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 @@ + + + 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,