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 @@ + + + + + diff --git a/frontend/src/components/pages/Estimate.vue b/frontend/src/components/pages/Estimate.vue index 79803be..ff53e7b 100644 --- a/frontend/src/components/pages/Estimate.vue +++ b/frontend/src/components/pages/Estimate.vue @@ -60,24 +60,29 @@ -
- - +
+
+ + +
+
+
@@ -198,6 +203,13 @@