diff --git a/custom_ui/api/db/estimates.py b/custom_ui/api/db/estimates.py
index 7576488..c1ac907 100644
--- a/custom_ui/api/db/estimates.py
+++ b/custom_ui/api/db/estimates.py
@@ -268,15 +268,17 @@ def get_estimate_templates(company):
filters["company"] = company
try:
print("DEBUG: Fetching estimate templates for company:", company)
- templates = frappe.get_all("Quotation Template", fields=["name", "is_active", "description"], filters=filters)
+ templates = frappe.get_all("Quotation Template", fields=["*"], filters=filters)
result = []
if not templates:
print("DEBUG: No templates found.")
return build_success_response(result)
+ print(f"DEBUG: Found {len(templates)} templates.")
for template in templates:
+ print("DEBUG: Processing template:", template)
items = frappe.get_all("Quotation Template Item",
- fields=["item_code", "item_name", "description", "qty", "discount_percentage", "rate"],
+ fields=["item_code", "item_name", "description", "quantity", "discount_percentage", "rate"],
filters={"parent": template.name},
order_by="idx")
@@ -293,8 +295,9 @@ def get_estimate_templates(company):
})
result.append({
- "templateName": template.name,
- "active": template.active,
+ "name": template.name,
+ "templateName": template.template_name,
+ "active": template.is_active,
"description": template.description,
"items": mapped_items
})
@@ -302,39 +305,74 @@ def get_estimate_templates(company):
return build_success_response(result)
except Exception as e:
return build_error_response(str(e), 500)
-
+
@frappe.whitelist()
-def create_template(data):
+def create_estimate_template(data):
"""Create a new estimate template."""
try:
- data = json.loads(data) if isinstance(data, str) else data
print("DEBUG: Creating estimate template with data:", data)
+ data = json.loads(data) if isinstance(data, str) else data
- new_template = frappe.get_doc({
+ doc_data = {
"doctype": "Quotation Template",
- "template_name": data.get("templateName"),
- "is_active": data.get("active", 1),
- "description": data.get("description", ""),
- "company": data.get("company", ""),
+ "is_active": 1,
+ "description": data.get("description"),
+ "company": data.get("company"),
+ "items": [],
+ "template_name": data.get("template_name"),
"source_quotation": data.get("source_quotation", "")
- })
+ }
+
+
+ new_template = frappe.get_doc(doc_data)
for item in data.get("items", []):
- item = json.loads(item) if isinstance(item, str) else item
new_template.append("items", {
- "item_code": item.get("itemCode"),
- "item_name": item.get("itemName"),
+ "item_code": item.get("item_code"),
+ "item_name": item.get("item_name"),
"description": item.get("description"),
- "qty": item.get("quantity"),
- "discount_percentage": item.get("discountPercentage"),
- "rate": item.get("rate")
+ "qty": item.get("qty") or item.get("quantity"),
+ "rate": item.get("standard_rate") or item.get("rate"),
+ "discount_percentage": item.get("discount_percentage")
})
-
+
new_template.insert()
- print("DEBUG: New estimate template created with name:", new_template.name)
- return build_success_response(new_template.as_dict())
+ return build_success_response(new_template.name)
except Exception as e:
return build_error_response(str(e), 500)
+
+# @frappe.whitelist()
+# def create_template(data):
+# """Create a new estimate template."""
+# try:
+# data = json.loads(data) if isinstance(data, str) else data
+# print("DEBUG: Creating estimate template with data:", data)
+
+# new_template = frappe.get_doc({
+# "doctype": "Quotation Template",
+# "template_name": data.get("templateName"),
+# "is_active": data.get("active", 1),
+# "description": data.get("description", ""),
+# "company": data.get("company", ""),
+# "source_quotation": data.get("source_quotation", "")
+# })
+
+# for item in data.get("items", []):
+# item = json.loads(item) if isinstance(item, str) else item
+# new_template.append("items", {
+# "item_code": item.get("itemCode"),
+# "item_name": item.get("itemName"),
+# "description": item.get("description"),
+# "qty": item.get("quantity"),
+# "discount_percentage": item.get("discountPercentage"),
+# "rate": item.get("rate")
+# })
+
+# new_template.insert()
+# print("DEBUG: New estimate template created with name:", new_template.name)
+# return build_success_response(new_template.as_dict())
+# except Exception as e:
+# return build_error_response(str(e), 500)
@frappe.whitelist()
def upsert_estimate(data):
diff --git a/frontend/src/api.js b/frontend/src/api.js
index 2f9cc4c..d3e2b0c 100644
--- a/frontend/src/api.js
+++ b/frontend/src/api.js
@@ -13,6 +13,7 @@ const FRAPPE_SEND_ESTIMATE_EMAIL_METHOD = "custom_ui.api.db.estimates.send_estim
const FRAPPE_LOCK_ESTIMATE_METHOD = "custom_ui.api.db.estimates.lock_estimate";
const FRAPPE_ESTIMATE_UPDATE_RESPONSE_METHOD = "custom_ui.api.db.estimates.manual_response";
const FRAPPE_GET_ESTIMATE_TEMPLATES_METHOD = "custom_ui.api.db.estimates.get_estimate_templates";
+const FRAPPE_CREATE_ESTIMATE_TEMPLATE_METHOD = "custom_ui.api.db.estimates.create_estimate_template";
// Job methods
const FRAPPE_GET_JOB_METHOD = "custom_ui.api.db.jobs.get_job";
const FRAPPE_GET_JOBS_METHOD = "custom_ui.api.db.jobs.get_jobs_table_data";
@@ -227,6 +228,10 @@ class Api {
return await this.request(FRAPPE_GET_ESTIMATE_TEMPLATES_METHOD, { company });
}
+ static async createEstimateTemplate(data) {
+ return await this.request(FRAPPE_CREATE_ESTIMATE_TEMPLATE_METHOD, { data });
+ }
+
// ============================================================================
// JOB / PROJECT METHODS
// ============================================================================
diff --git a/frontend/src/components/modals/SaveTemplateModal.vue b/frontend/src/components/modals/SaveTemplateModal.vue
new file mode 100644
index 0000000..aa94837
--- /dev/null
+++ b/frontend/src/components/modals/SaveTemplateModal.vue
@@ -0,0 +1,82 @@
+
+