Major updates: Setup environment, database, permissions and admin access
- Created virtual environment and installed requirements - Set up MariaDB database with user 'sa' and database 'recticel' - Created order_for_labels table for printing functionality - Implemented role-based permissions system with admin role - Added admin access to print label modules and etichete functionality - Fixed template routing issues in main_page_etichete.html - Updated app to run on port 8781 with network access (0.0.0.0) - Added systemd service file for background deployment - Created installation documentation
This commit is contained in:
BIN
py_app/app/__pycache__/__init__.cpython-311.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/__init__.cpython-311.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/models.cpython-311.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/models.cpython-311.pyc
Executable file → Normal file
Binary file not shown.
BIN
py_app/app/__pycache__/routes.cpython-311.pyc
Executable file → Normal file
BIN
py_app/app/__pycache__/routes.cpython-311.pyc
Executable file → Normal file
Binary file not shown.
@@ -2,10 +2,10 @@ import mariadb
|
||||
|
||||
# Database connection credentials
|
||||
DB_CONFIG = {
|
||||
"user": "trasabilitate",
|
||||
"password": "Initial01!",
|
||||
"user": "sa",
|
||||
"password": "12345678",
|
||||
"host": "localhost",
|
||||
"database": "trasabilitate_database"
|
||||
"database": "recticel"
|
||||
}
|
||||
|
||||
def recreate_order_for_labels_table():
|
||||
|
||||
@@ -27,84 +27,8 @@ from .print_module import get_unprinted_orders_data
|
||||
bp = Blueprint('main', __name__)
|
||||
warehouse_bp = Blueprint('warehouse', __name__)
|
||||
|
||||
def format_cell_data(cell):
|
||||
"""Helper function to format cell data, especially dates and times"""
|
||||
# Import date and datetime at the top of the function
|
||||
from datetime import datetime, date
|
||||
|
||||
if isinstance(cell, datetime):
|
||||
# Format datetime as dd/mm/yyyy
|
||||
return cell.strftime('%d/%m/%Y')
|
||||
elif isinstance(cell, date):
|
||||
# Format date as dd/mm/yyyy
|
||||
return cell.strftime('%d/%m/%Y')
|
||||
elif isinstance(cell, timedelta):
|
||||
# Convert timedelta to HH:MM:SS format
|
||||
total_seconds = int(cell.total_seconds())
|
||||
hours, remainder = divmod(total_seconds, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
elif isinstance(cell, str):
|
||||
# Handle string dates in yyyy-mm-dd or yyyy-mm-dd HH:MM:SS
|
||||
import re
|
||||
match = re.match(r'^(\d{4})-(\d{2})-(\d{2})(.*)$', cell)
|
||||
if match:
|
||||
year, month, day, rest = match.groups()
|
||||
formatted = f"{day}/{month}/{year}"
|
||||
if rest.strip():
|
||||
# If there is a time part, keep it after the date
|
||||
formatted += rest
|
||||
return formatted
|
||||
return cell
|
||||
else:
|
||||
return cell
|
||||
|
||||
@bp.route('/store_articles')
|
||||
def store_articles():
|
||||
return render_template('store_articles.html')
|
||||
|
||||
@bp.route('/get_pairing_keys')
|
||||
def get_pairing_keys():
|
||||
"""Return all pairing keys as JSON for client selection."""
|
||||
keys_path = os.path.join(current_app.instance_path, 'pairing_keys.json')
|
||||
try:
|
||||
if os.path.exists(keys_path):
|
||||
with open(keys_path, 'r') as f:
|
||||
keys = json.load(f)
|
||||
else:
|
||||
keys = []
|
||||
except Exception as e:
|
||||
print(f"Error loading pairing keys: {e}")
|
||||
return jsonify([]), 200
|
||||
return jsonify(keys)
|
||||
|
||||
@bp.route('/warehouse_reports')
|
||||
def warehouse_reports():
|
||||
return render_template('warehouse_reports.html')
|
||||
|
||||
def get_db_connection():
|
||||
"""Reads the external_server.conf file and returns a MariaDB database connection."""
|
||||
settings_file = os.path.join(current_app.instance_path, 'external_server.conf')
|
||||
if not os.path.exists(settings_file):
|
||||
raise FileNotFoundError("The external_server.conf file is missing in the instance folder.")
|
||||
|
||||
# Read settings from the configuration file
|
||||
settings = {}
|
||||
with open(settings_file, 'r') as f:
|
||||
for line in f:
|
||||
key, value = line.strip().split('=', 1)
|
||||
settings[key] = value
|
||||
|
||||
# Create a database connection
|
||||
return mariadb.connect(
|
||||
user=settings['username'],
|
||||
password=settings['password'],
|
||||
host=settings['server_domain'],
|
||||
port=int(settings['port']),
|
||||
database=settings['database_name']
|
||||
)
|
||||
|
||||
@bp.route('/login', methods=['GET', 'POST'])
|
||||
@bp.route('/', methods=['GET', 'POST'])
|
||||
def login():
|
||||
import sqlite3
|
||||
if request.method == 'POST':
|
||||
@@ -190,6 +114,83 @@ def login():
|
||||
flash('Invalid credentials. Please try again.')
|
||||
return render_template('login.html')
|
||||
|
||||
def format_cell_data(cell):
|
||||
"""Helper function to format cell data, especially dates and times"""
|
||||
# Import date and datetime at the top of the function
|
||||
from datetime import datetime, date
|
||||
|
||||
if isinstance(cell, datetime):
|
||||
# Format datetime as dd/mm/yyyy
|
||||
return cell.strftime('%d/%m/%Y')
|
||||
elif isinstance(cell, date):
|
||||
# Format date as dd/mm/yyyy
|
||||
return cell.strftime('%d/%m/%Y')
|
||||
elif isinstance(cell, timedelta):
|
||||
# Convert timedelta to HH:MM:SS format
|
||||
total_seconds = int(cell.total_seconds())
|
||||
hours, remainder = divmod(total_seconds, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||
elif isinstance(cell, str):
|
||||
# Handle string dates in yyyy-mm-dd or yyyy-mm-dd HH:MM:SS
|
||||
import re
|
||||
match = re.match(r'^(\d{4})-(\d{2})-(\d{2})(.*)$', cell)
|
||||
if match:
|
||||
year, month, day, rest = match.groups()
|
||||
formatted = f"{day}/{month}/{year}"
|
||||
if rest.strip():
|
||||
# If there is a time part, keep it after the date
|
||||
formatted += rest
|
||||
return formatted
|
||||
return cell
|
||||
else:
|
||||
return cell
|
||||
|
||||
@bp.route('/store_articles')
|
||||
def store_articles():
|
||||
return render_template('store_articles.html')
|
||||
|
||||
@bp.route('/get_pairing_keys')
|
||||
def get_pairing_keys():
|
||||
"""Return all pairing keys as JSON for client selection."""
|
||||
keys_path = os.path.join(current_app.instance_path, 'pairing_keys.json')
|
||||
try:
|
||||
if os.path.exists(keys_path):
|
||||
with open(keys_path, 'r') as f:
|
||||
keys = json.load(f)
|
||||
else:
|
||||
keys = []
|
||||
except Exception as e:
|
||||
print(f"Error loading pairing keys: {e}")
|
||||
return jsonify([]), 200
|
||||
return jsonify(keys)
|
||||
|
||||
@bp.route('/warehouse_reports')
|
||||
def warehouse_reports():
|
||||
return render_template('warehouse_reports.html')
|
||||
|
||||
def get_db_connection():
|
||||
"""Reads the external_server.conf file and returns a MariaDB database connection."""
|
||||
settings_file = os.path.join(current_app.instance_path, 'external_server.conf')
|
||||
if not os.path.exists(settings_file):
|
||||
raise FileNotFoundError("The external_server.conf file is missing in the instance folder.")
|
||||
|
||||
# Read settings from the configuration file
|
||||
settings = {}
|
||||
with open(settings_file, 'r') as f:
|
||||
for line in f:
|
||||
key, value = line.strip().split('=', 1)
|
||||
settings[key] = value
|
||||
|
||||
# Create a database connection
|
||||
return mariadb.connect(
|
||||
user=settings['username'],
|
||||
password=settings['password'],
|
||||
host=settings['server_domain'],
|
||||
port=int(settings['port']),
|
||||
database=settings['database_name']
|
||||
)
|
||||
|
||||
@bp.route('/dashboard')
|
||||
def dashboard():
|
||||
print("Session user:", session.get('user'), session.get('role'))
|
||||
@@ -203,21 +204,21 @@ def settings():
|
||||
|
||||
@bp.route('/quality')
|
||||
def quality():
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'quality']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'administrator', 'quality']:
|
||||
flash('Access denied: Quality users only.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return render_template('quality.html')
|
||||
|
||||
@bp.route('/warehouse')
|
||||
def warehouse():
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'administrator', 'admin', 'warehouse']:
|
||||
flash('Access denied: Warehouse users only.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return render_template('main_page_warehouse.html')
|
||||
|
||||
@bp.route('/scan', methods=['GET', 'POST'])
|
||||
def scan():
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'scan']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'administrator', 'admin', 'scan']:
|
||||
flash('Access denied: Scan users only.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
@@ -952,14 +953,14 @@ def test_database():
|
||||
|
||||
@bp.route('/etichete')
|
||||
def etichete():
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'etichete']:
|
||||
flash('Access denied: Etichete users only.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
return render_template('main_page_etichete.html')
|
||||
|
||||
@bp.route('/upload_data')
|
||||
def upload_data():
|
||||
return render_template('upload_data.html')
|
||||
return render_template('upload_orders.html')
|
||||
|
||||
@bp.route('/print_module')
|
||||
def print_module():
|
||||
@@ -1817,7 +1818,7 @@ def create_template():
|
||||
@bp.route('/get_database_tables', methods=['GET'])
|
||||
def get_database_tables():
|
||||
"""Get list of database tables for template creation"""
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
return jsonify({'error': 'Access denied'}), 403
|
||||
|
||||
try:
|
||||
@@ -1867,7 +1868,7 @@ def get_database_tables():
|
||||
@bp.route('/get_table_columns/<table_name>', methods=['GET'])
|
||||
def get_table_columns(table_name):
|
||||
"""Get column names and descriptions for a specific table"""
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
return jsonify({'error': 'Access denied'}), 403
|
||||
|
||||
try:
|
||||
@@ -2002,41 +2003,7 @@ def generate_pdf():
|
||||
return jsonify({'message': 'PDF generated successfully!', 'pdf_path': f'/static/label_templates/label_template.pdf'})
|
||||
|
||||
# Order Labels Upload Module Routes
|
||||
@bp.route('/upload_orders', methods=['GET', 'POST'])
|
||||
def upload_orders():
|
||||
"""Route for uploading orders CSV files for label generation"""
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse', 'warehouse_manager']:
|
||||
flash('Access denied: Warehouse management permissions required.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
from app.order_labels import upload_orders_handler
|
||||
return upload_orders_handler()
|
||||
|
||||
@bp.route('/view_orders')
|
||||
def view_orders():
|
||||
"""Route for viewing uploaded orders"""
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse', 'warehouse_manager', 'warehouse_worker']:
|
||||
flash('Access denied: Warehouse access required.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
from app.order_labels import get_orders_from_database
|
||||
orders = get_orders_from_database(200) # Get last 200 orders
|
||||
return render_template('view_orders.html', orders=orders)
|
||||
|
||||
@bp.route('/print_lost_labels')
|
||||
def print_lost_labels():
|
||||
"""Route for printing lost labels - allows searching and reprinting specific orders"""
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse', 'warehouse_manager', 'warehouse_worker']:
|
||||
flash('Access denied: Warehouse access required.')
|
||||
return redirect(url_for('main.dashboard'))
|
||||
|
||||
from app.order_labels import get_orders_from_database
|
||||
orders = get_orders_from_database(500) # Get more orders for searching
|
||||
return render_template('print_lost_labels.html', orders=orders)
|
||||
|
||||
@bp.route('/db_test')
|
||||
def db_test():
|
||||
"""Simple database test page"""
|
||||
# ...existing code...
|
||||
return render_template('db_test.html')
|
||||
|
||||
@bp.route('/get_unprinted_orders', methods=['GET'])
|
||||
@@ -2067,9 +2034,9 @@ def generate_labels_pdf(order_id, paper_saving_mode='true'):
|
||||
"""Generate PDF labels for a specific order"""
|
||||
print(f"DEBUG: generate_labels_pdf called for order_id: {order_id}")
|
||||
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
print(f"DEBUG: Access denied for role: {session.get('role')}")
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, warehouse_manager, etichete'}), 403
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, admin, administrator, warehouse_manager, etichete'}), 403
|
||||
|
||||
try:
|
||||
from .pdf_generator import generate_order_labels_pdf, update_order_printed_status
|
||||
@@ -2148,8 +2115,8 @@ def generate_labels_pdf(order_id, paper_saving_mode='true'):
|
||||
def generate_label_pdf():
|
||||
"""Generate a single label PDF for thermal printing via QZ Tray"""
|
||||
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, warehouse_manager, etichete'}), 403
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, admin, administrator, warehouse_manager, etichete'}), 403
|
||||
|
||||
try:
|
||||
from .pdf_generator import LabelPDFGenerator
|
||||
@@ -2197,9 +2164,9 @@ def update_printed_status(order_id):
|
||||
"""Update printed status for direct printing (without PDF generation)"""
|
||||
print(f"DEBUG: update_printed_status called for order_id: {order_id}")
|
||||
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
print(f"DEBUG: Access denied for role: {session.get('role')}")
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, warehouse_manager, etichete'}), 403
|
||||
return jsonify({'error': 'Access denied. Required roles: superadmin, admin, administrator, warehouse_manager, etichete'}), 403
|
||||
|
||||
try:
|
||||
from .pdf_generator import update_order_printed_status
|
||||
@@ -2312,7 +2279,7 @@ def get_order_data(order_id):
|
||||
"""Get specific order data for preview"""
|
||||
print(f"DEBUG: get_order_data called for order_id: {order_id}")
|
||||
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'warehouse_manager', 'etichete']:
|
||||
if 'role' not in session or session['role'] not in ['superadmin', 'admin', 'administrator', 'warehouse_manager', 'etichete']:
|
||||
return jsonify({'error': 'Access denied'}), 403
|
||||
|
||||
try:
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<h3>View Orders</h3>
|
||||
<p>Upload new orders or view existing orders and manage label data for printing.</p>
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<a href="{{ url_for('main.upload_orders') }}" class="btn">Upload Orders</a>
|
||||
<a href="{{ url_for('main.view_orders') }}" class="btn">View Orders</a>
|
||||
<a href="{{ url_for('main.upload_data') }}" class="btn">Upload Orders</a>
|
||||
<a href="{{ url_for('main.get_unprinted_orders') }}" class="btn">View Orders</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<p>Access the print module to print labels.</p>
|
||||
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
|
||||
<a href="{{ url_for('main.print_module') }}" class="btn">Launch Printing Module</a>
|
||||
<a href="{{ url_for('main.print_lost_labels') }}" class="btn">Launch lost labels printing module</a>
|
||||
<a href="{{ url_for('main.print_module') }}" class="btn">Launch lost labels printing module</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server_domain=localhost
|
||||
port=3602
|
||||
database_name=trasabilitate_database
|
||||
username=trasabilitate
|
||||
password=Initial01!
|
||||
database_name=recticel
|
||||
username=sa
|
||||
password=12345678
|
||||
|
||||
@@ -3,4 +3,4 @@ from app import create_app
|
||||
app = create_app()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
app.run(debug=True, port=8781, host='0.0.0.0')
|
||||
|
||||
Reference in New Issue
Block a user