diff --git a/westech_r2/doctype/pallet/pallet.js b/westech_r2/doctype/pallet/pallet.js index 46771c9..98e1e19 100644 --- a/westech_r2/doctype/pallet/pallet.js +++ b/westech_r2/doctype/pallet/pallet.js @@ -11,5 +11,61 @@ frappe.ui.form.on('Pallet', { 'pallet': frm.doc.pallet_number || frm.doc.name }); }, __('View')); + }, + + customer_number: function(frm) { + var customer = frm.doc.customer_number; + if (!customer) { + clear_customer_fields(frm); + return; + } + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Supplier', name: customer}, + callback: function(r) { + if (!r.message) return; + var s = r.message; + if (!frm.doc.supplier) { + frm.set_value('supplier', s.name); + } + if (!frm.doc.company_name && s.supplier_name) { + frm.set_value('company_name', s.supplier_name); + } + if (s.supplier_primary_contact) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Contact', name: s.supplier_primary_contact}, + callback: function(cr) { + if (!cr.message) return; + var ct = cr.message; + var full_name = [ct.first_name, ct.last_name].filter(Boolean).join(' '); + if (!frm.doc.contact_name) frm.set_value('contact_name', full_name); + if (!frm.doc.contact_number) frm.set_value('contact_number', ct.phone || ct.mobile_no || ''); + if (!frm.doc.contact_email) frm.set_value('contact_email', ct.email_id || ''); + } + }); + } + if (s.supplier_primary_address) { + frappe.call({ + method: 'frappe.client.get', + args: {doctype: 'Address', name: s.supplier_primary_address}, + callback: function(ar) { + if (!ar.message) return; + var a = ar.message; + if (!frm.doc.address_line) frm.set_value('address_line', a.address_line1 || ''); + } + }); + } + } + }); } }); + +function clear_customer_fields(frm) { + frm.set_value('supplier', ''); + frm.set_value('company_name', ''); + frm.set_value('contact_name', ''); + frm.set_value('contact_number', ''); + frm.set_value('contact_email', ''); + frm.set_value('address_line', ''); +} diff --git a/westech_r2/page/pallet-list/__init__.py b/westech_r2/page/pallet-list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/page/pallet-list/pallet-list.html b/westech_r2/page/pallet-list/pallet-list.html new file mode 100644 index 0000000..3414f7f --- /dev/null +++ b/westech_r2/page/pallet-list/pallet-list.html @@ -0,0 +1,51 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Pallet #Date ReservedRec. DateCustomer #CompanyLbsWhoItemsQTY SaleLbs SaleFinish DateStatusNotes
Loading...
+
+ +
diff --git a/westech_r2/page/pallet-list/pallet-list.js b/westech_r2/page/pallet-list/pallet-list.js new file mode 100644 index 0000000..0c3f9c1 --- /dev/null +++ b/westech_r2/page/pallet-list/pallet-list.js @@ -0,0 +1,128 @@ +frappe.pages["pallet-list"].on_page_load = function(wrapper) { + var page = frappe.ui.make_app_page({ + parent: wrapper, + title: __("Pallet List"), + single_column: true + }); + + var content = frappe.render_template("pallet-list", {}); + $(page.body).append(content); + + var currentPage = 1; + var pageSize = 100; + var currentSort = "pallet_number"; + var sortDir = "desc"; + var searchTerm = ""; + var statusFilter = ""; + + function loadPallets() { + frappe.call({ + method: "westech_r2.page.pallet-list.pallet-list.get_pallets", + args: { + page: currentPage, + page_size: pageSize, + sort_field: currentSort, + sort_dir: sortDir, + status_filter: statusFilter, + search: searchTerm + }, + callback: function(r) { + if (r.message) { + renderPallets(r.message.pallets, r.message.total); + } + } + }); + } + + function renderPallets(pallets, total) { + var tbody = $("#pallet-tbody"); + tbody.empty(); + + if (!pallets || pallets.length === 0) { + tbody.append('No pallets found'); + return; + } + + pallets.forEach(function(p) { + var statusClass = "status-" + (p.status || "").toLowerCase().replace(/\s+/g, "-"); + var link = "/app/pallet/" + encodeURIComponent(p.name); + var pn = (p.pallet_number || "").replace(//g, ">"); + + var row = '' + + '' + pn + '' + + '' + fmtDate(p.date_reserved) + '' + + '' + fmtDate(p.received_date) + '' + + '' + (p.customer_number || "") + '' + + '' + (p.company_name || "") + '' + + '' + (p.inbound_weight || "") + '' + + '' + (p.tester || "") + '' + + '' + (p.description || "") + '' + + '' + (p.qty_to_sales || "") + '' + + '' + (p.weight_to_sales || "") + '' + + '' + fmtDate(p.finish_date) + '' + + '' + (p.status || "") + '' + + '' + (p.notes || "").substring(0, 50) + '' + + ''; + tbody.append(row); + }); + + renderPagination(total); + } + + function renderPagination(total) { + var totalPages = Math.ceil(total / pageSize); + var pagination = $("#pallet-pagination"); + pagination.empty(); + + if (totalPages <= 1) return; + + var prevBtn = $('').attr("disabled", currentPage === 1) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage > 1) { currentPage--; loadPallets(); } + }); + pagination.append(prevBtn); + + var startPage = Math.max(1, currentPage - 2); + var endPage = Math.min(totalPages, startPage + 4); + + for (var i = startPage; i <= endPage; i++) { + var btn = $('') + .css({padding: "5px 12px", border: "1px solid #ddd", background: i === currentPage ? "#3cc062" : "white", + color: i === currentPage ? "white" : "#333", cursor: "pointer", marginRight: "5px"}) + .on("click", function(page) { + return function() { currentPage = page; loadPallets(); }; + }(i)); + pagination.append(btn); + } + + var nextBtn = $('').attr("disabled", currentPage === totalPages) + .css({padding: "5px 12px", border: "1px solid #ddd", background: "white", cursor: "pointer", marginRight: "5px"}) + .on("click", function() { + if (currentPage < totalPages) { currentPage++; loadPallets(); } + }); + pagination.append(nextBtn); + } + + function fmtDate(v) { + if (!v) return ""; + var s = String(v); + if (s.indexOf("T") > -1) s = s.split("T")[0]; + if (s.indexOf(" ") > -1) s = s.split(" ")[0]; + return s; + } + + $("#pallet-search").on("input", function() { + searchTerm = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + $("#status-filter").on("change", function() { + statusFilter = $(this).val(); + currentPage = 1; + loadPallets(); + }); + + loadPallets(); +}; diff --git a/westech_r2/page/pallet-list/pallet-list.json b/westech_r2/page/pallet-list/pallet-list.json new file mode 100644 index 0000000..d7304c4 --- /dev/null +++ b/westech_r2/page/pallet-list/pallet-list.json @@ -0,0 +1,19 @@ +{ + content: null, + creation: 2026-05-19 13:00:00.000000, + docstatus: 0, + doctype: Page, + idx: 0, + modified: 2026-05-19 13:00:00.000000, + modified_by: Administrator, + module: Westech R2, + name: pallet-list, + owner: Administrator, + page_name: pallet-list, + roles: [], + script: null, + standard: Yes, + style: null, + system_page: 0, + title: Pallet List +} diff --git a/westech_r2/page/pallet-list/pallet-list.py b/westech_r2/page/pallet-list/pallet-list.py new file mode 100644 index 0000000..64730c5 --- /dev/null +++ b/westech_r2/page/pallet-list/pallet-list.py @@ -0,0 +1,63 @@ +import frappe +import json + +@frappe.whitelist() +def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""): + """Fetch pallets from ERPNext with filters.""" + page = int(page) + page_size = int(page_size) + offset = (page - 1) * page_size + + # Base filters + filters = [ + ["Pallet", "pallet_number", "is", "set"], + ["Pallet", "date_reserved", "is", "set"], + ] + + if status_filter: + filters.append(["Pallet", "status", "=", status_filter]) + if search: + filters.append(["Pallet", "pallet_number", "like", f"%{search}%"]) + + fields = [ + "name", "pallet_number", "date_reserved", "received_date", + "customer_number", "company_name", "inbound_weight", "tester", + "description", "qty_to_sales", "weight_to_sales", "finish_date", "notes", "status" + ] + + order_by = f"{sort_field} {sort_dir}" + + # Get total count + count_result = frappe.get_list( + "Pallet", + filters=filters, + fields=["count(*) as total"], + as_list=True + ) + total = count_result[0][0] if count_result else 0 + + # Get pallets + pallets = frappe.get_list( + "Pallet", + filters=filters, + fields=fields, + order_by=order_by, + limit_page_length=page_size, + limit_start=offset + ) + + return { + "pallets": pallets, + "total": total, + "page": page, + "page_size": page_size + } + +@frappe.whitelist() +def update_pallet(docname, field, value): + """Update a single field on a Pallet.""" + pallet = frappe.get_doc("Pallet", docname) + pallet.set(field, value) + pallet.save(ignore_permissions=True) + frappe.db.commit() + return {"status": "ok", "message": f"Updated {field}"}