diff --git a/custom_ui/api/db/estimates.py b/custom_ui/api/db/estimates.py
index b1cb7db..d9ad39e 100644
--- a/custom_ui/api/db/estimates.py
+++ b/custom_ui/api/db/estimates.py
@@ -1,10 +1,52 @@
import frappe, json
-from custom_ui.db_utils import process_query_conditions, build_datatable_response, get_count_or_filters
+from custom_ui.db_utils import process_query_conditions, build_datatable_dict, get_count_or_filters, build_success_response
# ===============================================================================
# ESTIMATES & INVOICES API METHODS
# ===============================================================================
+
+@frappe.whitelist()
+def get_estimate_table_data(filters={}, sortings=[], page=1, page_size=10):
+ """Get paginated estimate table data with filtering and sorting support."""
+ print("DEBUG: Raw estimate options received:", filters, sortings, page, page_size)
+
+ processed_filters, processed_sortings, is_or, page, page_size = process_query_conditions(filters, sortings, page, page_size)
+
+ if is_or:
+ count = frappe.db.sql(*get_count_or_filters("Quotation", processed_filters))[0][0]
+ else:
+ count = frappe.db.count("Quotation", filters=processed_filters)
+
+ print(f"DEBUG: Number of estimates returned: {count}")
+
+ estimates = frappe.db.get_all(
+ "Quotation",
+ fields=["*"],
+ filters=processed_filters if not is_or else None,
+ or_filters=processed_filters if is_or else None,
+ limit=page_size,
+ start=(page - 1) * page_size,
+ order_by=processed_sortings
+ )
+
+ tableRows = []
+ for estimate in estimates:
+ tableRow = {}
+ tableRow["id"] = estimate["name"]
+ tableRow["name"] = estimate["name"]
+ tableRow["quotation_to"] = estimate.get("quotation_to", "")
+ tableRow["customer"] = estimate.get("party_name", "")
+ tableRow["status"] = estimate.get("custom_current_status", "")
+ tableRow["date"] = estimate.get("transaction_date", "")
+ tableRow["order_type"] = estimate.get("order_type", "")
+ tableRow["items"] = estimate.get("items", "")
+ tableRows.append(tableRow)
+
+ table_data_dict = build_datatable_dict(data=tableRows, count=count, page=page, page_size=page_size)
+ return build_success_response(table_data_dict)
+
+
@frappe.whitelist()
def upsert_estimate(data):
"""Create or update an estimate."""
@@ -16,4 +58,4 @@ def upsert_estimate(data):
def upsert_invoice(data):
"""Create or update an invoice."""
# TODO: Implement invoice creation/update logic
- pass
\ No newline at end of file
+ pass
diff --git a/frontend/src/api.js b/frontend/src/api.js
index 7b6a5b2..8557562 100644
--- a/frontend/src/api.js
+++ b/frontend/src/api.js
@@ -6,6 +6,7 @@ const ZIPPOPOTAMUS_BASE_URL = "https://api.zippopotam.us/us";
const FRAPPE_PROXY_METHOD = "custom_ui.api.proxy.request";
// Estimate methods
const FRAPPE_UPSERT_ESTIMATE_METHOD = "custom_ui.api.db.estimates.upsert_estimate";
+const FRAPPE_GET_ESTIMATES_METHOD = "custom_ui.api.db.estimates.get_estimate_table_data";
// Job methods
const FRAPPE_GET_JOBS_METHOD = "custom_ui.api.db.get_jobs";
const FRAPPE_UPSERT_JOB_METHOD = "custom_ui.api.db.jobs.upsert_job";
@@ -178,6 +179,31 @@ class Api {
return result;
}
+ static async getPaginatedEstimateDetails(paginationParams = {}, filters = {}, sorting = null) {
+ const { page = 0, pageSize = 10, sortField = null, sortOrder = null } = paginationParams;
+
+ // Use sorting from the dedicated sorting parameter first, then fall back to pagination params
+ const actualSortField = sorting?.field || sortField;
+ const actualSortOrder = sorting?.order || sortOrder;
+
+ const options = {
+ page: page + 1, // Backend expects 1-based pages
+ page_size: pageSize,
+ filters,
+ sorting:
+ actualSortField && actualSortOrder
+ ? `${actualSortField} ${actualSortOrder === -1 ? "desc" : "asc"}`
+ : null,
+ for_table: true,
+ };
+
+ console.log("DEBUG: API - Sending estimate options to backend:", options);
+
+ const result = await this.request(FRAPPE_GET_ESTIMATES_METHOD, { options });
+ return result;
+
+ }
+
/**
* Get paginated job data with filtering and sorting
* @param {Object} paginationParams - Pagination parameters from store
diff --git a/frontend/src/components/pages/Estimates.vue b/frontend/src/components/pages/Estimates.vue
new file mode 100644
index 0000000..ade5df6
--- /dev/null
+++ b/frontend/src/components/pages/Estimates.vue
@@ -0,0 +1,172 @@
+
+
+
Estimates
+
+
+
+
+
diff --git a/frontend/src/router.js b/frontend/src/router.js
index f0abe49..2fd655e 100644
--- a/frontend/src/router.js
+++ b/frontend/src/router.js
@@ -3,6 +3,7 @@ import { createRouter, createWebHashHistory } from "vue-router";
import Calendar from "./components/pages/Calendar.vue";
import Clients from "./components/pages/Clients.vue";
import Jobs from "./components/pages/Jobs.vue";
+import Estimates from "./components/pages/Estimates.vue";
import Create from "./components/pages/Create.vue";
import Routes from "./components/pages/Routes.vue";
import TimeSheets from "./components/pages/TimeSheets.vue";
@@ -23,6 +24,7 @@ const routes = [
{ path: "/client", component: Client },
{ path: "/schedule-onsite", component: ScheduleOnSite },
{ path: "/jobs", component: Jobs },
+ { path: "/estimates", component: Estimates },
{ path: "/routes", component: Routes },
{ path: "/create", component: Create },
{ path: "/timesheets", component: TimeSheets },
diff --git a/frontend/src/stores/pagination.js b/frontend/src/stores/pagination.js
index 963d5c4..ea173ba 100644
--- a/frontend/src/stores/pagination.js
+++ b/frontend/src/stores/pagination.js
@@ -20,6 +20,14 @@ export const usePaginationStore = defineStore("pagination", {
sortField: null,
sortOrder: null,
},
+ estimates: {
+ first: 0,
+ page: 0,
+ rows: 10,
+ totalRecords: 0,
+ sortField: null,
+ sortOrder: null,
+ },
timesheets: {
first: 0,
page: 0,