From cb59dd65caacc31859fada787b502468572a4948 Mon Sep 17 00:00:00 2001 From: Casey Date: Fri, 2 Jan 2026 15:55:27 -0600 Subject: [PATCH] add template get --- custom_ui/api/db/estimates.py | 77 +++++++++++++++++- custom_ui/fixtures/doctype.json | 66 ++++++++++++++- frontend/src/api.js | 5 ++ .../src/components/clientSubPages/History.vue | 42 +++++----- frontend/src/components/pages/Estimate.vue | 80 ++++++++++++++++++- 5 files changed, 246 insertions(+), 24 deletions(-) diff --git a/custom_ui/api/db/estimates.py b/custom_ui/api/db/estimates.py index b961ee5..7576488 100644 --- a/custom_ui/api/db/estimates.py +++ b/custom_ui/api/db/estimates.py @@ -260,8 +260,81 @@ def update_response(name, response): html = frappe.render_template(template, {"error": str(e)}) return Response(html, mimetype="text/html") - - +@frappe.whitelist() +def get_estimate_templates(company): + """Get available estimate templates.""" + filters = {"is_active": 1} + if 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) + + result = [] + if not templates: + print("DEBUG: No templates found.") + return build_success_response(result) + for template in templates: + items = frappe.get_all("Quotation Template Item", + fields=["item_code", "item_name", "description", "qty", "discount_percentage", "rate"], + filters={"parent": template.name}, + order_by="idx") + + # Map fields to camelCase as requested + mapped_items = [] + for item in items: + mapped_items.append({ + "itemCode": item.item_code, + "itemName": item.item_name, + "description": item.description, + "quantity": item.qty, + "discountPercentage": item.discount_percentage, + "rate": item.rate + }) + + result.append({ + "templateName": template.name, + "active": template.active, + "description": template.description, + "items": mapped_items + }) + + return build_success_response(result) + 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/custom_ui/fixtures/doctype.json b/custom_ui/fixtures/doctype.json index 72f23a9..c06140a 100644 --- a/custom_ui/fixtures/doctype.json +++ b/custom_ui/fixtures/doctype.json @@ -413,6 +413,70 @@ "trigger": null, "unique": 0, "width": null + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "default": null, + "depends_on": null, + "description": null, + "documentation_url": null, + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "is_virtual": 0, + "label": "Company", + "length": 0, + "link_filters": null, + "make_attachment_public": 0, + "mandatory_depends_on": null, + "max_height": null, + "no_copy": 0, + "non_negative": 0, + "oldfieldname": null, + "oldfieldtype": null, + "options": "Company", + "parent": "Quotation Template", + "parentfield": "fields", + "parenttype": "DocType", + "permlevel": 0, + "placeholder": null, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "show_dashboard": 0, + "show_on_timeline": 0, + "show_preview_popup": 0, + "sort_options": 0, + "translatable": 0, + "trigger": null, + "unique": 0, + "width": null } ], "force_re_route_to_default_view": 0, @@ -435,7 +499,7 @@ "max_attachments": 0, "menu_index": null, "migration_hash": null, - "modified": "2025-12-23 02:03:44.840865", + "modified": "2026-01-02 11:26:31.164108", "module": "Selling", "name": "Quotation Template", "naming_rule": "", diff --git a/frontend/src/api.js b/frontend/src/api.js index a895290..2f9cc4c 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -12,6 +12,7 @@ const FRAPPE_GET_ESTIMATE_BY_ADDRESS_METHOD = "custom_ui.api.db.estimates.get_es const FRAPPE_SEND_ESTIMATE_EMAIL_METHOD = "custom_ui.api.db.estimates.send_estimate_email"; 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"; // 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"; @@ -222,6 +223,10 @@ class Api { return await this.request(FRAPPE_ESTIMATE_UPDATE_RESPONSE_METHOD, {name: estimateName, response}); } + static async getEstimateTemplates(company) { + return await this.request(FRAPPE_GET_ESTIMATE_TEMPLATES_METHOD, { company }); + } + // ============================================================================ // JOB / PROJECT METHODS // ============================================================================ diff --git a/frontend/src/components/clientSubPages/History.vue b/frontend/src/components/clientSubPages/History.vue index a6c2b13..4da28ec 100644 --- a/frontend/src/components/clientSubPages/History.vue +++ b/frontend/src/components/clientSubPages/History.vue @@ -1,24 +1,26 @@