feat: Add Set Orders on Boxes feature with debouncing and page refresh
- Created warehouse_orders.py module with 8 order management functions - Added /warehouse/set-orders-on-boxes route and 7 API endpoints - Implemented 4-tab interface: assign, find, move, and view orders - Changed assign input from dropdown to text field with BOX validation - Fixed location join issue in warehouse.py (use boxes_crates.location_id) - Added debouncing flag to prevent multiple rapid form submissions - Added page refresh after successful order assignment - Disabled assign button during processing - Added page refresh with 2 second delay for UX feedback - Added CP code validation in inventory page - Improved modal styling with theme support - Fixed set_boxes_locations page to refresh box info after assignments
This commit is contained in:
@@ -452,6 +452,7 @@ def get_cp_inventory_list(limit=100, offset=0):
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Get all CP codes with their box and location info (latest entries first)
|
||||
# NOTE: Use box's CURRENT location (from boxes_crates), not the historical scan location
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
s.id,
|
||||
@@ -468,7 +469,7 @@ def get_cp_inventory_list(limit=100, offset=0):
|
||||
SUM(s.rejected_quantity) as total_rejected
|
||||
FROM scanfg_orders s
|
||||
LEFT JOIN boxes_crates bc ON s.box_id = bc.id
|
||||
LEFT JOIN warehouse_locations wl ON s.location_id = wl.id
|
||||
LEFT JOIN warehouse_locations wl ON bc.location_id = wl.id
|
||||
GROUP BY SUBSTRING(s.CP_full_code, 1, 10), s.box_id
|
||||
ORDER BY MAX(s.created_at) DESC
|
||||
LIMIT %s OFFSET %s
|
||||
@@ -476,7 +477,15 @@ def get_cp_inventory_list(limit=100, offset=0):
|
||||
|
||||
# Convert tuples to dicts using cursor description
|
||||
columns = [col[0] for col in cursor.description]
|
||||
results = [{columns[i]: row[i] for i in range(len(columns))} for row in cursor.fetchall()]
|
||||
results = []
|
||||
for row in cursor.fetchall():
|
||||
row_dict = {columns[i]: row[i] for i in range(len(columns))}
|
||||
# Convert time and date fields to strings to avoid JSON serialization issues
|
||||
if row_dict.get('latest_date'):
|
||||
row_dict['latest_date'] = str(row_dict['latest_date'])
|
||||
if row_dict.get('latest_time'):
|
||||
row_dict['latest_time'] = str(row_dict['latest_time'])
|
||||
results.append(row_dict)
|
||||
cursor.close()
|
||||
|
||||
return results if results else []
|
||||
@@ -503,6 +512,7 @@ def search_cp_code(cp_code_search):
|
||||
search_term = cp_code_search.replace('-', '').strip().upper()
|
||||
|
||||
# Search for matching CP codes
|
||||
# NOTE: Use box's CURRENT location (from boxes_crates), not the historical scan location
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
s.id,
|
||||
@@ -519,7 +529,7 @@ def search_cp_code(cp_code_search):
|
||||
SUM(s.rejected_quantity) as total_rejected
|
||||
FROM scanfg_orders s
|
||||
LEFT JOIN boxes_crates bc ON s.box_id = bc.id
|
||||
LEFT JOIN warehouse_locations wl ON s.location_id = wl.id
|
||||
LEFT JOIN warehouse_locations wl ON bc.location_id = wl.id
|
||||
WHERE REPLACE(s.CP_full_code, '-', '') LIKE %s
|
||||
GROUP BY SUBSTRING(s.CP_full_code, 1, 10), s.box_id
|
||||
ORDER BY MAX(s.created_at) DESC
|
||||
@@ -527,7 +537,15 @@ def search_cp_code(cp_code_search):
|
||||
|
||||
# Convert tuples to dicts using cursor description
|
||||
columns = [col[0] for col in cursor.description]
|
||||
results = [{columns[i]: row[i] for i in range(len(columns))} for row in cursor.fetchall()]
|
||||
results = []
|
||||
for row in cursor.fetchall():
|
||||
row_dict = {columns[i]: row[i] for i in range(len(columns))}
|
||||
# Convert time and date fields to strings to avoid JSON serialization issues
|
||||
if row_dict.get('latest_date'):
|
||||
row_dict['latest_date'] = str(row_dict['latest_date'])
|
||||
if row_dict.get('latest_time'):
|
||||
row_dict['latest_time'] = str(row_dict['latest_time'])
|
||||
results.append(row_dict)
|
||||
cursor.close()
|
||||
|
||||
return results if results else []
|
||||
@@ -569,7 +587,7 @@ def search_by_box_number(box_number_search):
|
||||
s.created_at
|
||||
FROM scanfg_orders s
|
||||
LEFT JOIN boxes_crates bc ON s.box_id = bc.id
|
||||
LEFT JOIN warehouse_locations wl ON s.location_id = wl.id
|
||||
LEFT JOIN warehouse_locations wl ON bc.location_id = wl.id
|
||||
WHERE bc.box_number LIKE %s
|
||||
ORDER BY s.created_at DESC
|
||||
LIMIT 500
|
||||
@@ -577,7 +595,17 @@ def search_by_box_number(box_number_search):
|
||||
|
||||
# Convert tuples to dicts using cursor description
|
||||
columns = [col[0] for col in cursor.description]
|
||||
results = [{columns[i]: row[i] for i in range(len(columns))} for row in cursor.fetchall()]
|
||||
results = []
|
||||
for row in cursor.fetchall():
|
||||
row_dict = {columns[i]: row[i] for i in range(len(columns))}
|
||||
# Convert time and date fields to strings to avoid JSON serialization issues
|
||||
if row_dict.get('date'):
|
||||
row_dict['date'] = str(row_dict['date'])
|
||||
if row_dict.get('time'):
|
||||
row_dict['time'] = str(row_dict['time'])
|
||||
if row_dict.get('created_at'):
|
||||
row_dict['created_at'] = str(row_dict['created_at'])
|
||||
results.append(row_dict)
|
||||
cursor.close()
|
||||
|
||||
return results if results else []
|
||||
@@ -602,6 +630,7 @@ def get_cp_details(cp_code):
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Search for all entries with this CP base
|
||||
# NOTE: Use box's CURRENT location (from boxes_crates), not the historical scan location
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
s.id,
|
||||
@@ -622,7 +651,7 @@ def get_cp_details(cp_code):
|
||||
s.created_at
|
||||
FROM scanfg_orders s
|
||||
LEFT JOIN boxes_crates bc ON s.box_id = bc.id
|
||||
LEFT JOIN warehouse_locations wl ON s.location_id = wl.id
|
||||
LEFT JOIN warehouse_locations wl ON bc.location_id = wl.id
|
||||
WHERE SUBSTRING(s.CP_full_code, 1, 10) = %s
|
||||
ORDER BY s.created_at DESC
|
||||
LIMIT 1000
|
||||
@@ -630,7 +659,17 @@ def get_cp_details(cp_code):
|
||||
|
||||
# Convert tuples to dicts using cursor description
|
||||
columns = [col[0] for col in cursor.description]
|
||||
results = [{columns[i]: row[i] for i in range(len(columns))} for row in cursor.fetchall()]
|
||||
results = []
|
||||
for row in cursor.fetchall():
|
||||
row_dict = {columns[i]: row[i] for i in range(len(columns))}
|
||||
# Convert time and date fields to strings to avoid JSON serialization issues
|
||||
if row_dict.get('date'):
|
||||
row_dict['date'] = str(row_dict['date'])
|
||||
if row_dict.get('time'):
|
||||
row_dict['time'] = str(row_dict['time'])
|
||||
if row_dict.get('created_at'):
|
||||
row_dict['created_at'] = str(row_dict['created_at'])
|
||||
results.append(row_dict)
|
||||
cursor.close()
|
||||
|
||||
return results if results else []
|
||||
|
||||
Reference in New Issue
Block a user