diff --git a/custom_ui/api/db/estimates.py b/custom_ui/api/db/estimates.py index 70983f7..e743bd5 100644 --- a/custom_ui/api/db/estimates.py +++ b/custom_ui/api/db/estimates.py @@ -286,20 +286,21 @@ def get_estimate_templates(company): mapped_items = [] for item in items: mapped_items.append({ - "itemCode": item.item_code, - "itemName": item.item_name, + "item_code": item.item_code, + "item_name": item.item_name, "description": item.description, - "quantity": item.qty, - "discountPercentage": item.discount_percentage, + "quantity": item.quantity, + "discount_percentage": item.discount_percentage, "rate": item.rate }) result.append({ "name": template.name, - "templateName": template.template_name, + "template_name": template.template_name, "active": template.is_active, "description": template.description, - "items": mapped_items + "items": mapped_items, + "project_template": template.project_template, }) return build_success_response(result) @@ -320,6 +321,7 @@ def create_estimate_template(data): "company": data.get("company"), "items": [], "template_name": data.get("template_name"), + "custom_project_template": data.get("project_template", ""), "source_quotation": data.get("source_quotation", "") } @@ -448,8 +450,8 @@ def upsert_estimate(data): def get_estimate_history(estimate_name): """Get the history of changes for a specific estimate.""" - - return history + pass + # return history # @frappe.whitelist() # def get_estimate_counts(): diff --git a/custom_ui/events/jobs.py b/custom_ui/events/jobs.py index 2039480..f05774c 100644 --- a/custom_ui/events/jobs.py +++ b/custom_ui/events/jobs.py @@ -1,5 +1,5 @@ import frappe -def after_insert(doc, method): +def before_insert(doc, method): # This is where we will add logic to set tasks and other properties of a job based on it's project_template pass \ No newline at end of file diff --git a/frontend/src/components/pages/Estimate.vue b/frontend/src/components/pages/Estimate.vue index a536a7e..229dc2d 100644 --- a/frontend/src/components/pages/Estimate.vue +++ b/frontend/src/components/pages/Estimate.vue @@ -59,6 +59,41 @@ + +
+
+ +
+ +
+
+
+
+
+
- -
-
- - -
-
-
-
-

Items

@@ -408,6 +417,17 @@ const isEditable = computed(() => { return estimate.value.customSent === 0; }); +const templateOptions = computed(() => { + return [ + { name: null, templateName: 'None', description: 'Start from scratch' }, + ...templates.value + ]; +}); + +const isProjectTemplateDisabled = computed(() => { + return selectedTemplate.value !== null; +}); + const itemColumns = [ { label: "Item Code", fieldName: "itemCode", type: "text" }, { label: "Item Name", fieldName: "itemName", type: "text" }, @@ -437,24 +457,49 @@ const fetchTemplates = async () => { }; const onTemplateChange = () => { - const template = templates.value.find(t => t.name === selectedTemplate.value); - if (template && template.items) { - selectedItems.value = template.items.map(item => ({ - itemCode: item.itemCode, - itemName: item.itemName, - qty: item.quantity, - standardRate: item.rate, - discountAmount: null, - discountPercentage: item.discountPercentage, - discountType: item.discountPercentage > 0 ? 'percentage' : 'currency' - })); - // Calculate discount amounts - selectedItems.value.forEach(item => { - if (item.discountType === 'percentage') { - updateDiscountFromPercentage(item); - } - }); + if (!selectedTemplate.value) { + // None selected - clear items and project template + selectedItems.value = []; + formData.projectTemplate = null; + return; } + + const template = templates.value.find(t => t.name === selectedTemplate.value); + console.log("DEBUG: Selected template:", template); + if (template) { + // Auto-select project template if available (check both camelCase and snake_case) + const projectTemplateValue = template.projectTemplate || template.project_template; + console.log("DEBUG: Project template value from template:", projectTemplateValue); + console.log("DEBUG: Available project templates:", projectTemplates.value); + if (projectTemplateValue) { + formData.projectTemplate = projectTemplateValue; + console.log("DEBUG: Set formData.projectTemplate to:", formData.projectTemplate); + } + + if (template.items) { + selectedItems.value = template.items.map(item => ({ + itemCode: item.itemCode, + itemName: item.itemName, + qty: item.quantity, + standardRate: item.rate, + discountAmount: null, + discountPercentage: item.discountPercentage, + discountType: item.discountPercentage > 0 ? 'percentage' : 'currency' + })); + // Calculate discount amounts + selectedItems.value.forEach(item => { + if (item.discountType === 'percentage') { + updateDiscountFromPercentage(item); + } + }); + } + } +}; + +const clearTemplate = () => { + selectedTemplate.value = null; + selectedItems.value = []; + formData.projectTemplate = null; }; const openSaveTemplateModal = () => { @@ -468,6 +513,7 @@ const confirmSaveTemplate = async (templateData) => { description: templateData.description, company: company.currentCompany, sourceQuotation: estimate.value.name, + projectTemplate: formData.projectTemplate, items: selectedItems.value.map(item => ({ itemCode: item.itemCode, itemName: item.itemName, @@ -898,6 +944,16 @@ onMounted(async () => { margin-bottom: 1.5rem; } +.template-input-group { + display: flex; + gap: 0.5rem; + align-items: center; +} + +.clear-button { + flex-shrink: 0; +} + .field-label { display: block; margin-bottom: 0.5rem;