Fix 2024 pallet numbering and update pallet-list page
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,51 +1,82 @@
|
|||||||
<style>
|
<style>
|
||||||
.pallet-table-container { padding: 0; overflow-x: auto; }
|
.pallet-list-page { font-family: Helvetica Neue, Arial, sans-serif; }
|
||||||
|
.pallet-list-page h2 { color: #2F5496; margin-bottom: 16px; font-size: 20px; }
|
||||||
|
.pallet-search-box { margin-bottom: 16px; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
|
||||||
|
.pallet-search-box input, .pallet-search-box select {
|
||||||
|
padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px;
|
||||||
|
}
|
||||||
|
.pallet-search-box button {
|
||||||
|
padding: 6px 14px; border: 1px solid #ddd; border-radius: 4px; cursor: pointer;
|
||||||
|
font-size: 13px; background: white;
|
||||||
|
}
|
||||||
|
.pallet-search-box button.btn-primary { background: #2F5496; color: white; border-color: #2F5496; }
|
||||||
|
.pallet-search-box button.btn-success { background: #548235; color: white; border-color: #548235; }
|
||||||
|
.pallet-table-container { padding: 0; overflow-x: auto; background: white; border-radius: 4px; }
|
||||||
.pallet-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
.pallet-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||||
.pallet-table th { background: #3cc062; color: white; padding: 8px 10px; text-align: left; cursor: pointer; }
|
.pallet-table th {
|
||||||
|
background: #2F5496; color: white; padding: 8px 10px; text-align: left;
|
||||||
|
cursor: pointer; white-space: nowrap; font-weight: 500;
|
||||||
|
}
|
||||||
.pallet-table td { padding: 5px 10px; border-bottom: 1px solid #eee; }
|
.pallet-table td { padding: 5px 10px; border-bottom: 1px solid #eee; }
|
||||||
.pallet-table tr:hover { background: #f5f5f5; }
|
.pallet-table tr:hover { background: #f5f5f5; }
|
||||||
.status-received { color: #2196F3; }
|
.pallet-table tr.new-row { background: #FFF9E6 !important; }
|
||||||
.status-sorting { color: #FF9800; }
|
.pallet-table a { color: #2F5496; text-decoration: none; font-weight: 600; }
|
||||||
.status-processing { color: #9C27B0; }
|
.status-received { color: #2196F3; font-weight: 600; }
|
||||||
.status-complete { color: #4CAF50; }
|
.status-sorting { color: #FF9800; font-weight: 600; }
|
||||||
.status-shipped { color: #607D8B; }
|
.status-processing { color: #9C27B0; font-weight: 600; }
|
||||||
|
.status-complete { color: #4CAF50; font-weight: 600; }
|
||||||
|
.status-shipped { color: #607D8B; font-weight: 600; }
|
||||||
|
.pallet-pagination { margin-top: 12px; display: flex; gap: 5px; align-items: center; }
|
||||||
|
.pallet-pagination button {
|
||||||
|
padding: 5px 12px; border: 1px solid #ddd; background: white; cursor: pointer;
|
||||||
|
border-radius: 4px; font-size: 13px; color: #2F5496;
|
||||||
|
}
|
||||||
|
.pallet-pagination button.active { background: #2F5496; color: white; border-color: #2F5496; }
|
||||||
|
.pallet-pagination button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
.pallet-count { margin-left: auto; color: #666; font-size: 13px; }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="search-box">
|
<div class="pallet-list-page">
|
||||||
<input type="text" id="pallet-search" placeholder="Search pallet #...">
|
<h2>📦 Pallet List</h2>
|
||||||
<select id="status-filter">
|
|
||||||
<option value="">All</option>
|
|
||||||
<option value="Received">Received</option>
|
|
||||||
<option value="Sorting">Sorting</option>
|
|
||||||
<option value="Processing">Processing</option>
|
|
||||||
<option value="Complete">Complete</option>
|
|
||||||
<option value="Shipped">Shipped</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pallet-table-container">
|
<div class="pallet-search-box">
|
||||||
<table class="pallet-table" id="pallet-table">
|
<input type="text" id="pallet-search" placeholder="Search pallet #..." style="max-width:200px;">
|
||||||
<thead>
|
<select id="status-filter">
|
||||||
<tr>
|
<option value="">All Statuses</option>
|
||||||
<th>Pallet #</th>
|
<option value="Received">Received</option>
|
||||||
<th>Date Reserved</th>
|
<option value="Sorting">Sorting</option>
|
||||||
<th>Rec. Date</th>
|
<option value="Processing">Processing</option>
|
||||||
<th>Customer #</th>
|
<option value="Complete">Complete</option>
|
||||||
<th>Company</th>
|
<option value="Shipped">Shipped</option>
|
||||||
<th>Lbs</th>
|
</select>
|
||||||
<th>Who</th>
|
<button class="btn btn-default" id="btn-clear">✕ Clear</button>
|
||||||
<th>Items</th>
|
<button class="btn btn-success" id="btn-export">⬇ Export CSV</button>
|
||||||
<th>QTY Sale</th>
|
<span class="pallet-count" id="pallet-count"></span>
|
||||||
<th>Lbs Sale</th>
|
</div>
|
||||||
<th>Finish Date</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Notes</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="pallet-tbody">
|
|
||||||
<tr><td colspan="13" style="text-align:center;padding:40px;">Loading...</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="pallet-pagination" style="margin-top:12px;"\u003e</div>
|
<div class="pallet-table-container">
|
||||||
|
<table class="pallet-table" id="pallet-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-sort="pallet_number">Pallet # ⇅</th>
|
||||||
|
<th data-sort="date_reserved">Date Reserved ⇅</th>
|
||||||
|
<th data-sort="received_date">Rec. Date ⇅</th>
|
||||||
|
<th data-sort="customer_number">Customer # ⇅</th>
|
||||||
|
<th data-sort="inbound_weight">Lbs ⇅</th>
|
||||||
|
<th data-sort="tester">Who ⇅</th>
|
||||||
|
<th data-sort="description">Items Tested ⇅</th>
|
||||||
|
<th data-sort="qty_to_sales">QTY Sale ⇅</th>
|
||||||
|
<th data-sort="weight_to_sales">Lbs Sale ⇅</th>
|
||||||
|
<th data-sort="finish_date">Finish Date ⇅</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Notes</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="pallet-tbody">
|
||||||
|
<tr><td colspan="12" style="text-align:center;padding:40px;color:#666;">Loading...</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pallet-pagination" id="pallet-pagination"></div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,50 +1,40 @@
|
|||||||
import frappe
|
import frappe
|
||||||
import json
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="desc", status_filter="", search=""):
|
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 = int(page)
|
||||||
page_size = int(page_size)
|
page_size = int(page_size)
|
||||||
offset = (page - 1) * page_size
|
offset = (page - 1) * page_size
|
||||||
|
|
||||||
# Base filters
|
# Only pallets with dates (filters empty rows)
|
||||||
filters = [
|
conditions = ["pallet_number IS NOT NULL", "pallet_number != ", "date_reserved IS NOT NULL"]
|
||||||
["Pallet", "pallet_number", "is", "set"],
|
|
||||||
["Pallet", "date_reserved", "is", "set"],
|
# Junk filter (same as EIM)
|
||||||
]
|
junk = ["", "0", "0000", "N/A", "TBD", "null"]
|
||||||
|
conditions.append("pallet_number NOT IN ( + , .join(junk) + )")
|
||||||
|
|
||||||
if status_filter:
|
if status_filter:
|
||||||
filters.append(["Pallet", "status", "=", status_filter])
|
conditions.append("status = {0}".format(frappe.db.escape(status_filter)))
|
||||||
if search:
|
if search:
|
||||||
filters.append(["Pallet", "pallet_number", "like", f"%{search}%"])
|
conditions.append("pallet_number LIKE %{0}%".format(frappe.db.escape(search)))
|
||||||
|
|
||||||
fields = [
|
where_clause = " AND ".join(conditions)
|
||||||
"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
|
||||||
|
total = frappe.db.sql("""SELECT COUNT(*) FROM tabPallet WHERE {0}""".format(where_clause))[0][0]
|
||||||
|
|
||||||
# Get total count
|
# Get pallets - convert pallet_number to unsigned int for numeric sort
|
||||||
count_result = frappe.get_list(
|
# Use natural sort: convert to int for proper numeric ordering
|
||||||
"Pallet",
|
pallets = frappe.db.sql("""
|
||||||
filters=filters,
|
SELECT
|
||||||
fields=["count(*) as total"],
|
name, pallet_number, date_reserved, received_date,
|
||||||
as_list=True
|
customer_number, inbound_weight, tester,
|
||||||
)
|
description, qty_to_sales, weight_to_sales, finish_date, notes, status
|
||||||
total = count_result[0][0] if count_result else 0
|
FROM tabPallet
|
||||||
|
WHERE {0}
|
||||||
# Get pallets
|
ORDER BY CAST(pallet_number AS UNSIGNED) {1}
|
||||||
pallets = frappe.get_list(
|
LIMIT {2} OFFSET {3}
|
||||||
"Pallet",
|
""".format(where_clause, sort_dir, page_size, offset), as_dict=True)
|
||||||
filters=filters,
|
|
||||||
fields=fields,
|
|
||||||
order_by=order_by,
|
|
||||||
limit_page_length=page_size,
|
|
||||||
limit_start=offset
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"pallets": pallets,
|
"pallets": pallets,
|
||||||
@@ -52,12 +42,3 @@ def get_pallets(page=1, page_size=100, sort_field="pallet_number", sort_dir="des
|
|||||||
"page": page,
|
"page": page,
|
||||||
"page_size": page_size
|
"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}"}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user