Implement boxes management module with auto-numbered box creation
- Add boxes_crates database table with BIGINT IDs and 8-digit auto-numbered box_numbers - Implement boxes CRUD operations (add, edit, update, delete, delete_multiple) - Create boxes route handlers with POST actions for all operations - Add boxes.html template with 3-panel layout matching warehouse locations module - Implement barcode generation and printing with JsBarcode and QZ Tray integration - Add browser print fallback for when QZ Tray is not available - Simplify create box form to single button with auto-generation - Fix JavaScript null reference errors with proper element validation - Convert tuple data to dictionaries for Jinja2 template compatibility - Register boxes blueprint in Flask app initialization
This commit is contained in:
213
app/modules/warehouse/warehouse.py
Normal file
213
app/modules/warehouse/warehouse.py
Normal file
@@ -0,0 +1,213 @@
|
||||
"""
|
||||
Warehouse Module - Helper Functions
|
||||
Provides functions for warehouse operations
|
||||
"""
|
||||
import logging
|
||||
from app.database import get_db
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def ensure_warehouse_locations_table():
|
||||
"""Ensure warehouse_locations table exists"""
|
||||
try:
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS warehouse_locations (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
location_code VARCHAR(12) UNIQUE NOT NULL,
|
||||
size INT,
|
||||
description VARCHAR(250),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_location_code (location_code)
|
||||
)
|
||||
""")
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
logger.info("warehouse_locations table ensured")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Error ensuring warehouse_locations table: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def add_location(location_code, size, description):
|
||||
"""Add a new warehouse location"""
|
||||
try:
|
||||
ensure_warehouse_locations_table()
|
||||
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO warehouse_locations (location_code, size, description)
|
||||
VALUES (%s, %s, %s)
|
||||
""", (location_code, size if size else None, description))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
|
||||
return True, "Location added successfully."
|
||||
except Exception as e:
|
||||
if "Duplicate entry" in str(e):
|
||||
return False, f"Failed: Location code '{location_code}' already exists."
|
||||
logger.error(f"Error adding location: {e}")
|
||||
return False, f"Error adding location: {str(e)}"
|
||||
|
||||
|
||||
def get_all_locations():
|
||||
"""Get all warehouse locations"""
|
||||
try:
|
||||
ensure_warehouse_locations_table()
|
||||
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id, location_code, size, description, created_at, updated_at
|
||||
FROM warehouse_locations
|
||||
ORDER BY id DESC
|
||||
""")
|
||||
|
||||
locations = cursor.fetchall()
|
||||
cursor.close()
|
||||
|
||||
result = []
|
||||
for loc in locations:
|
||||
result.append({
|
||||
'id': loc[0],
|
||||
'location_code': loc[1],
|
||||
'size': loc[2],
|
||||
'description': loc[3],
|
||||
'created_at': loc[4],
|
||||
'updated_at': loc[5]
|
||||
})
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting locations: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def get_location_by_id(location_id):
|
||||
"""Get a specific location by ID"""
|
||||
try:
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id, location_code, size, description, created_at, updated_at
|
||||
FROM warehouse_locations
|
||||
WHERE id = %s
|
||||
""", (location_id,))
|
||||
|
||||
loc = cursor.fetchone()
|
||||
cursor.close()
|
||||
|
||||
if loc:
|
||||
return {
|
||||
'id': loc[0],
|
||||
'location_code': loc[1],
|
||||
'size': loc[2],
|
||||
'description': loc[3],
|
||||
'created_at': loc[4],
|
||||
'updated_at': loc[5]
|
||||
}
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting location: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def update_location(location_id, location_code=None, size=None, description=None):
|
||||
"""Update a warehouse location
|
||||
|
||||
Args:
|
||||
location_id: ID of location to update
|
||||
location_code: New location code (optional - cannot be changed in form)
|
||||
size: New size (optional)
|
||||
description: New description (optional)
|
||||
"""
|
||||
try:
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Build update query dynamically
|
||||
updates = []
|
||||
params = []
|
||||
|
||||
if location_code:
|
||||
updates.append("location_code = %s")
|
||||
params.append(location_code)
|
||||
if size is not None:
|
||||
updates.append("size = %s")
|
||||
params.append(size)
|
||||
if description is not None:
|
||||
updates.append("description = %s")
|
||||
params.append(description)
|
||||
|
||||
if not updates:
|
||||
return False, "No fields to update"
|
||||
|
||||
params.append(location_id)
|
||||
|
||||
query = f"UPDATE warehouse_locations SET {', '.join(updates)} WHERE id = %s"
|
||||
cursor.execute(query, params)
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
|
||||
return True, "Location updated successfully."
|
||||
except Exception as e:
|
||||
if "Duplicate entry" in str(e):
|
||||
return False, f"Failed: Location code already exists."
|
||||
logger.error(f"Error updating location: {e}")
|
||||
return False, f"Error updating location: {str(e)}"
|
||||
|
||||
|
||||
def delete_location(location_id):
|
||||
"""Delete a warehouse location"""
|
||||
try:
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("DELETE FROM warehouse_locations WHERE id = %s", (location_id,))
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
|
||||
return True, "Location deleted successfully."
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting location: {e}")
|
||||
return False, f"Error deleting location: {str(e)}"
|
||||
|
||||
|
||||
def delete_multiple_locations(location_ids):
|
||||
"""Delete multiple warehouse locations"""
|
||||
try:
|
||||
if not location_ids:
|
||||
return False, "No locations to delete."
|
||||
|
||||
conn = get_db()
|
||||
cursor = conn.cursor()
|
||||
|
||||
deleted_count = 0
|
||||
for loc_id in location_ids:
|
||||
try:
|
||||
cursor.execute("DELETE FROM warehouse_locations WHERE id = %s", (int(loc_id),))
|
||||
if cursor.rowcount > 0:
|
||||
deleted_count += 1
|
||||
except:
|
||||
pass
|
||||
|
||||
conn.commit()
|
||||
cursor.close()
|
||||
|
||||
return True, f"Deleted {deleted_count} location(s)."
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting multiple locations: {e}")
|
||||
return False, f"Error deleting locations: {str(e)}"
|
||||
Reference in New Issue
Block a user