Compare commits
No commits in common. "2f1c975e0ae8d6387a6e448755a689f57330d198" and "f7ce3a39d05304fd7838824a775fe83221e47f10" have entirely different histories.
2f1c975e0a
...
f7ce3a39d0
13 changed files with 208 additions and 613 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import frappe
|
||||
import json
|
||||
from custom_ui.db_utils import build_error_response, build_success_response
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
@ -55,8 +54,10 @@ def get_contacts_for_address(address_name):
|
|||
def get_addresses(fields=["*"], filters={}):
|
||||
"""Get addresses with optional filtering."""
|
||||
if isinstance(fields, str):
|
||||
import json
|
||||
fields = json.loads(fields)
|
||||
if isinstance(filters, str):
|
||||
import json
|
||||
filters = json.loads(filters)
|
||||
if fields[0] != "*" and len(fields) == 1:
|
||||
pluck = fields[0]
|
||||
|
|
@ -85,16 +86,6 @@ def create_address(address_data):
|
|||
address.insert(ignore_permissions=True)
|
||||
return address
|
||||
|
||||
def update_address(address_data):
|
||||
"""Update an existing address."""
|
||||
if isinstance(address_data, str):
|
||||
address_data = json.loads(address_data)
|
||||
address_doc = check_and_get_address_by_name(address_data.get("name"))
|
||||
for key, value in address_data.items():
|
||||
setattr(address_doc, key, value)
|
||||
address_doc.save(ignore_permissions=True)
|
||||
return address_doc
|
||||
|
||||
def address_exists(address_line1, address_line2, city, state, pincode):
|
||||
"""Check if an address with the given details already exists."""
|
||||
filters = {
|
||||
|
|
@ -106,16 +97,6 @@ def address_exists(address_line1, address_line2, city, state, pincode):
|
|||
}
|
||||
return frappe.db.exists("Address", filters) is not None
|
||||
|
||||
def check_and_get_address_by_name(address_name):
|
||||
"""Check if an address exists by name and return the address document if found."""
|
||||
if frappe.db.exists("Address", address_name):
|
||||
return frappe.get_doc("Address", address_name)
|
||||
raise ValueError(f"Address with name {address_name} does not exist.")
|
||||
|
||||
def address_exists_by_name(address_name):
|
||||
"""Check if an address with the given name exists."""
|
||||
return frappe.db.exists("Address", address_name) is not None
|
||||
|
||||
def calculate_address_title(customer_name, address_data):
|
||||
return f"{customer_name} - {address_data.get('address_line1', '')}, {address_data.get('city', '')} - {address_data.get('type', '')}"
|
||||
|
||||
|
|
|
|||
|
|
@ -210,38 +210,6 @@ def get_clients_table_data(filters={}, sortings=[], page=1, page_size=10):
|
|||
except Exception as e:
|
||||
return build_error_response(str(e), 500)
|
||||
|
||||
@frappe.whitelist()
|
||||
def update_client_info(client_name, data):
|
||||
"""Update client information for a given client."""
|
||||
try:
|
||||
data = json.loads(data)
|
||||
print("DEBUG: update_client_info called with client_name:", client_name, "and data:", data)
|
||||
client_doc = check_and_get_client_doc(client_name)
|
||||
if not client_doc:
|
||||
return build_error_response(f"Client with name '{client_name}' does not exist.", 404)
|
||||
address_updates = data.get("addresses", [])
|
||||
contact_updates = data.get("contacts", [])
|
||||
customer_updates = data.get("customer", {})
|
||||
# Update addresses
|
||||
if address_updates:
|
||||
for addr_data in address_updates:
|
||||
update_address(addr_data)
|
||||
# Update contacts
|
||||
if contact_updates:
|
||||
for contact_data in contact_updates:
|
||||
update_contact(contact_data)
|
||||
# Update customer/lead
|
||||
if customer_updates:
|
||||
for field, value in customer_updates.items():
|
||||
if hasattr(client_doc, field):
|
||||
setattr(client_doc, field, value)
|
||||
client_doc.save(ignore_permissions=True)
|
||||
frappe.local.message_log = []
|
||||
return get_client(client_name)
|
||||
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 upsert_client(data):
|
||||
|
|
|
|||
|
|
@ -24,12 +24,6 @@ def check_and_get_contact(first_name: str, last_name: str, email: str, phone: st
|
|||
return get_contact(contact_name)
|
||||
return None
|
||||
|
||||
def check_and_get_contact_by_name(contact_name: str):
|
||||
"""Check if a contact exists by name and return the contact document if found."""
|
||||
if frappe.db.exists("Contact", contact_name):
|
||||
return get_contact(contact_name)
|
||||
return None
|
||||
|
||||
def create_contact(contact_data: dict):
|
||||
"""Create a new contact."""
|
||||
contact = frappe.get_doc({
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ def upsert_estimate(data):
|
|||
new_estimate = frappe.get_doc({
|
||||
"doctype": "Quotation",
|
||||
"custom_requires_half_payment": data.get("requires_half_payment", 0),
|
||||
"custom_job_address": data.get("address_name"),
|
||||
"custom_installation_address": data.get("address_name"),
|
||||
"custom_current_status": "Draft",
|
||||
"contact_email": data.get("contact_email"),
|
||||
"party_name": data.get("customer"),
|
||||
|
|
|
|||
|
|
@ -1,54 +1,37 @@
|
|||
import frappe
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
from custom_ui.services import DbService
|
||||
|
||||
def after_insert(doc, method):
|
||||
print("DEBUG: after_insert hook triggered for Quotation:", doc.name)
|
||||
try:
|
||||
template = doc.custom_project_template or "Other"
|
||||
if template == "Other":
|
||||
print("WARN: No project template specified.")
|
||||
if template == "SNW Install":
|
||||
print("DEBUG: SNW Install template detected, updating custom address field.")
|
||||
DbService.set_value(
|
||||
doctype="Address",
|
||||
name=doc.custom_job_address,
|
||||
fieldname="custom_estimate_sent_status",
|
||||
value="Pending"
|
||||
)
|
||||
print("DEBUG: after_insert hook triggered for Quotation:", doc.name)
|
||||
if not doc.custom_installation_address:
|
||||
print("ERROR: custom_installation_address is empty")
|
||||
return
|
||||
address_doc = frappe.get_doc("Address", doc.custom_installation_address)
|
||||
address_doc.custom_estimate_sent_status = "In Progress"
|
||||
address_doc.save()
|
||||
except Exception as e:
|
||||
print("ERROR in after_insert hook:", str(e))
|
||||
frappe.log_error(f"Error in estimate after_insert: {str(e)}", "Estimate Hook Error")
|
||||
|
||||
def after_save(doc, method):
|
||||
print("DEBUG: after_save hook triggered for Quotation:", doc.name)
|
||||
if doc.custom_sent and doc.custom_response and doc.custom_project_template == "SNW Install":
|
||||
if doc.custom_sent and doc.custom_response:
|
||||
print("DEBUG: Quotation has been sent, updating Address status")
|
||||
try:
|
||||
DbService.set_value(
|
||||
doctype="Address",
|
||||
name=doc.custom_job_address,
|
||||
fieldname="custom_estimate_sent_status",
|
||||
value="Sent"
|
||||
)
|
||||
except Exception as e:
|
||||
print("ERROR updating Address in after_save hook:", str(e))
|
||||
frappe.log_error(f"Error updating Address in estimate after_save: {str(e)}", "Estimate Hook Error")
|
||||
address_doc = frappe.get_doc("Address", doc.custom_installation_address)
|
||||
address_doc.custom_estimate_sent_status = "Completed"
|
||||
address_doc.save()
|
||||
|
||||
def on_update_after_submit(doc, method):
|
||||
print("DEBUG: on_update_after_submit hook triggered for Quotation:", doc.name)
|
||||
print("DEBUG: Current custom_current_status:", doc.custom_current_status)
|
||||
if doc.custom_current_status == "Estimate Accepted":
|
||||
doc.custom_current_status = "Won"
|
||||
if doc.custom_project_template == "SNW Install":
|
||||
DbService.set_value(
|
||||
doctype="Address",
|
||||
name=doc.custom_job_address,
|
||||
fieldname="custom_estimate_sent_status",
|
||||
value="Completed"
|
||||
)
|
||||
print("DEBUG: Creating Sales Order from accepted Estimate")
|
||||
address_doc = frappe.get_doc("Address", doc.customer_address)
|
||||
address_doc.custom_estimate_sent_status = "Completed"
|
||||
address_doc.save()
|
||||
try:
|
||||
print("DEBUG: Creating Sales Order from accepted Estimate")
|
||||
new_sales_order = make_sales_order(doc.name)
|
||||
new_sales_order.custom_requires_half_payment = doc.requires_half_payment
|
||||
new_sales_order.custom_installation_address = doc.custom_installation_address
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import frappe
|
||||
from custom_ui.services import DbService
|
||||
|
||||
|
||||
def on_submit(doc, method):
|
||||
print("DEBUG: Info from Sales Order")
|
||||
|
|
@ -11,18 +11,15 @@ def on_submit(doc, method):
|
|||
try:
|
||||
print("Creating Project from Sales Order", doc.name)
|
||||
sales_order = frappe.get_doc("Sales Order", doc.name)
|
||||
if not sales_order.custom_project_template:
|
||||
return
|
||||
project_template = DbService.get("Project Template", sales_order.custom_project_template)
|
||||
project_template = frappe.get_doc("Project Template", "SNW Install")
|
||||
new_job = frappe.get_doc({
|
||||
"doctype": "Project",
|
||||
"custom_job_address": sales_order.custom_job_address,
|
||||
"project_name": f"{sales_order.custom_project_template} - {sales_order.custom_job_address}",
|
||||
"project_template": project_template.name,
|
||||
"custom_installation_address": sales_order.custom_installation_address,
|
||||
"project_name": sales_order.custom_installation_address,
|
||||
"project_template": project_template,
|
||||
"custom_warranty_duration_days": 90,
|
||||
"sales_order": sales_order.name
|
||||
"sales_order": sales_order
|
||||
})
|
||||
# attatch the job to the sales_order links
|
||||
new_job.insert()
|
||||
frappe.db.commit()
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
from curses import meta
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -24,14 +23,14 @@ def after_migrate():
|
|||
update_onsite_meeting_fields()
|
||||
frappe.db.commit()
|
||||
|
||||
# Proper way to refresh metadata for all doctypes with custom fields
|
||||
doctypes_to_refresh = ["Lead", "Address", "Contact", "On-Site Meeting", "Quotation", "Sales Order", "Project Template"]
|
||||
for doctype in doctypes_to_refresh:
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
frappe.reload_doctype(doctype)
|
||||
# Proper way to refresh metadata
|
||||
frappe.clear_cache(doctype="Address")
|
||||
frappe.reload_doctype("Address")
|
||||
frappe.clear_cache(doctype="On-Site Meeting")
|
||||
frappe.reload_doctype("On-Site Meeting")
|
||||
|
||||
update_address_fields()
|
||||
# build_frontend()
|
||||
# update_address_fields()
|
||||
build_frontend()
|
||||
|
||||
|
||||
def build_frontend():
|
||||
|
|
@ -69,7 +68,7 @@ def build_frontend():
|
|||
def add_custom_fields():
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
|
||||
print("\n🔧 Adding custom fields to doctypes...")
|
||||
print("\n🔧 Adding custom fields to Address doctype...")
|
||||
|
||||
custom_fields = {
|
||||
"Lead": [
|
||||
|
|
@ -209,17 +208,7 @@ def add_custom_fields():
|
|||
fieldtype="Link",
|
||||
options="Project Template",
|
||||
insert_after="custom_quotation_template",
|
||||
description="The project template to use when creating a project from this quotation.",
|
||||
allow_on_submit=1
|
||||
),
|
||||
dict(
|
||||
fieldname="custom_job_address",
|
||||
label="Job Address",
|
||||
fieldtype="Link",
|
||||
options="Address",
|
||||
insert_after="custom_installation_address",
|
||||
description="The address where the job will be performed.",
|
||||
allow_on_submit=1
|
||||
description="The project template to use when creating a project from this quotation."
|
||||
)
|
||||
],
|
||||
"Sales Order": [
|
||||
|
|
@ -236,17 +225,7 @@ def add_custom_fields():
|
|||
fieldtype="Link",
|
||||
options="Project Template",
|
||||
description="The project template to use when creating a project from this sales order.",
|
||||
insert_after="custom_installation_address",
|
||||
allow_on_submit=1
|
||||
),
|
||||
dict(
|
||||
fieldname="custom_job_address",
|
||||
label="Job Address",
|
||||
fieldtype="Link",
|
||||
options="Address",
|
||||
insert_after="custom_installation_address",
|
||||
description="The address where the job will be performed.",
|
||||
allow_on_submit=1
|
||||
insert_after="custom_installation_address"
|
||||
)
|
||||
],
|
||||
"Project Template": [
|
||||
|
|
@ -261,68 +240,32 @@ def add_custom_fields():
|
|||
]
|
||||
}
|
||||
|
||||
print("🔧 Custom fields to check per doctype:")
|
||||
for key, value in custom_fields.items():
|
||||
print(f" • {key}: {len(value)} fields")
|
||||
print(f" Total fields to check: {sum(len(v) for v in custom_fields.values())}\n")
|
||||
|
||||
missing_fields = []
|
||||
fields_to_update = []
|
||||
|
||||
for doctype, field_options in custom_fields.items():
|
||||
meta = frappe.get_meta(doctype)
|
||||
for field_spec in field_options:
|
||||
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}"
|
||||
if frappe.db.exists("Custom Field", custom_field_name):
|
||||
custom_field_doc = frappe.get_doc("Custom Field", custom_field_name)
|
||||
needs_update = False
|
||||
|
||||
# Compare important properties
|
||||
for key, desired_value in field_spec.items():
|
||||
if key == "fieldname":
|
||||
continue
|
||||
current_value = getattr(custom_field_doc, key, None)
|
||||
if current_value != desired_value:
|
||||
needs_update = True
|
||||
break
|
||||
|
||||
if needs_update:
|
||||
fields_to_update.append((doctype, fieldname, field_spec))
|
||||
|
||||
if missing_fields:
|
||||
print("\n❌ Missing custom fields:")
|
||||
for entry in missing_fields:
|
||||
print(f" • {entry}")
|
||||
print("\n🔧 Creating missing custom fields...")
|
||||
missing_field_specs = build_missing_field_specs(custom_fields, missing_fields)
|
||||
create_custom_fields(missing_field_specs)
|
||||
print("✅ Missing custom fields created.")
|
||||
|
||||
if fields_to_update:
|
||||
print("\n🔧 Updating custom fields with mismatched specs:")
|
||||
for doctype, fieldname, field_spec in fields_to_update:
|
||||
print(f" • {doctype}: {fieldname}")
|
||||
custom_field_name = f"{doctype}-{fieldname}"
|
||||
custom_field_doc = frappe.get_doc("Custom Field", custom_field_name)
|
||||
|
||||
# Update all properties from field_spec
|
||||
for key, value in field_spec.items():
|
||||
if key != "fieldname":
|
||||
setattr(custom_field_doc, key, value)
|
||||
|
||||
custom_field_doc.save(ignore_permissions=True)
|
||||
|
||||
frappe.db.commit()
|
||||
print("✅ Custom fields updated.")
|
||||
|
||||
if not missing_fields and not fields_to_update:
|
||||
print("✅ All custom fields verified.")
|
||||
lead_field_count = len(custom_fields["Lead"])
|
||||
address_field_count = len(custom_fields["Address"])
|
||||
contact_field_count = len(custom_fields["Contact"])
|
||||
onsite_field_count = len(custom_fields["On-Site Meeting"])
|
||||
quotation_field_count = len(custom_fields["Quotation"])
|
||||
sales_order_field_count = len(custom_fields["Sales Order"])
|
||||
project_template_field_count = len(custom_fields["Project Template"])
|
||||
field_count = (lead_field_count + address_field_count + contact_field_count +
|
||||
onsite_field_count + quotation_field_count +
|
||||
sales_order_field_count + project_template_field_count)
|
||||
print(f"🔧 Preparing to add {field_count} custom fields:")
|
||||
print(f" • Lead: {lead_field_count} fields")
|
||||
print(f" • Address: {address_field_count} fields")
|
||||
print(f" • Contact: {contact_field_count} fields")
|
||||
print(f" • On-Site Meeting: {onsite_field_count} fields")
|
||||
print(f" • Quotation: {quotation_field_count} fields")
|
||||
print(f" • Sales Order: {sales_order_field_count} fields")
|
||||
print(f" • Project Template: {project_template_field_count} fields")
|
||||
|
||||
try:
|
||||
create_custom_fields(custom_fields)
|
||||
print("✅ Custom fields added successfully!")
|
||||
except Exception as e:
|
||||
print(f"❌ Error creating custom fields: {str(e)}")
|
||||
frappe.log_error(message=str(e), title="Custom Fields Creation Failed")
|
||||
raise
|
||||
|
||||
def update_onsite_meeting_fields():
|
||||
"""Update On-Site Meeting doctype fields to make start_time and end_time optional."""
|
||||
|
|
@ -354,55 +297,90 @@ def update_onsite_meeting_fields():
|
|||
# Don't raise - this is not critical enough to stop migration
|
||||
|
||||
def update_address_fields():
|
||||
quotations = frappe.get_all("Quotation", pluck="name")
|
||||
addresses = frappe.get_all("Address", pluck="name")
|
||||
sales_orders = frappe.get_all("Sales Order", pluck="name")
|
||||
total_addresses = len(addresses)
|
||||
total_quotations = len(quotations)
|
||||
total_sales_orders = len(sales_orders)
|
||||
total_doctypes = total_addresses + total_quotations + total_sales_orders
|
||||
combined_doctypes = []
|
||||
for sales_order in sales_orders:
|
||||
combined_doctypes.append({"doctype": "Sales Order", "name": sales_order})
|
||||
for quotation in quotations:
|
||||
combined_doctypes.append({"doctype": "Quotation", "name": quotation})
|
||||
for address in addresses:
|
||||
combined_doctypes.append({"doctype": "Address", "name": address})
|
||||
|
||||
|
||||
print(f"\n📍 Updating field values for {total_addresses} addresses, {total_quotations} quotations, and {total_sales_orders} sales orders...")
|
||||
if total_addresses == 0:
|
||||
print("📍 No addresses found to update.")
|
||||
return
|
||||
|
||||
print(f"\n📍 Updating fields for {total_addresses} addresses...")
|
||||
|
||||
# Verify custom fields exist by checking the meta for every doctype that was customized
|
||||
def has_any_field(meta, candidates):
|
||||
return any(meta.has_field(f) for f in candidates)
|
||||
|
||||
custom_field_expectations = {
|
||||
"Address": [
|
||||
["full_address"],
|
||||
["custom_onsite_meeting_scheduled", "onsite_meeting_scheduled"],
|
||||
["custom_estimate_sent_status", "estimate_sent_status"],
|
||||
["custom_job_status", "job_status"],
|
||||
["custom_payment_received_status", "payment_received_status",],
|
||||
["custom_lead_name", "lead_name"]
|
||||
],
|
||||
"Contact": [
|
||||
["custom_role", "role"],
|
||||
["custom_email", "email"],
|
||||
],
|
||||
"On-Site Meeting": [
|
||||
["custom_notes", "notes"],
|
||||
["custom_assigned_employee", "assigned_employee"],
|
||||
["custom_status", "status"],
|
||||
["custom_completed_by", "completed_by"]
|
||||
],
|
||||
"Quotation": [
|
||||
["custom_requires_half_payment", "requires_half_payment"]
|
||||
],
|
||||
"Sales Order": [
|
||||
["custom_requires_half_payment", "requires_half_payment"]
|
||||
],
|
||||
"Lead": [
|
||||
["custom_customer_type", "customer_type"]
|
||||
]
|
||||
}
|
||||
|
||||
missing_fields = []
|
||||
for doctype, field_options in custom_field_expectations.items():
|
||||
meta = frappe.get_meta(doctype)
|
||||
for candidates in field_options:
|
||||
if not has_any_field(meta, candidates):
|
||||
missing_fields.append(f"{doctype}: {'/'.join(candidates)}")
|
||||
|
||||
if missing_fields:
|
||||
print("\n❌ Missing custom fields:")
|
||||
for entry in missing_fields:
|
||||
print(f" • {entry}")
|
||||
print(" Custom fields creation may have failed. Skipping address updates.")
|
||||
return
|
||||
|
||||
print("✅ All custom fields verified. Proceeding with address updates...")
|
||||
|
||||
# Field update counters
|
||||
field_counters = {
|
||||
'quotation_addresses_updated': 0,
|
||||
'quotation_project_templates_updated': 0,
|
||||
'sales_order_addresses_updated': 0,
|
||||
'sales_order_project_templates_updated': 0,
|
||||
'full_address': 0,
|
||||
'custom_onsite_meeting_scheduled': 0,
|
||||
'custom_estimate_sent_status': 0,
|
||||
'custom_job_status': 0,
|
||||
'custom_payment_received_status': 0,
|
||||
'total_field_updates': 0,
|
||||
'addresses_updated': 0,
|
||||
'quotations_updated': 0,
|
||||
'sales_orders_updated': 0
|
||||
'custom_payment_received_status': 0
|
||||
}
|
||||
total_field_updates = 0
|
||||
addresses_updated = 0
|
||||
|
||||
onsite_meta = frappe.get_meta("On-Site Meeting")
|
||||
onsite_status_field = "custom_status" if onsite_meta.has_field("custom_status") else "status"
|
||||
|
||||
for index, doc in enumerate(combined_doctypes, 1):
|
||||
for index, name in enumerate(addresses, 1):
|
||||
# Calculate progress
|
||||
progress_percentage = int((index / total_doctypes) * 100)
|
||||
progress_percentage = int((index / total_addresses) * 100)
|
||||
bar_length = 30
|
||||
filled_length = int(bar_length * index // total_doctypes)
|
||||
filled_length = int(bar_length * index // total_addresses)
|
||||
bar = '█' * filled_length + '░' * (bar_length - filled_length)
|
||||
|
||||
# Print a three-line, refreshing progress block without adding new lines each loop
|
||||
progress_line = f"📊 Progress: [{bar}] {progress_percentage:3d}% ({index}/{total_doctypes})"
|
||||
counters_line = f" Fields updated: {field_counters['total_field_updates']} | DocTypes updated: {field_counters['addresses_updated'] + field_counters['quotations_updated'] + field_counters['sales_orders_updated']}"
|
||||
detail_line = f" Processing: {doc['name'][:40]}..."
|
||||
progress_line = f"📊 Progress: [{bar}] {progress_percentage:3d}% ({index}/{total_addresses})"
|
||||
counters_line = f" Fields updated: {total_field_updates} | Addresses updated: {addresses_updated}"
|
||||
detail_line = f" Processing: {name[:40]}..."
|
||||
|
||||
if index == 1:
|
||||
# First render: write the three lines
|
||||
|
|
@ -418,139 +396,100 @@ def update_address_fields():
|
|||
sys.stdout.write(f"\033[K{counters_line}\n")
|
||||
sys.stdout.write(f"\033[K{detail_line}")
|
||||
|
||||
if index == total_doctypes:
|
||||
if index == total_addresses:
|
||||
sys.stdout.write("\n")
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
if doc['doctype'] == "Quotation" or doc['doctype'] == "Sales Order":
|
||||
dict_field = doc['doctype'].lower().replace(" ", "_")
|
||||
quotation_doc = frappe.get_doc(doc['doctype'], doc['name'])
|
||||
custom_installation_address = getattr(quotation_doc, 'custom_installation_address', None)
|
||||
custom_job_address = getattr(quotation_doc, 'custom_job_address', None)
|
||||
custom_project_template = getattr(quotation_doc, 'custom_project_template', None)
|
||||
|
||||
updates = {}
|
||||
if custom_installation_address and not custom_job_address:
|
||||
updates['custom_job_address'] = custom_installation_address
|
||||
field_counters[f"{dict_field}_addresses_updated"] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
if custom_installation_address and not custom_project_template:
|
||||
updates['custom_project_template'] = "SNW Install"
|
||||
field_counters[f"{dict_field}_project_templates_updated"] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
|
||||
if updates:
|
||||
frappe.db.set_value(doc['doctype'], doc['name'], updates)
|
||||
field_counters[f"{dict_field}s_updated"] += 1
|
||||
|
||||
if doc['doctype'] == "Address":
|
||||
address_doc = frappe.get_doc("Address", doc['name'])
|
||||
updates = {}
|
||||
|
||||
# Use getattr with default values instead of direct attribute access
|
||||
if not getattr(address_doc, 'full_address', None):
|
||||
address_parts_1 = [
|
||||
address_doc.address_line1 or "",
|
||||
address_doc.address_line2 or "",
|
||||
address_doc.city or "",
|
||||
]
|
||||
address_parts_2 = [
|
||||
address_doc.state or "",
|
||||
address_doc.pincode or "",
|
||||
]
|
||||
|
||||
full_address = ", ".join([
|
||||
" ".join(filter(None, address_parts_1)),
|
||||
" ".join(filter(None, address_parts_2))
|
||||
]).strip()
|
||||
updates['full_address'] = full_address
|
||||
field_counters['full_address'] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
|
||||
onsite_meeting = "Not Started"
|
||||
estimate_sent = "Not Started"
|
||||
job_status = "Not Started"
|
||||
payment_received = "Not Started"
|
||||
|
||||
|
||||
onsite_meetings = frappe.get_all("On-Site Meeting", fields=[onsite_status_field], filters={"address": address_doc.address_title})
|
||||
if onsite_meetings and onsite_meetings[0]:
|
||||
status_value = onsite_meetings[0].get(onsite_status_field)
|
||||
onsite_meeting = "Completed" if status_value == "Completed" else "In Progress"
|
||||
|
||||
estimates = frappe.get_all("Quotation", fields=["custom_sent", "docstatus", "custom_response"], filters={"custom_job_address": address_doc.address_title})
|
||||
if estimates and estimates[0] and estimates[0]["custom_sent"] == 1 and estimates[0]["custom_response"]:
|
||||
estimate_sent = "Completed"
|
||||
elif estimates and estimates[0] and not (estimates[0]["custom_sent"] == 1 and estimates[0]["custom_response"]):
|
||||
estimate_sent = "In Progress"
|
||||
|
||||
jobs = frappe.get_all("Project", fields=["status"], filters={"custom_installation_address": address_doc.address_title, "project_template": "SNW Install"})
|
||||
if jobs and jobs[0] and jobs[0]["status"] == "Completed":
|
||||
job_status = "Completed"
|
||||
elif jobs and jobs[0]:
|
||||
job_status = "In Progress"
|
||||
|
||||
sales_invoices = frappe.get_all("Sales Invoice", fields=["outstanding_amount"], filters={"custom_installation_address": address_doc.address_title})
|
||||
# payments = frappe.get_all("Payment Entry", filters={"custom_installation_address": address_doc.address_title})
|
||||
if sales_invoices and sales_invoices[0] and sales_invoices[0]["outstanding_amount"] == 0:
|
||||
payment_received = "Completed"
|
||||
elif sales_invoices and sales_invoices[0]:
|
||||
payment_received = "In Progress"
|
||||
|
||||
if getattr(address_doc, 'custom_onsite_meeting_scheduled', None) != onsite_meeting:
|
||||
updates['custom_onsite_meeting_scheduled'] = onsite_meeting
|
||||
field_counters['custom_onsite_meeting_scheduled'] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
if getattr(address_doc, 'custom_estimate_sent_status', None) != estimate_sent:
|
||||
updates['custom_estimate_sent_status'] = estimate_sent
|
||||
field_counters['custom_estimate_sent_status'] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
if getattr(address_doc, 'custom_job_status', None) != job_status:
|
||||
updates['custom_job_status'] = job_status
|
||||
field_counters['custom_job_status'] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
if getattr(address_doc, 'custom_payment_received_status', None) != payment_received:
|
||||
updates['custom_payment_received_status'] = payment_received
|
||||
field_counters['custom_payment_received_status'] += 1
|
||||
field_counters['total_field_updates'] += 1
|
||||
|
||||
if updates:
|
||||
frappe.db.set_value("Address", doc['name'], updates)
|
||||
field_counters['addresses_updated'] += 1
|
||||
should_update = False
|
||||
address = frappe.get_doc("Address", name)
|
||||
current_address_updates = 0
|
||||
|
||||
# Commit every 100 records to avoid long transactions
|
||||
if index % 100 == 0:
|
||||
frappe.db.commit()
|
||||
# Use getattr with default values instead of direct attribute access
|
||||
if not getattr(address, 'full_address', None):
|
||||
address_parts_1 = [
|
||||
address.address_line1 or "",
|
||||
address.address_line2 or "",
|
||||
address.city or "",
|
||||
]
|
||||
address_parts_2 = [
|
||||
address.state or "",
|
||||
address.pincode or "",
|
||||
]
|
||||
|
||||
full_address = ", ".join([
|
||||
" ".join(filter(None, address_parts_1)),
|
||||
" ".join(filter(None, address_parts_2))
|
||||
]).strip()
|
||||
address.full_address = full_address
|
||||
field_counters['full_address'] += 1
|
||||
current_address_updates += 1
|
||||
should_update = True
|
||||
onsite_meeting = "Not Started"
|
||||
estimate_sent = "Not Started"
|
||||
job_status = "Not Started"
|
||||
payment_received = "Not Started"
|
||||
|
||||
onsite_meetings = frappe.get_all("On-Site Meeting", fields=[onsite_status_field], filters={"address": address.address_title})
|
||||
if onsite_meetings and onsite_meetings[0]:
|
||||
status_value = onsite_meetings[0].get(onsite_status_field)
|
||||
onsite_meeting = "Completed" if status_value == "Completed" else "In Progress"
|
||||
|
||||
estimates = frappe.get_all("Quotation", fields=["custom_sent", "docstatus", "custom_response"], filters={"custom_installation_address": address.address_title})
|
||||
if estimates and estimates[0] and estimates[0]["custom_sent"] == 1 and estimates[0]["custom_response"]:
|
||||
estimate_sent = "Completed"
|
||||
elif estimates and estimates[0] and not (estimates[0]["custom_sent"] == 1 and estimates[0]["custom_response"]):
|
||||
estimate_sent = "In Progress"
|
||||
|
||||
jobs = frappe.get_all("Project", fields=["status"], filters={"custom_installation_address": address.address_title, "project_template": "SNW Install"})
|
||||
if jobs and jobs[0] and jobs[0]["status"] == "Completed":
|
||||
job_status = "Completed"
|
||||
elif jobs and jobs[0]:
|
||||
job_status = "In Progress"
|
||||
|
||||
sales_invoices = frappe.get_all("Sales Invoice", fields=["outstanding_amount"], filters={"custom_installation_address": address.address_title})
|
||||
# payments = frappe.get_all("Payment Entry", filters={"custom_installation_address": address.address_title})
|
||||
if sales_invoices and sales_invoices[0] and sales_invoices[0]["outstanding_amount"] == 0:
|
||||
payment_received = "Completed"
|
||||
elif sales_invoices and sales_invoices[0]:
|
||||
payment_received = "In Progress"
|
||||
|
||||
if getattr(address, 'custom_onsite_meeting_scheduled', None) != onsite_meeting:
|
||||
address.custom_onsite_meeting_scheduled = onsite_meeting
|
||||
field_counters['custom_onsite_meeting_scheduled'] += 1
|
||||
current_address_updates += 1
|
||||
should_update = True
|
||||
if getattr(address, 'custom_estimate_sent_status', None) != estimate_sent:
|
||||
address.custom_estimate_sent_status = estimate_sent
|
||||
field_counters['custom_estimate_sent_status'] += 1
|
||||
current_address_updates += 1
|
||||
should_update = True
|
||||
if getattr(address, 'custom_job_status', None) != job_status:
|
||||
address.custom_job_status = job_status
|
||||
field_counters['custom_job_status'] += 1
|
||||
current_address_updates += 1
|
||||
should_update = True
|
||||
if getattr(address, 'custom_payment_received_status', None) != payment_received:
|
||||
address.custom_payment_received_status = payment_received
|
||||
field_counters['custom_payment_received_status'] += 1
|
||||
current_address_updates += 1
|
||||
should_update = True
|
||||
|
||||
if should_update:
|
||||
address.save(ignore_permissions=True)
|
||||
addresses_updated += 1
|
||||
total_field_updates += current_address_updates
|
||||
|
||||
# Print completion summary
|
||||
print(f"\n\n✅ DocType field value update completed!")
|
||||
print(f"\n\n✅ Address field update completed!")
|
||||
print(f"📊 Summary:")
|
||||
print(f" • Total DocTypes processed: {total_doctypes:,}")
|
||||
print(f" • Addresses updated: {field_counters['addresses_updated']:,}")
|
||||
print(f" • Quotations updated: {field_counters['quotations_updated']:,}")
|
||||
print(f" • Sales Orders updated: {field_counters['sales_orders_updated']:,}")
|
||||
print(f" • Total field updates: {field_counters['total_field_updates']:,}")
|
||||
print(f" • Total addresses processed: {total_addresses:,}")
|
||||
print(f" • Addresses updated: {addresses_updated:,}")
|
||||
print(f" • Total field updates: {total_field_updates:,}")
|
||||
print(f"\n📝 Field-specific updates:")
|
||||
print(f" • Full Address: {field_counters['full_address']:,}")
|
||||
print(f" • On-Site Meeting Status: {field_counters['custom_onsite_meeting_scheduled']:,}")
|
||||
print(f" • Estimate Sent Status: {field_counters['custom_estimate_sent_status']:,}")
|
||||
print(f" • Job Status: {field_counters['custom_job_status']:,}")
|
||||
print(f" • Payment Received Status: {field_counters['custom_payment_received_status']:,}")
|
||||
print(f" • Quotation Addresses Updated: {field_counters['quotation_addresses_updated']:,}")
|
||||
print(f" • Quotation Project Templates Updated: {field_counters['quotation_project_templates_updated']:,}")
|
||||
print(f" • Sales Order Addresses Updated: {field_counters['sales_order_addresses_updated']:,}")
|
||||
print(f" • Sales Order Project Templates Updated: {field_counters['sales_order_project_templates_updated']:,}")
|
||||
print("📍 DocType field value updates complete.\n")
|
||||
|
||||
def build_missing_field_specs(custom_fields, missing_fields):
|
||||
missing_field_specs = {}
|
||||
for entry in missing_fields:
|
||||
doctype, fieldname = entry.split(": ")
|
||||
missing_field_specs.setdefault(doctype, [])
|
||||
for field_spec in custom_fields.get(doctype, []):
|
||||
if field_spec["fieldname"] == fieldname:
|
||||
missing_field_specs[doctype].append(field_spec)
|
||||
break
|
||||
|
||||
return missing_field_specs
|
||||
print("📍 Address field updates complete.\n")
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
from .address_service import AddressService
|
||||
|
||||
from .db_service import DbService
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
import frappe
|
||||
|
||||
class AddressService:
|
||||
|
||||
@staticmethod
|
||||
def exists(address_name: str) -> bool:
|
||||
"""Check if an address with the given name exists."""
|
||||
print(f"DEBUG: Checking existence of Address with name: {address_name}")
|
||||
result = frappe.db.exists("Address", address_name) is not None
|
||||
print(f"DEBUG: Address existence: {result}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get(address_name: str):
|
||||
"""Retrieve an address document by name. Returns None if not found."""
|
||||
print(f"DEBUG: Retrieving Address document with name: {address_name}")
|
||||
if AddressService.exists(address_name):
|
||||
address_doc = frappe.get_doc("Address", address_name)
|
||||
print("DEBUG: Address document found.")
|
||||
return address_doc
|
||||
print("DEBUG: Address document not found.")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_or_throw(address_name: str):
|
||||
"""Retrieve an address document by name or throw an error if not found."""
|
||||
address_doc = AddressService.get(address_name)
|
||||
if address_doc:
|
||||
return address_doc
|
||||
raise ValueError(f"Address with name {address_name} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def update_value(docname: str, fieldname: str, value, save: bool = True) -> frappe._dict:
|
||||
"""Update a specific field value of a document."""
|
||||
print(f"DEBUG: Updating Address {docname}, setting {fieldname} to {value}")
|
||||
if AddressService.exists(docname) is False:
|
||||
raise ValueError(f"Address with name {docname} does not exist.")
|
||||
if save:
|
||||
print("DEBUG: Saving updated Address document.")
|
||||
address_doc = AddressService.get_or_throw(docname)
|
||||
setattr(address_doc, fieldname, value)
|
||||
address_doc.save(ignore_permissions=True)
|
||||
else:
|
||||
print("DEBUG: Not saving Address document as save=False.")
|
||||
frappe.db.set_value("Address", docname, fieldname, value)
|
||||
print(f"DEBUG: Updated Address {docname}: set {fieldname} to {value}")
|
||||
return address_doc
|
||||
|
||||
@staticmethod
|
||||
def get_value(docname: str, fieldname: str):
|
||||
"""Get a specific field value of a document. Returns None if document does not exist."""
|
||||
print(f"DEBUG: Getting value of field {fieldname} from Address {docname}")
|
||||
if not AddressService.exists(docname):
|
||||
print("DEBUG: Value cannot be retrieved; Address does not exist.")
|
||||
return None
|
||||
value = frappe.db.get_value("Address", docname, fieldname)
|
||||
print(f"DEBUG: Retrieved value: {value}")
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def get_value_or_throw(docname: str, fieldname: str):
|
||||
"""Get a specific field value of a document or throw an error if document does not exist."""
|
||||
value = AddressService.get_value(docname, fieldname)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(f"Address with name {docname} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def create(address_data: dict):
|
||||
"""Create a new address."""
|
||||
print("DEBUG: Creating new Address with data:", address_data)
|
||||
address = frappe.get_doc({
|
||||
"doctype": "Address",
|
||||
**address_data
|
||||
})
|
||||
address.insert(ignore_permissions=True)
|
||||
print("DEBUG: Created new Address:", address.as_dict())
|
||||
return address
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
import frappe
|
||||
|
||||
class DbService:
|
||||
|
||||
@staticmethod
|
||||
def exists(doctype: str, name: str) -> bool:
|
||||
"""Check if a document exists by doctype and name."""
|
||||
result = frappe.db.exists(doctype, name) is not None
|
||||
print(f"DEBUG: {doctype} existence for {name}: {result}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get(doctype: str, name: str):
|
||||
"""Retrieve a document by doctype and name. Returns None if not found."""
|
||||
print(f"DEBUG: Retrieving {doctype} document with name: {name}")
|
||||
if DbService.exists(doctype, name):
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
print(f"DEBUG: {doctype} document found.")
|
||||
return doc
|
||||
print(f"DEBUG: {doctype} document not found.")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_or_throw(doctype: str, name: str):
|
||||
"""Retrieve a document by doctype and name or throw an error if not found."""
|
||||
doc = DbService.get(doctype, name)
|
||||
if doc:
|
||||
return doc
|
||||
raise ValueError(f"{doctype} document with name {name} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def get_value(doctype: str, name: str, fieldname: str):
|
||||
"""Get a specific field value of a document. Returns None if document does not exist."""
|
||||
print(f"DEBUG: Getting value of field {fieldname} from {doctype} {name}")
|
||||
if not DbService.exists(doctype, name):
|
||||
print("DEBUG: Value cannot be retrieved; document does not exist.")
|
||||
return None
|
||||
value = frappe.db.get_value(doctype, name, fieldname)
|
||||
print(f"DEBUG: Retrieved value: {value}")
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def get_value_or_throw(doctype: str, name: str, fieldname: str):
|
||||
"""Get a specific field value of a document or throw an error if document does not exist."""
|
||||
value = DbService.get_value(doctype, name, fieldname)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(f"{doctype} document with name {name} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def create(doctype: str, data: dict):
|
||||
"""Create a new document of the specified doctype."""
|
||||
print(f"DEBUG: Creating new {doctype} document with data: {data}")
|
||||
doc = frappe.get_doc({
|
||||
"doctype": doctype,
|
||||
**data
|
||||
})
|
||||
doc.insert(ignore_permissions=True)
|
||||
print(f"DEBUG: Created new {doctype} document with name: {doc.name}")
|
||||
return doc
|
||||
|
||||
@staticmethod
|
||||
def set_value(doctype: str, name: str, fieldname: str, value: any, save: bool = True):
|
||||
"""Set a specific field value of a document."""
|
||||
print(f"DEBUG: Setting value of field {fieldname} in {doctype} {name} to {value}")
|
||||
if save:
|
||||
print("DEBUG: Saving updated document.")
|
||||
doc = DbService.get_or_throw(doctype, name)
|
||||
setattr(doc, fieldname, value)
|
||||
doc.save(ignore_permissions=True)
|
||||
return doc
|
||||
else:
|
||||
print("DEBUG: Not saving document as save=False.")
|
||||
frappe.db.set_value(doctype, name, fieldname, value)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def update(doctype: str, name: str, update_data: dict, save: bool = True):
|
||||
"""Update an existing document of the specified doctype."""
|
||||
print(f"DEBUG: Updating {doctype} {name}")
|
||||
doc = DbService.get_or_throw(doctype, name)
|
||||
for key, value in update_data.items():
|
||||
setattr(doc, key, value)
|
||||
if save:
|
||||
doc.save(ignore_permissions=True)
|
||||
else:
|
||||
DbService.set_value(doctype, name, key, value, save=False)
|
||||
print(f"DEBUG: Updated {doctype} document: {doc.as_dict()}")
|
||||
return doc
|
||||
|
||||
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
import frappe
|
||||
|
||||
class EstimateService:
|
||||
|
||||
@staticmethod
|
||||
def exists(estimate_name: str) -> bool:
|
||||
"""Check if a Quotation document exists by name."""
|
||||
print(f"DEBUG: Checking existence of Quotation document with name: {estimate_name}")
|
||||
result = frappe.db.exists("Quotation", estimate_name) is not None
|
||||
print(f"DEBUG: Quotation document existence: {result}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get(estimate_name: str) -> frappe._dict:
|
||||
"""Retrieve a Quotation document by name. Returns None if not found."""
|
||||
print(f"DEBUG: Retrieving Quotation document with name: {estimate_name}")
|
||||
if EstimateService.exists(estimate_name):
|
||||
estimate_doc = frappe.get_doc("Quotation", estimate_name)
|
||||
print("DEBUG: Quotation document found.")
|
||||
return estimate_doc
|
||||
print("DEBUG: Quotation document not found.")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_or_throw(estimate_name: str) -> frappe._dict:
|
||||
"""Retrieve a Quotation document by name or throw an error if not found."""
|
||||
estimate_doc = EstimateService.get(estimate_name)
|
||||
if estimate_doc:
|
||||
return estimate_doc
|
||||
raise ValueError(f"Quotation document with name {estimate_name} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def update_value(docname: str, fieldname: str, value, save: bool = True) -> None:
|
||||
"""Update a specific field value of an Quotation document."""
|
||||
print(f"DEBUG: Updating Quotation {docname}, setting {fieldname} to {value}")
|
||||
if save:
|
||||
print("DEBUG: Saving updated Quotation document.")
|
||||
estimate_doc = EstimateService.get_or_throw(docname)
|
||||
setattr(estimate_doc, fieldname, value)
|
||||
estimate_doc.save(ignore_permissions=True)
|
||||
else:
|
||||
print("DEBUG: Not saving Quotation document as save=False.")
|
||||
frappe.db.set_value("Quotation", docname, fieldname, value)
|
||||
print(f"DEBUG: Updated Quotation {docname}: set {fieldname} to {value}")
|
||||
|
||||
@staticmethod
|
||||
def get_value(docname: str, fieldname: str) -> any:
|
||||
"""Get a specific field value of a Quotation document. Returns None if document does not exist."""
|
||||
print(f"DEBUG: Getting value of field {fieldname} from Quotation {docname}")
|
||||
if not EstimateService.exists(docname):
|
||||
print("DEBUG: Value cannot be retrieved; Quotation document does not exist.")
|
||||
return None
|
||||
value = frappe.db.get_value("Quotation", docname, fieldname)
|
||||
print(f"DEBUG: Retrieved value: {value}")
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def get_value_or_throw(docname: str, fieldname: str) -> any:
|
||||
"""Get a specific field value of a Quotation document or throw an error if document does not exist."""
|
||||
value = EstimateService.get_value(docname, fieldname)
|
||||
if value is not None:
|
||||
return value
|
||||
raise ValueError(f"Quotation document with name {docname} does not exist.")
|
||||
|
||||
@staticmethod
|
||||
def update(estimate_name: str, update_data: dict) -> frappe._dict:
|
||||
"""Update an existing Quotation document."""
|
||||
print(f"DEBUG: Updating Quotation {estimate_name} with data: {update_data}")
|
||||
estimate_doc = EstimateService.get_or_throw(estimate_name)
|
||||
for key, value in update_data.items():
|
||||
setattr(estimate_doc, key, value)
|
||||
estimate_doc.save(ignore_permissions=True)
|
||||
print(f"DEBUG: Updated Quotation document: {estimate_doc.as_dict()}")
|
||||
return estimate_doc
|
||||
|
||||
@staticmethod
|
||||
def create(estimate_data: dict) -> frappe._dict:
|
||||
"""Create a new Quotation document."""
|
||||
print(f"DEBUG: Creating new Quotation with data: {estimate_data}")
|
||||
estimate_doc = frappe.get_doc({
|
||||
"doctype": "Quotation",
|
||||
**estimate_data
|
||||
})
|
||||
estimate_doc.insert(ignore_permissions=True)
|
||||
print(f"DEBUG: Created Quotation document: {estimate_doc.as_dict()}")
|
||||
return estimate_doc
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ const formatDate = (date) => {
|
|||
|
||||
.section-label {
|
||||
font-weight: 500;
|
||||
color: var(--theme-text-dark);
|
||||
color: var(--theme-text-muted);
|
||||
white-space: nowrap;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
|
@ -130,7 +130,7 @@ const formatDate = (date) => {
|
|||
|
||||
.customer-name {
|
||||
font-size: 0.75rem;
|
||||
color: var(--theme-text-dark);
|
||||
color: var(--theme-text-muted);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ const themeMap = {
|
|||
textMuted: "#8798afff",
|
||||
textDark: "#0b1220",
|
||||
textLight: "#ffffff",
|
||||
textAlt: "#06274aff",
|
||||
},
|
||||
"Nuco Yard Care": {
|
||||
primary: "#3b7f2f",
|
||||
|
|
@ -43,7 +42,6 @@ const themeMap = {
|
|||
textMuted: "#4b5b35",
|
||||
textDark: "#192016",
|
||||
textLight: "#ffffff",
|
||||
textAlt: "#172519ff",
|
||||
},
|
||||
"Lowe Fencing": {
|
||||
primary: "#2f3b52",
|
||||
|
|
@ -65,7 +63,6 @@ const themeMap = {
|
|||
textMuted: "#42506a",
|
||||
textDark: "#0b1220",
|
||||
textLight: "#ffffff",
|
||||
textAlt: "#291d3aff",
|
||||
},
|
||||
"Veritas Stone": {
|
||||
primary: "#7a6f63",
|
||||
|
|
@ -87,7 +84,6 @@ const themeMap = {
|
|||
textMuted: "#5a5047",
|
||||
textDark: "#231c16",
|
||||
textLight: "#ffffff",
|
||||
textAlt: "#25201bff",
|
||||
},
|
||||
"Daniels Landscape Supplies": {
|
||||
primary: "#2f6b2f",
|
||||
|
|
@ -109,7 +105,6 @@ const themeMap = {
|
|||
textMuted: "#4f5b3f",
|
||||
textDark: "#162016",
|
||||
textLight: "#ffffff",
|
||||
textAlt: "#172519ff",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue