Compare commits
6 Commits
9b5f3b23fb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 46a42c99c2 | |||
| c0528a2488 | |||
| 156c753d6a | |||
| 72fb73cb5f | |||
| 6c55c1701c | |||
| c5853ba688 |
287
web/app.py
287
web/app.py
@@ -1,13 +1,12 @@
|
|||||||
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
from flask import Flask, render_template, request, redirect, url_for, flash, session, jsonify
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from werkzeug.security import check_password_hash, generate_password_hash
|
from db import get_db_connection, fetch_users, fetch_orders, fetch_roles, fetch_repairs, fetch_employees, fetch_products, update_product, add_product_stock
|
||||||
from db import get_db_connection, fetch_users, fetch_orders, fetch_roles, fetch_repairs, fetch_employees
|
|
||||||
from auth import encrypt_password, check_password
|
from auth import encrypt_password, check_password
|
||||||
import random
|
import sqlite3
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = 'aezakmi'
|
app.secret_key = 'e462a50b0401f495cfb5c67c3871fe4b'
|
||||||
|
|
||||||
# ----------------- Logging part not related to project requirements -----------------
|
# ----------------- Logging part not related to project requirements -----------------
|
||||||
# Set up custom logging
|
# Set up custom logging
|
||||||
@@ -20,14 +19,20 @@ werkzeug_logger.setLevel(logging.ERROR)
|
|||||||
# Log client IP before each request
|
# Log client IP before each request
|
||||||
@app.before_request
|
@app.before_request
|
||||||
def log_client_ip():
|
def log_client_ip():
|
||||||
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
|
if request.remote_addr == '127.0.0.1':
|
||||||
|
client_ip = request.headers.get('CF-Connecting-IP', request.headers.get('X-Forwarded-For', request.remote_addr))
|
||||||
|
else:
|
||||||
|
client_ip = request.remote_addr
|
||||||
client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request
|
client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request
|
||||||
request.client_ip = client_ip # Store the client IP in the request context
|
request.client_ip = client_ip # Store the client IP in the request context
|
||||||
|
|
||||||
# Override werkzeug's default logging to show client IP in the access log
|
# Override werkzeug's default logging to show client IP in the access log
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def log_request(response):
|
def log_request(response):
|
||||||
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
|
if request.remote_addr == '127.0.0.1':
|
||||||
|
client_ip = request.headers.get('CF-Connecting-IP', request.headers.get('X-Forwarded-For', request.remote_addr))
|
||||||
|
else:
|
||||||
|
client_ip = request.remote_addr
|
||||||
client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request
|
client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request
|
||||||
app.logger.info(f"{client_ip} - - [{request.date}] \"{request.method} {request.full_path} {request.environ.get('SERVER_PROTOCOL')}\" {response.status_code}")
|
app.logger.info(f"{client_ip} - - [{request.date}] \"{request.method} {request.full_path} {request.environ.get('SERVER_PROTOCOL')}\" {response.status_code}")
|
||||||
return response
|
return response
|
||||||
@@ -39,6 +44,7 @@ def logout():
|
|||||||
session.pop('logged_in', None)
|
session.pop('logged_in', None)
|
||||||
session.pop('role_id', None)
|
session.pop('role_id', None)
|
||||||
session.pop('username', None)
|
session.pop('username', None)
|
||||||
|
session.pop('user_id', None)
|
||||||
return '''
|
return '''
|
||||||
<script>
|
<script>
|
||||||
alert('Úspěšně odhlášen.');
|
alert('Úspěšně odhlášen.');
|
||||||
@@ -52,6 +58,10 @@ def login():
|
|||||||
flash('Již jste přihlášen.', 'info')
|
flash('Již jste přihlášen.', 'info')
|
||||||
if session.get('role_id') == 1:
|
if session.get('role_id') == 1:
|
||||||
return redirect(url_for('administrator'))
|
return redirect(url_for('administrator'))
|
||||||
|
elif session.get('role_id') == 2:
|
||||||
|
return redirect(url_for('managers'))
|
||||||
|
elif session.get('role_id') == 3:
|
||||||
|
return redirect(url_for('repairs'))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('home'))
|
return redirect(url_for('home'))
|
||||||
|
|
||||||
@@ -64,14 +74,24 @@ def login():
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if user is None or not check_password(user['heslo'], password):
|
if user is None or not check_password(user['heslo'], password):
|
||||||
flash('Nesprávné uživatelské jméno nebo heslo.', 'error')
|
return '''
|
||||||
|
<script>
|
||||||
|
alert('Nesprávné uživatelské jméno nebo heslo.');
|
||||||
|
window.location.href = '/login';
|
||||||
|
</script>
|
||||||
|
'''
|
||||||
else:
|
else:
|
||||||
session['logged_in'] = True
|
session['logged_in'] = True
|
||||||
session['role_id'] = user['Role_ID']
|
session['role_id'] = user['Role_ID']
|
||||||
session['username'] = user['Username'] # Store username in session
|
session['username'] = user['Username']
|
||||||
|
session['user_id'] = user['ID_Uzivatele']
|
||||||
flash('Úspěšně přihlášen.', 'success')
|
flash('Úspěšně přihlášen.', 'success')
|
||||||
if user['Role_ID'] == 1:
|
if user['Role_ID'] == 1:
|
||||||
return redirect(url_for('administrator'))
|
return redirect(url_for('administrator'))
|
||||||
|
elif user['Role_ID'] == 2:
|
||||||
|
return redirect(url_for('managers'))
|
||||||
|
elif user['Role_ID'] == 3:
|
||||||
|
return redirect(url_for('repairs'))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('home'))
|
return redirect(url_for('home'))
|
||||||
|
|
||||||
@@ -95,11 +115,22 @@ def administrator():
|
|||||||
users = fetch_users(session.get('role_id'))
|
users = fetch_users(session.get('role_id'))
|
||||||
orders = fetch_orders()
|
orders = fetch_orders()
|
||||||
roles = fetch_roles()
|
roles = fetch_roles()
|
||||||
return render_template('administrator.html', users=users, orders=orders, roles=roles)
|
products = fetch_products()
|
||||||
|
return render_template('administrator.html', users=users, orders=orders, roles=roles, products=products)
|
||||||
|
|
||||||
|
@app.route('/managers')
|
||||||
|
def managers():
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
users = fetch_users(session.get('role_id'))
|
||||||
|
orders = fetch_orders()
|
||||||
|
roles = fetch_roles()
|
||||||
|
return render_template('managers.html', users=users, orders=orders, roles=roles)
|
||||||
|
|
||||||
@app.route('/create_user', methods=['GET', 'POST'])
|
@app.route('/create_user', methods=['GET', 'POST'])
|
||||||
def create_user():
|
def create_user():
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@@ -128,11 +159,12 @@ def create_user():
|
|||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return render_template('create_user.html')
|
roles = fetch_roles()
|
||||||
|
return render_template('create_user.html', roles=roles)
|
||||||
|
|
||||||
@app.route('/edit_user/<int:user_id>', methods=['GET', 'POST'])
|
@app.route('/edit_user/<int:user_id>', methods=['GET', 'POST'])
|
||||||
def edit_user(user_id):
|
def edit_user(user_id):
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@@ -166,7 +198,7 @@ def edit_user(user_id):
|
|||||||
|
|
||||||
@app.route('/delete_user/<int:user_id>', methods=['POST'])
|
@app.route('/delete_user/<int:user_id>', methods=['POST'])
|
||||||
def delete_user(user_id):
|
def delete_user(user_id):
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@@ -185,12 +217,13 @@ def delete_user(user_id):
|
|||||||
|
|
||||||
@app.route('/edit_order/<int:order_id>', methods=['GET', 'POST'])
|
@app.route('/edit_order/<int:order_id>', methods=['GET', 'POST'])
|
||||||
def edit_order(order_id):
|
def edit_order(order_id):
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2, 3]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
order = conn.execute('SELECT * FROM Objednavky WHERE ID_Objednavky = ?', (order_id,)).fetchone()
|
order = conn.execute('SELECT * FROM Objednavky WHERE ID_Objednavky = ?', (order_id,)).fetchone()
|
||||||
|
users = fetch_users(session.get('role_id'))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
stav = request.form['stav']
|
stav = request.form['stav']
|
||||||
@@ -208,19 +241,35 @@ def edit_order(order_id):
|
|||||||
return redirect(url_for('administrator'))
|
return redirect(url_for('administrator'))
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return render_template('edit_order.html', order=order)
|
return render_template('edit_order.html', order=order, users=users)
|
||||||
|
|
||||||
|
@app.route('/delete_order/<int:order_id>', methods=['POST'])
|
||||||
|
def delete_order(order_id):
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2, 3]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
conn.execute('DELETE FROM Objednavky WHERE ID_Objednavky = ?', (order_id,))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
flash('Objednávka byla úspěšně smazána.')
|
||||||
|
return redirect(url_for('administrator'))
|
||||||
|
|
||||||
@app.route('/repairs')
|
@app.route('/repairs')
|
||||||
def repairs():
|
def repairs():
|
||||||
if not session.get('logged_in'):
|
if not session.get('logged_in') or session.get('role_id') not in [1, 3]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
repairs = fetch_repairs()
|
repairs = fetch_repairs()
|
||||||
return render_template('repairs.html', repairs=repairs)
|
orders = fetch_orders()
|
||||||
|
users = fetch_users(session.get('role_id'))
|
||||||
|
return render_template('repairs.html', repairs=repairs, orders=orders, users=users)
|
||||||
|
|
||||||
@app.route('/create_repair', methods=['GET', 'POST'])
|
@app.route('/create_repair', methods=['GET', 'POST'])
|
||||||
def create_repair():
|
def create_repair():
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') and session.get('role_id') != 1 or session.get('role_id') not in [1, 3]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@@ -228,51 +277,102 @@ def create_repair():
|
|||||||
id_zamestnance = request.form['id_zamestnance']
|
id_zamestnance = request.form['id_zamestnance']
|
||||||
nazev = request.form['nazev']
|
nazev = request.form['nazev']
|
||||||
popis = request.form['popis']
|
popis = request.form['popis']
|
||||||
|
products = [{'id': pid, 'quantity': qty} for pid, qty in zip(request.form.getlist('products[0][id]'), request.form.getlist('products[0][quantity]'))]
|
||||||
|
|
||||||
|
app.logger.debug(f"Received id_zamestnance: {id_zamestnance}")
|
||||||
|
app.logger.debug(f"Received nazev: {nazev}")
|
||||||
|
app.logger.debug(f"Received popis: {popis}")
|
||||||
|
app.logger.debug(f"Received products: {products}")
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
try:
|
try:
|
||||||
conn.execute('INSERT INTO Opravy (ID_Zamestnance, Nazev, Popis) VALUES (?, ?, ?)',
|
conn.execute('BEGIN')
|
||||||
(id_zamestnance, nazev, popis))
|
sql_insert_repair = 'INSERT INTO Opravy (ID_Zamestnance, Nazev, Popis) VALUES (?, ?, ?)'
|
||||||
|
app.logger.debug(f"Executing SQL: {sql_insert_repair} with values ({id_zamestnance}, {nazev}, {popis})")
|
||||||
|
conn.execute(sql_insert_repair, (id_zamestnance, nazev, popis))
|
||||||
|
repair_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
||||||
|
|
||||||
|
debug_info = f"Inserted Repair ID: {repair_id}\n"
|
||||||
|
|
||||||
|
for product in products:
|
||||||
|
product_id = product['id']
|
||||||
|
quantity = product['quantity']
|
||||||
|
app.logger.debug(f"Inserting product {product_id} with quantity {quantity} for repair {repair_id}")
|
||||||
|
if quantity and int(quantity) > 0:
|
||||||
|
conn.execute('INSERT INTO Pouzite_Produkty (ID_Opravy, ID_Produktu, Pocet_Produktu) VALUES (?, ?, ?)',
|
||||||
|
(repair_id, product_id, quantity))
|
||||||
|
debug_info += f"Inserted Product ID: {product_id}, Quantity: {quantity}\n"
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
session['debug'] = debug_info
|
||||||
flash('Nová oprava byla úspěšně vytvořena.', 'success')
|
flash('Nová oprava byla úspěšně vytvořena.', 'success')
|
||||||
return redirect(url_for('repairs'))
|
return redirect(url_for('repairs'))
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
|
conn.rollback()
|
||||||
|
app.logger.error(f"Error creating repair: {e}")
|
||||||
flash(f'Chyba při vytváření opravy: {e}', 'error')
|
flash(f'Chyba při vytváření opravy: {e}', 'error')
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
employees = fetch_employees()
|
employees = fetch_employees()
|
||||||
return render_template('create_repair.html', employees=employees)
|
products = fetch_products()
|
||||||
|
return render_template('create_repair.html', employees=employees, products=products)
|
||||||
|
|
||||||
@app.route('/edit_repair/<int:repair_id>', methods=['GET', 'POST'])
|
@app.route('/edit_repair/<int:repair_id>', methods=['GET', 'POST'])
|
||||||
def edit_repair(repair_id):
|
def edit_repair(repair_id):
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 3]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
repair = conn.execute('SELECT * FROM Opravy WHERE ID_Opravy = ?', (repair_id,)).fetchone()
|
repair = conn.execute('SELECT * FROM Opravy WHERE ID_Opravy = ?', (repair_id,)).fetchone()
|
||||||
|
repair = dict(repair)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
id_zamestnance = request.form['id_zamestnance']
|
id_zamestnance = request.form['id_zamestnance']
|
||||||
nazev = request.form['nazev']
|
nazev = request.form['nazev']
|
||||||
popis = request.form['popis']
|
popis = request.form['popis']
|
||||||
|
products = [{'id': pid, 'quantity': qty} for pid, qty in zip(request.form.getlist('products[][id]'), request.form.getlist('products[][quantity]'))]
|
||||||
|
|
||||||
conn.execute('UPDATE Opravy SET ID_Zamestnance = ?, Nazev = ?, Popis = ? WHERE ID_Opravy = ?',
|
conn.execute('BEGIN')
|
||||||
(id_zamestnance, nazev, popis, repair_id))
|
try:
|
||||||
conn.commit()
|
conn.execute('UPDATE Opravy SET ID_Zamestnance = ?, Nazev = ?, Popis = ? WHERE ID_Opravy = ?',
|
||||||
conn.close()
|
(id_zamestnance, nazev, popis, repair_id))
|
||||||
|
|
||||||
|
conn.execute('DELETE FROM Pouzite_Produkty WHERE ID_Opravy = ?', (repair_id,))
|
||||||
|
|
||||||
|
for product in products:
|
||||||
|
product_id = product['id']
|
||||||
|
quantity = product['quantity']
|
||||||
|
if quantity and int(quantity) > 0:
|
||||||
|
conn.execute('INSERT INTO Pouzite_Produkty (ID_Opravy, ID_Produktu, Pocet_Produktu) VALUES (?, ?, ?)',
|
||||||
|
(repair_id, product_id, quantity))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
flash('Oprava byla úspěšně aktualizována.')
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
conn.rollback()
|
||||||
|
app.logger.error(f"Error updating repair: {e}")
|
||||||
|
flash(f'Chyba při aktualizaci opravy: {e}', 'error')
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
flash('Oprava byla úspěšně aktualizována.')
|
|
||||||
return redirect(url_for('repairs'))
|
return redirect(url_for('repairs'))
|
||||||
|
|
||||||
employees = fetch_employees()
|
employees = fetch_employees()
|
||||||
|
products = fetch_products()
|
||||||
|
repair['products'] = [dict(row) for row in conn.execute('''
|
||||||
|
SELECT Produkty.ID_Produktu, Produkty.Nazev, Pouzite_Produkty.Pocet_Produktu
|
||||||
|
FROM Pouzite_Produkty
|
||||||
|
JOIN Produkty ON Pouzite_Produkty.ID_Produktu = Produkty.ID_Produktu
|
||||||
|
WHERE Pouzite_Produkty.ID_Opravy = ?
|
||||||
|
''', (repair_id,)).fetchall()]
|
||||||
conn.close()
|
conn.close()
|
||||||
return render_template('edit_repair.html', repair=repair, employees=employees)
|
return render_template('edit_repair.html', repair=repair, employees=employees, products=products)
|
||||||
|
|
||||||
@app.route('/delete_repair/<int:repair_id>', methods=['POST'])
|
@app.route('/delete_repair/<int:repair_id>', methods=['POST'])
|
||||||
def delete_repair(repair_id):
|
def delete_repair(repair_id):
|
||||||
if not session.get('logged_in') or session.get('role_id') != 1:
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2, 3]:
|
||||||
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
return redirect(url_for('login'))
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
@@ -288,23 +388,20 @@ def delete_repair(repair_id):
|
|||||||
def create_reservation():
|
def create_reservation():
|
||||||
full_name = request.form['fullName']
|
full_name = request.form['fullName']
|
||||||
email = request.form['email']
|
email = request.form['email']
|
||||||
date = request.form['date']
|
datum_konce = request.form['datum_konce']
|
||||||
description = request.form['description']
|
description = request.form['description']
|
||||||
|
|
||||||
# Convert date to DD.MM.YYYY format
|
|
||||||
formatted_date = datetime.strptime(date, '%Y-%m-%d').strftime('%d.%m.%Y')
|
|
||||||
|
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
try:
|
try:
|
||||||
# Fetch a random user with role_id 2
|
# Fetch a random user with role_id 3
|
||||||
user = conn.execute('SELECT ID_Uzivatele FROM Zamestnanci WHERE Role_ID = 2 ORDER BY RANDOM() LIMIT 1').fetchone()
|
user = conn.execute('SELECT ID_Uzivatele FROM Zamestnanci WHERE Role_ID = 3 ORDER BY RANDOM() LIMIT 1').fetchone()
|
||||||
if user:
|
if user:
|
||||||
user_id = user['ID_Uzivatele']
|
user_id = user['ID_Uzivatele']
|
||||||
else:
|
else:
|
||||||
user_id = 1 # Fallback to a default user ID if no user with role_id 2 is found
|
user_id = 1 # Fallback to a default user ID if no user with role_id 3 is found
|
||||||
|
|
||||||
conn.execute('INSERT INTO Objednavky (Stav, ID_Zamestnance, Popis, ID_Vozidla, Datum_Zacatku, Cena) VALUES (?, ?, ?, ?, ?, ?)',
|
conn.execute('INSERT INTO Objednavky (Stav, ID_Zamestnance, Popis, ID_Vozidla, Datum_Zacatku, Datum_Konce, Cena) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||||
('Nová', user_id, description, 1, formatted_date, 0.0)) # Example values for ID_Vozidla
|
('Nová', user_id, description, 1, datetime.now().strftime('%Y-%m-%d'), datum_konce, 0.0)) # Use the current date for Datum_Zacatku
|
||||||
conn.commit()
|
conn.commit()
|
||||||
flash('Rezervace byla úspěšně vytvořena.', 'success')
|
flash('Rezervace byla úspěšně vytvořena.', 'success')
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
@@ -312,7 +409,117 @@ def create_reservation():
|
|||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return redirect(url_for('home'))
|
return '''
|
||||||
|
<script>
|
||||||
|
alert('Rezervace byla úspěšně vytvořena.');
|
||||||
|
window.location.href = '/';
|
||||||
|
</script>
|
||||||
|
'''
|
||||||
|
|
||||||
|
@app.route('/edit_product/<int:product_id>', methods=['GET', 'POST'])
|
||||||
|
def edit_product(product_id):
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
product = conn.execute('SELECT * FROM Produkty WHERE ID_Produktu = ?', (product_id,)).fetchone()
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
nazev = request.form['nazev']
|
||||||
|
popis = request.form['popis']
|
||||||
|
momentalni_zasoba = request.form['momentalni_zasoba']
|
||||||
|
minimalni_zasoba = request.form['minimalni_zasoba']
|
||||||
|
|
||||||
|
update_product(product_id, nazev, popis, momentalni_zasoba, minimalni_zasoba)
|
||||||
|
|
||||||
|
flash('Produkt byl úspěšně aktualizován.')
|
||||||
|
return redirect(url_for('administrator'))
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return render_template('edit_product.html', product=product)
|
||||||
|
|
||||||
|
@app.route('/add_product_stock/<int:product_id>', methods=['GET', 'POST'])
|
||||||
|
def add_product_stock(product_id):
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
product = conn.execute('SELECT * FROM Produkty WHERE ID_Produktu = ?', (product_id,)).fetchone()
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
quantity = request.form['quantity']
|
||||||
|
|
||||||
|
add_product_stock(product_id, quantity)
|
||||||
|
|
||||||
|
flash('Zásoba byla úspěšně přidána.')
|
||||||
|
return redirect(url_for('administrator'))
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return render_template('add_product_stock.html', product=product)
|
||||||
|
|
||||||
|
@app.route('/create_product', methods=['GET', 'POST'])
|
||||||
|
def create_product():
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
nazev = request.form['nazev']
|
||||||
|
popis = request.form['popis']
|
||||||
|
momentalni_zasoba = request.form['momentalni_zasoba']
|
||||||
|
minimalni_zasoba = request.form['minimalni_zasoba']
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
try:
|
||||||
|
conn.execute('INSERT INTO Produkty (Nazev, Popis, Momentalni_Zasoba, Minimalni_Zasoba) VALUES (?, ?, ?, ?)',
|
||||||
|
(nazev, popis, momentalni_zasoba, minimalni_zasoba))
|
||||||
|
conn.commit()
|
||||||
|
flash('Nový produkt byl úspěšně přidán.', 'success')
|
||||||
|
return redirect(url_for('administrator'))
|
||||||
|
except sqlite3.Error as e:
|
||||||
|
flash(f'Chyba při přidávání produktu: {e}', 'error')
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return render_template('create_product.html')
|
||||||
|
|
||||||
|
@app.route('/statistics')
|
||||||
|
def statistics():
|
||||||
|
if not session.get('logged_in') or session.get('role_id') not in [1, 2]:
|
||||||
|
flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error')
|
||||||
|
return redirect(url_for('login'))
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
repairs_data = conn.execute('''
|
||||||
|
SELECT Zamestnanci.Jmeno || ' ' || Zamestnanci.Prijmeni AS employee, COUNT(Opravy.ID_Opravy) AS count
|
||||||
|
FROM Opravy
|
||||||
|
JOIN Zamestnanci ON Opravy.ID_Zamestnance = Zamestnanci.ID_Uzivatele
|
||||||
|
GROUP BY Zamestnanci.ID_Uzivatele
|
||||||
|
''').fetchall()
|
||||||
|
repairs_data = [dict(employee=row['employee'], count=row['count']) for row in repairs_data]
|
||||||
|
conn.close()
|
||||||
|
return render_template('statistics.html', repairs_data=repairs_data)
|
||||||
|
|
||||||
|
@app.route('/repairs_by_date')
|
||||||
|
def repairs_by_date():
|
||||||
|
start_date = request.args.get('start')
|
||||||
|
end_date = request.args.get('end')
|
||||||
|
|
||||||
|
conn = get_db_connection()
|
||||||
|
repairs_data = conn.execute('''
|
||||||
|
SELECT DATE(Datum_Zacatku) AS date, COUNT(*) AS count
|
||||||
|
FROM Objednavky
|
||||||
|
WHERE Datum_Zacatku BETWEEN ? AND ?
|
||||||
|
GROUP BY DATE(Datum_Zacatku)
|
||||||
|
''', (start_date, end_date)).fetchall()
|
||||||
|
repairs_data = [dict(date=row['date'], count=row['count']) for row in repairs_data]
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return jsonify(repairs_data)
|
||||||
|
|
||||||
# Always redirect back home
|
# Always redirect back home
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
|
|||||||
64
web/db.py
64
web/db.py
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
|
import time
|
||||||
|
|
||||||
def get_db_connection():
|
def get_db_connection():
|
||||||
conn = sqlite3.connect('./static/db/db.sqlite')
|
conn = sqlite3.connect('./static/db/db.sqlite')
|
||||||
@@ -10,6 +10,21 @@ def get_db_connection():
|
|||||||
def dict_from_row(row):
|
def dict_from_row(row):
|
||||||
return {key: row[key] for key in row.keys()}
|
return {key: row[key] for key in row.keys()}
|
||||||
|
|
||||||
|
def execute_with_retry(conn, query, params=(), retries=5, delay=0.1):
|
||||||
|
for attempt in range(retries):
|
||||||
|
try:
|
||||||
|
conn.execute(query, params)
|
||||||
|
conn.commit()
|
||||||
|
return
|
||||||
|
except sqlite3.OperationalError as e:
|
||||||
|
if "database is locked" in str(e):
|
||||||
|
if attempt < retries - 1:
|
||||||
|
time.sleep(delay)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
def fetch_users(role_id):
|
def fetch_users(role_id):
|
||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
users = conn.execute('SELECT * FROM Zamestnanci WHERE Role_ID >= ?', (role_id,)).fetchall()
|
users = conn.execute('SELECT * FROM Zamestnanci WHERE Role_ID >= ?', (role_id,)).fetchall()
|
||||||
@@ -63,3 +78,50 @@ def fetch_employees():
|
|||||||
conn.close()
|
conn.close()
|
||||||
app.logger.debug(f"Fetched employees: {employees}")
|
app.logger.debug(f"Fetched employees: {employees}")
|
||||||
return employees
|
return employees
|
||||||
|
|
||||||
|
def fetch_products():
|
||||||
|
conn = get_db_connection()
|
||||||
|
products = conn.execute('SELECT * FROM Produkty').fetchall()
|
||||||
|
products = [dict_from_row(product) for product in products]
|
||||||
|
conn.close()
|
||||||
|
app.logger.debug(f"Fetched products: {products}")
|
||||||
|
return products
|
||||||
|
|
||||||
|
def update_product(product_id, nazev, popis, momentalni_zasoba, minimalni_zasoba):
|
||||||
|
conn = get_db_connection()
|
||||||
|
execute_with_retry(conn, '''
|
||||||
|
UPDATE Produkty
|
||||||
|
SET Nazev = ?, Popis = ?, Momentalni_Zasoba = ?, Minimalni_Zasoba = ?
|
||||||
|
WHERE ID_Produktu = ?
|
||||||
|
''', (nazev, popis, momentalni_zasoba, minimalni_zasoba, product_id))
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def add_product_stock(product_id, quantity):
|
||||||
|
conn = get_db_connection()
|
||||||
|
execute_with_retry(conn, '''
|
||||||
|
UPDATE Produkty
|
||||||
|
SET Momentalni_Zasoba = Momentalni_Zasoba + ?
|
||||||
|
WHERE ID_Produktu = ?
|
||||||
|
''', (quantity, product_id))
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def create_product(nazev, popis, momentalni_zasoba, minimalni_zasoba):
|
||||||
|
conn = get_db_connection()
|
||||||
|
execute_with_retry(conn, '''
|
||||||
|
INSERT INTO Produkty (Nazev, Popis, Momentalni_Zasoba, Minimalni_Zasoba)
|
||||||
|
VALUES (?, ?, ?, ?)
|
||||||
|
''', (nazev, popis, momentalni_zasoba, minimalni_zasoba))
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def insert_used_products(repair_id, products):
|
||||||
|
conn = get_db_connection()
|
||||||
|
try:
|
||||||
|
for product in products:
|
||||||
|
product_id = product['id']
|
||||||
|
quantity = product['quantity']
|
||||||
|
app.logger.debug(f"Inserting product {product_id} with quantity {quantity} for repair {repair_id}")
|
||||||
|
if quantity and int(quantity) > 0:
|
||||||
|
execute_with_retry(conn, 'INSERT INTO Pouzite_Produkty (ID_Opravy, ID_Produktu, Pocet_Produktu) VALUES (?, ?, ?)',
|
||||||
|
(repair_id, product_id, quantity))
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
@@ -71,17 +71,7 @@ footer {
|
|||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-users-table {
|
.table-header {
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
background-color: #444;
|
|
||||||
padding: 10px;
|
|
||||||
margin-top: 1.5em;
|
|
||||||
border-top-left-radius: 0.5em;
|
|
||||||
border-top-right-radius: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-orders-table {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
@@ -251,20 +241,43 @@ footer {
|
|||||||
|
|
||||||
/* Reviews section */
|
/* Reviews section */
|
||||||
.reviews {
|
.reviews {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #222;
|
||||||
|
border: 1px solid #555;
|
||||||
|
color: white;
|
||||||
|
border-radius: 1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reviews-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.review-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
margin: 20px;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-box {
|
.review-box {
|
||||||
|
flex: 1 1 200px;
|
||||||
|
background-color: #333;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
background-color: #444;
|
display: flex;
|
||||||
border: 1px solid #555;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
margin: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: transform 0.3s, box-shadow 0.3s;
|
}
|
||||||
color: white;
|
|
||||||
|
.review-box:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Text alignment for Directions */
|
/* Text alignment for Directions */
|
||||||
@@ -423,19 +436,29 @@ table tr:hover {
|
|||||||
|
|
||||||
/* Media queries for mobile responsiveness */
|
/* Media queries for mobile responsiveness */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.navbar, .container, .about, .map, .service-info, .photos, .directions, .services, .service-item, .review-box {
|
header, footer, .navbar, .container, .about, .map, .service-info, .photos, .directions, .services, .service-item, .review-box {
|
||||||
|
width: 100%;
|
||||||
border-radius: 0.5em;
|
border-radius: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header, .buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header .contact-info, .header .nazev, .header .buttons {
|
||||||
|
text-align: center;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar a {
|
.navbar button {
|
||||||
padding: 10px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
margin: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -484,6 +507,19 @@ table tr:hover {
|
|||||||
.form-container {
|
.form-container {
|
||||||
width: 90%;
|
width: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th, table td {
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Button link styles */
|
/* Button link styles */
|
||||||
@@ -560,3 +596,121 @@ option {
|
|||||||
color: white;
|
color: white;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Graph container styling */
|
||||||
|
.graph-container {
|
||||||
|
background-color: #222;
|
||||||
|
border: 1px solid #555;
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Canvas styling */
|
||||||
|
canvas {
|
||||||
|
width: 100% !important; /* Make the canvas span the whole container */
|
||||||
|
height: auto;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #333; /* Make the background of the graph darker */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Statistics page styling */
|
||||||
|
.statistics-container {
|
||||||
|
background-color: #222;
|
||||||
|
border: 1px solid #555;
|
||||||
|
border-radius: 1em;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-form label {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-form input {
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0 10px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #555;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-form button {
|
||||||
|
background-color: #808080;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-form button:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.partners {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #222;
|
||||||
|
border: 1px solid #555;
|
||||||
|
color: white;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-list {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-item {
|
||||||
|
flex: 1 1 200px;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: transform 0.3s, box-shadow 0.3s;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-item img {
|
||||||
|
width: 10em;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-item:hover {
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-logos {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.partner-logos img {
|
||||||
|
width: var(--partner-logo-width, 100px);
|
||||||
|
height: var(--partner-logo-height, auto);
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|||||||
Binary file not shown.
BIN
web/static/img/partner1.png
Normal file
BIN
web/static/img/partner1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
BIN
web/static/img/partner2.png
Normal file
BIN
web/static/img/partner2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
BIN
web/static/img/partner3.png
Normal file
BIN
web/static/img/partner3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
BIN
web/static/img/partner4.png
Normal file
BIN
web/static/img/partner4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 180 KiB |
13
web/static/scripts/home.js
Normal file
13
web/static/scripts/home.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
function openReservationForm() {
|
||||||
|
const now = new Date();
|
||||||
|
const minDate = new Date();
|
||||||
|
minDate.setDate(now.getDate() + 3); // Exclude today and the next 2 days
|
||||||
|
const formattedMinDate = minDate.toISOString().split('T')[0];
|
||||||
|
document.getElementById('datum_konce').setAttribute('min', formattedMinDate);
|
||||||
|
document.getElementById('reservationForm').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeReservationForm() {
|
||||||
|
document.getElementById('reservationForm').style.display = 'none';
|
||||||
|
}
|
||||||
29
web/static/scripts/products.js
Normal file
29
web/static/scripts/products.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
let productCount = document.querySelectorAll('.product-item').length;
|
||||||
|
|
||||||
|
function addProduct() {
|
||||||
|
const container = document.getElementById('product-container');
|
||||||
|
const newProduct = document.createElement('div');
|
||||||
|
newProduct.classList.add('product-item');
|
||||||
|
newProduct.id = `product-item-${productCount}`;
|
||||||
|
newProduct.innerHTML = `
|
||||||
|
<label for="product_${productCount}">Produkt:</label>
|
||||||
|
<select id="product_${productCount}" name="products[${productCount}][id]" required>
|
||||||
|
<option value="" disabled selected>Vyberte produkt</option>
|
||||||
|
{% for product in products %}
|
||||||
|
<option value="{{ product['ID_Produktu'] }}">{{ product['Nazev'] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="quantity_${productCount}">Množství:</label>
|
||||||
|
<input type="number" id="quantity_${productCount}" name="products[${productCount}][quantity]" value="0" min="0" required>
|
||||||
|
<button type="button" onclick="removeProduct(${productCount})">Odstranit</button>
|
||||||
|
`;
|
||||||
|
container.appendChild(newProduct);
|
||||||
|
productCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeProduct(index) {
|
||||||
|
const productItem = document.getElementById(`product-item-${index}`);
|
||||||
|
if (productItem) {
|
||||||
|
productItem.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
function openReservationForm() {
|
function openReservationForm() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const formattedDate = now.toLocaleDateString('cs-CZ', { day: '2-digit', month: '2-digit', year: 'numeric' });
|
const formattedDate = now.toISOString().split('T')[0]; // Format date as YYYY-MM-DD
|
||||||
document.getElementById('date').value = formattedDate;
|
document.getElementById('date').value = formattedDate;
|
||||||
document.getElementById('reservationForm').style.display = 'block';
|
document.getElementById('reservationForm').style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|||||||
61
web/static/scripts/statistics.js
Normal file
61
web/static/scripts/statistics.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const ctx = document.getElementById('repairsChart').getContext('2d');
|
||||||
|
const repairsData = JSON.parse(document.getElementById('repairsData').textContent);
|
||||||
|
const labels = repairsData.map(data => data.employee);
|
||||||
|
const data = repairsData.map(data => data.count);
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Počet Oprav',
|
||||||
|
data: data,
|
||||||
|
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||||
|
borderColor: 'rgba(255, 99, 132, 1)',
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function fetchRepairsByDate() {
|
||||||
|
const startDate = document.getElementById('startDate').value;
|
||||||
|
const endDate = document.getElementById('endDate').value;
|
||||||
|
|
||||||
|
fetch(`/repairs_by_date?start=${startDate}&end=${endDate}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const ctx = document.getElementById('timeRepairsChart').getContext('2d');
|
||||||
|
const labels = data.map(item => item.date);
|
||||||
|
const counts = data.map(item => item.count);
|
||||||
|
|
||||||
|
new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Počet Oprav',
|
||||||
|
data: counts,
|
||||||
|
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||||
|
borderColor: 'rgba(54, 162, 235, 1)',
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
47
web/templates/add_product_stock.html
Normal file
47
web/templates/add_product_stock.html
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Přidat Zásobu</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="header">
|
||||||
|
<div class="contact-info">
|
||||||
|
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
|
||||||
|
</div>
|
||||||
|
<h1 class="nazev">
|
||||||
|
<a href="{{ url_for('home') }}" style="text-decoration: none;">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
|
||||||
|
</a>
|
||||||
|
Přidat Zásobu
|
||||||
|
</h1>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{{ url_for('administrator') }}" class="button">Zpět na Tabulku Produktů</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<h2>Přidat Zásobu</h2>
|
||||||
|
<form action="{{ url_for('add_product_stock', product_id=product['ID_Produktu']) }}" method="post" class="form-container">
|
||||||
|
<label for="quantity">Množství:</label>
|
||||||
|
<input type="number" id="quantity" name="quantity" required>
|
||||||
|
|
||||||
|
<button type="submit" class="button">Přidat</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer" id="kontakt">
|
||||||
|
<div>Made by Hrachovina and Kirsch</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Administrativní pracovníci</title>
|
<title>Administrativní pracovníci</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
<script src="{{url_for('static', filename='scripts/user_table.js')}}"></script>
|
<script src="{{url_for('static', filename='scripts/user_table.js')}}"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -23,22 +24,16 @@
|
|||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<a href="{{ url_for('home') }}" class="button">Zpět na Domovskou Stránku</a>
|
<a href="{{ url_for('home') }}" class="button">Zpět na Domovskou Stránku</a>
|
||||||
<a href="{{ url_for('create_user') }}" class="button">Vytvořit Nového Uživatele</a>
|
<a href="{{ url_for('create_user') }}" class="button">Vytvořit Nového Uživatele</a>
|
||||||
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a> <!-- New Log Out button -->
|
<a href="{{ url_for('create_product') }}" class="button">Přidat Nový Produkt</a> <!-- Fixed route -->
|
||||||
|
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{% if not session.get('logged_in') %}
|
|
||||||
<p>Musíte se přihlásit, abyste mohli zobrazit tuto stránku.</p>
|
|
||||||
{% elif session.get('role_id') != 1 %}
|
|
||||||
<p>Nemáte oprávnění zobrazit tuto stránku.</p>
|
|
||||||
{% else %}
|
|
||||||
<div class="user-table">
|
<div class="user-table">
|
||||||
<nav class="navbar-users-table">
|
<nav class="table-header">
|
||||||
<h2 id="users-table">Správa Uživatelů</h2>
|
<h2 id="users-table">Správa Uživatelů</h2>
|
||||||
</nav>
|
</nav>
|
||||||
{% if users %}
|
{% if users %}
|
||||||
@@ -51,7 +46,7 @@
|
|||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Role</th>
|
<th>Role</th>
|
||||||
<th>Username</th>
|
<th>Username</th>
|
||||||
<th>Akce</th> <!-- New column for actions -->
|
<th>Akce</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -76,7 +71,7 @@
|
|||||||
<button type="submit" class="button-link">Delete</button>
|
<button type="submit" class="button-link">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td> <!-- Edit and Delete buttons -->
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -86,20 +81,20 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="order-management">
|
<div class="order-management">
|
||||||
<nav class="navbar-orders-table">
|
<nav class="table-header">
|
||||||
<h2 id="orders-table">Správa objednávek</h2>
|
<h2 id="orders-table">Správa objednávek</h2>
|
||||||
</nav>
|
</nav>
|
||||||
{% if orders %}
|
{% if orders %}
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Číslo objednávky</th>
|
<th>ID</th>
|
||||||
<th>Datum začátku</th>
|
<th>Datum začátku</th>
|
||||||
<th>Datum konce</th>
|
<th>Datum konce</th>
|
||||||
<th>Stav</th>
|
<th>Stav</th>
|
||||||
<th>Přiřazený zaměstnanec</th>
|
<th>Přiřazený zaměstnanec</th>
|
||||||
<th>Popis</th>
|
<th>Popis</th>
|
||||||
<th>Akce</th> <!-- New column for actions -->
|
<th>Akce</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -118,8 +113,11 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>{{ order['Popis'] }}</td>
|
<td>{{ order['Popis'] }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('edit_order', order_id=order['ID_Objednavky']) }}">Edit</a>
|
<a href="{{ url_for('edit_order', order_id=order['ID_Objednavky']) }}">Edit</a> /
|
||||||
</td> <!-- Edit button -->
|
<form action="{{ url_for('delete_order', order_id=order['ID_Objednavky']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tuto objednávku?');">
|
||||||
|
<button type="submit" class="button-link">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -132,10 +130,49 @@
|
|||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
<div class="stock-management">
|
||||||
|
<nav class="table-header">
|
||||||
|
<h2 id="stock-table">Správa produktových zásob</h2>
|
||||||
|
</nav>
|
||||||
|
{% if products %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Název</th>
|
||||||
|
<th>Popis</th>
|
||||||
|
<th>Minimální Zásoba</th>
|
||||||
|
<th>Momentální Zásoba</th>
|
||||||
|
<th>Akce</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for product in products %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ product['ID_Produktu'] }}</td>
|
||||||
|
<td>{{ product['Nazev'] }}</td>
|
||||||
|
<td>{{ product['Popis'] }}</td>
|
||||||
|
<td>{{ product['Minimalni_Zasoba'] }}</td>
|
||||||
|
<td>{{ product['Momentalni_Zasoba'] }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('edit_product', product_id=product['ID_Produktu']) }}">Edit</a> /
|
||||||
|
<a href="{{ url_for('add_product_stock', product_id=product['ID_Produktu']) }}">Add</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6">Nenalezeny žádné produkty k zobrazení.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<footer class="footer" id="kontakt">
|
<footer class="footer">
|
||||||
<div>Made by Hrachovina</div>
|
<div>Made by Hrachovina</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
59
web/templates/create_product.html
Normal file
59
web/templates/create_product.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Přidat Nový Produkt</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
|
<script src="{{url_for('static', filename='scripts/create_product.js')}}"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="header">
|
||||||
|
<div class="contact-info">
|
||||||
|
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
|
||||||
|
</div>
|
||||||
|
<h1 class="nazev">
|
||||||
|
<a href="{{ url_for('home') }}" style="text-decoration: none;">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
|
||||||
|
</a>
|
||||||
|
Přidat Nový Produkt
|
||||||
|
</h1>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{{ url_for('administrator') }}" class="button">Zpět na Administraci</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
{% if not session.get('logged_in') or session.get('role_id') != 1 %}
|
||||||
|
<p>Nemáte oprávnění k přístupu na tuto stránku.</p>
|
||||||
|
{% else %}
|
||||||
|
<form action="{{ url_for('create_product') }}" method="post" class="form-container" onsubmit="handleCreateProduct(event)">
|
||||||
|
<label for="nazev">Název:</label>
|
||||||
|
<input type="text" id="nazev" name="nazev" required>
|
||||||
|
|
||||||
|
<label for="popis">Popis:</label>
|
||||||
|
<textarea id="popis" name="popis" required></textarea>
|
||||||
|
|
||||||
|
<label for="momentalni_zasoba">Momentální Zásoba:</label>
|
||||||
|
<input type="number" id="momentalni_zasoba" name="momentalni_zasoba" required>
|
||||||
|
|
||||||
|
<label for="minimalni_zasoba">Minimální Zásoba:</label>
|
||||||
|
<input type="number" id="minimalni_zasoba" name="minimalni_zasoba" required>
|
||||||
|
|
||||||
|
<button type="submit" class="button">Přidat</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer" id="kontakt">
|
||||||
|
<div>Made by Hrachovina and Kirsch</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -30,6 +30,23 @@
|
|||||||
<label for="popis">Popis:</label>
|
<label for="popis">Popis:</label>
|
||||||
<textarea id="popis" name="popis" required></textarea>
|
<textarea id="popis" name="popis" required></textarea>
|
||||||
|
|
||||||
|
<h3>Použité Produkty</h3>
|
||||||
|
<div id="product-container">
|
||||||
|
<div class="product-item" id="product-item-0">
|
||||||
|
<label for="product_0">Produkt:</label>
|
||||||
|
<select id="product_0" name="products[0][id]" required>
|
||||||
|
<option value="" disabled selected>Vyberte produkt</option>
|
||||||
|
{% for product in products %}
|
||||||
|
<option value="{{ product['ID_Produktu'] }}">{{ product['Nazev'] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="quantity_0">Množství:</label>
|
||||||
|
<input type="number" id="quantity_0" name="products[0][quantity]" value="0" min="0" required>
|
||||||
|
<button type="button" onclick="removeProduct(0)">Odstranit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" onclick="addProduct()">Přidat Produkt</button>
|
||||||
|
|
||||||
<button type="submit" class="button">Vytvořit</button>
|
<button type="submit" class="button">Vytvořit</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,5 +55,7 @@
|
|||||||
<div>Made by Hrachovina</div>
|
<div>Made by Hrachovina</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='scripts/products.js') }}"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Vytvořit Nového Uživatele</title>
|
<title>Vytvořit Nového Uživatele</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
<script src="{{url_for('static', filename='scripts/create_user.js')}}"></script>
|
<script src="{{url_for('static', filename='scripts/create_user.js')}}"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -28,9 +29,6 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{% if not session.get('logged_in') or session.get('role_id') != 1 %}
|
|
||||||
<p>Nemáte oprávnění k přístupu na tuto stránku.</p>
|
|
||||||
{% else %}
|
|
||||||
<form action="{{ url_for('create_user') }}" method="post" class="form-container" onsubmit="handleCreateUser(event)">
|
<form action="{{ url_for('create_user') }}" method="post" class="form-container" onsubmit="handleCreateUser(event)">
|
||||||
<label for="jmeno">Jméno:</label>
|
<label for="jmeno">Jméno:</label>
|
||||||
<input type="text" id="jmeno" name="jmeno" required>
|
<input type="text" id="jmeno" name="jmeno" required>
|
||||||
@@ -42,7 +40,11 @@
|
|||||||
<input type="email" id="email" name="email" required>
|
<input type="email" id="email" name="email" required>
|
||||||
|
|
||||||
<label for="role">Role:</label>
|
<label for="role">Role:</label>
|
||||||
<input type="text" id="role" name="role" required>
|
<select id="role" name="role" required>
|
||||||
|
{% for role in roles %}
|
||||||
|
<option value="{{ role['Role_ID'] }}">{{ role['Nazev'] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
<label for="username">Username:</label>
|
<label for="username">Username:</label>
|
||||||
<input type="text" id="username" name="username" required>
|
<input type="text" id="username" name="username" required>
|
||||||
@@ -52,7 +54,6 @@
|
|||||||
|
|
||||||
<button type="submit" class="button">Vytvořit</button>
|
<button type="submit" class="button">Vytvořit</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="cs">
|
<html lang="cs">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Editovat Objednávku</title>
|
<title>Editovat Objednávku</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -34,12 +34,18 @@
|
|||||||
<input type="text" id="stav" name="stav" value="{{ order['Stav'] }}" required>
|
<input type="text" id="stav" name="stav" value="{{ order['Stav'] }}" required>
|
||||||
|
|
||||||
<label for="id_zamestnance">Přiřazený zaměstnanec:</label>
|
<label for="id_zamestnance">Přiřazený zaměstnanec:</label>
|
||||||
<input type="text" id="id_zamestnance" name="id_zamestnance" value="{{ order['ID_Zamestnance'] }}" required>
|
<select id="id_zamestnance" name="id_zamestnance" required>
|
||||||
|
{% for user in users %}
|
||||||
|
<option value="{{ user['ID_Uzivatele'] }}" {% if user['ID_Uzivatele'] == order['ID_Zamestnance'] %}selected{% endif %}>
|
||||||
|
{{ user['Jmeno'] }} {{ user['Prijmeni'] }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
<label for="popis">Popis:</label>
|
<label for="popis">Popis:</label>
|
||||||
<input type="text" id="popis" name="popis" value="{{ order['Popis'] }}" required>
|
<textarea id="popis" name="popis" rows="4" required>{{ order['Popis'] }}</textarea>
|
||||||
|
|
||||||
<label for="datum_konce">Datum expedice:</label>
|
<label for="datum_konce">Datum konce:</label>
|
||||||
<input type="date" id="datum_konce" name="datum_konce" value="{{ order['Datum_Konce'] }}">
|
<input type="date" id="datum_konce" name="datum_konce" value="{{ order['Datum_Konce'] }}">
|
||||||
|
|
||||||
<button type="submit" class="button">Aktualizovat</button>
|
<button type="submit" class="button">Aktualizovat</button>
|
||||||
|
|||||||
56
web/templates/edit_product.html
Normal file
56
web/templates/edit_product.html
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Editovat Produkt</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="header">
|
||||||
|
<div class="contact-info">
|
||||||
|
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
|
||||||
|
</div>
|
||||||
|
<h1 class="nazev">
|
||||||
|
<a href="{{ url_for('home') }}" style="text-decoration: none;">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
|
||||||
|
</a>
|
||||||
|
Editovat Produkt
|
||||||
|
</h1>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{{ url_for('administrator') }}" class="button">Zpět na Tabulku Produktů</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<h2>Editovat Produkt</h2>
|
||||||
|
<form action="{{ url_for('edit_product', product_id=product['ID_Produktu']) }}" method="post" class="form-container">
|
||||||
|
<label for="nazev">Název:</label>
|
||||||
|
<input type="text" id="nazev" name="nazev" value="{{ product['Nazev'] }}" required>
|
||||||
|
|
||||||
|
<label for="popis">Popis:</label>
|
||||||
|
<textarea id="popis" name="popis" rows="4" required>{{ product['Popis'] }}</textarea>
|
||||||
|
|
||||||
|
<label for="momentalni_zasoba">Momentální Zásoba:</label>
|
||||||
|
<input type="number" id="momentalni_zasoba" name="momentalni_zasoba" value="{{ product['Momentalni_Zasoba'] }}" required>
|
||||||
|
|
||||||
|
<label for="minimalni_zasoba">Minimální Zásoba:</label>
|
||||||
|
<input type="number" id="minimalni_zasoba" name="minimalni_zasoba" value="{{ product['Minimalni_Zasoba'] }}" required>
|
||||||
|
|
||||||
|
<button type="submit" class="button">Aktualizovat</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer" id="kontakt">
|
||||||
|
<div>Made by Hrachovina and Kirsch</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -42,14 +42,35 @@
|
|||||||
<label for="popis">Popis:</label>
|
<label for="popis">Popis:</label>
|
||||||
<textarea id="popis" name="popis" required>{{ repair['Popis'] }}</textarea>
|
<textarea id="popis" name="popis" required>{{ repair['Popis'] }}</textarea>
|
||||||
|
|
||||||
|
<h3>Použité Produkty</h3>
|
||||||
|
<div id="product-container">
|
||||||
|
{% for product in repair['products'] %}
|
||||||
|
<div class="product-item" id="product-item-{{ loop.index0 }}">
|
||||||
|
<label for="product_{{ loop.index0 }}">Produkt:</label>
|
||||||
|
<select id="product_{{ loop.index0 }}" name="products[{{ loop.index0 }}][id]" required>
|
||||||
|
<option value="" disabled>Vyberte produkt</option>
|
||||||
|
{% for p in products %}
|
||||||
|
<option value="{{ p['ID_Produktu'] }}" {% if p['ID_Produktu'] == product['ID_Produktu'] %}selected{% endif %}>{{ p['Nazev'] }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="quantity_{{ loop.index0 }}">Množství:</label>
|
||||||
|
<input type="number" id="quantity_{{ loop.index0 }}" name="products[{{ loop.index0 }}][quantity]" value="{{ product['Pocet_Produktu'] }}" min="0" required>
|
||||||
|
<button type="button" style="margin-top: -5px;" onclick="removeProduct({{ loop.index0 }})">Odstranit</button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<button type="button" onclick="addProduct()">Přidat Produkt</button>
|
||||||
|
|
||||||
<button type="submit" class="button">Aktualizovat</button>
|
<button type="submit" class="button">Aktualizovat</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="footer" id="kontakt">
|
<footer class="footer" id="kontakt">
|
||||||
<div>Made by Hrachovina</div>
|
<div>Made by Hrachovina and Kirsch </div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<script src="{{ url_for('static', filename='scripts/products.js') }}"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Editovat Uživatele</title>
|
<title>Editovat Uživatele</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Autoservis</title>
|
<title>Autoservis</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
<script src="{{url_for('static', filename='scripts/reservation.js')}}"></script>
|
<script src="{{url_for('static', filename='scripts/reservation.js')}}"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -22,11 +23,17 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
{% if session.get('logged_in') %}
|
{% if session.get('logged_in') %}
|
||||||
<a href="{{ url_for('administrator') }}" class="button">Administrace</a>
|
{% if session.get('role_id') == 1 %}
|
||||||
<a href="{{ url_for('repairs') }}" class="button">Správa Oprav</a>
|
<a href="{{ url_for('administrator') }}" class="button">Administrace</a>
|
||||||
|
{% elif session.get('role_id') == 2 %}
|
||||||
|
<a href="{{ url_for('managers') }}" class="button">Manažerský panel</a>
|
||||||
|
<a href="{{ url_for('statistics') }}" class="button">Statistiky</a>
|
||||||
|
{% elif session.get('role_id') == 3 %}
|
||||||
|
<a href="{{ url_for('repairs') }}" class="button">Správa Oprav</a>
|
||||||
|
{% endif %}
|
||||||
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
|
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ url_for('login') }}" class="button">Administrace</a>
|
<a href="{{ url_for('login') }}" class="button">Přihlásit se</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<button class="button" onclick="openReservationForm()">Objednat se</button>
|
<button class="button" onclick="openReservationForm()">Objednat se</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -44,6 +51,7 @@
|
|||||||
<button class="button" onclick="location.href='#directions'">K nám</button>
|
<button class="button" onclick="location.href='#directions'">K nám</button>
|
||||||
<button class="button" onclick="location.href='#nabidka-sluzeb'">Služby</button>
|
<button class="button" onclick="location.href='#nabidka-sluzeb'">Služby</button>
|
||||||
<button class="button" onclick="location.href='#recenze'">Recenze</button>
|
<button class="button" onclick="location.href='#recenze'">Recenze</button>
|
||||||
|
<button class="button" onclick="location.href='#partners'">Partneři</button>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -98,29 +106,51 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="reviews" id="recenze">
|
<div class="reviews" id="recenze">
|
||||||
<div class="review-box">
|
<h2 class="reviews-header">Recenze</h2>
|
||||||
<p>Skvělý servis! Rychlá a profesionální oprava.</p>
|
<div class="review-list">
|
||||||
<p>⭐⭐⭐⭐</p>
|
<div class="review-box">
|
||||||
<p>- Jan Novák</p>
|
<p>Skvělý servis! Rychlá a profesionální oprava.</p>
|
||||||
</div>
|
<p>⭐⭐⭐⭐</p>
|
||||||
<div class="review-box">
|
<p>- Jan Novák</p>
|
||||||
<p>Velmi přátelský personál a kvalitní služby.</p>
|
</div>
|
||||||
<p>⭐⭐⭐⭐⭐</p>
|
<div class="review-box">
|
||||||
<p>- Petra Svobodová</p>
|
<p>Velmi přátelský personál a kvalitní služby.</p>
|
||||||
</div>
|
<p>⭐⭐⭐⭐⭐</p>
|
||||||
<div class="review-box">
|
<p>- Petra Svobodová</p>
|
||||||
<p>Oprava byla hotová dříve, než jsem očekával.</p>
|
</div>
|
||||||
<p>⭐⭐⭐</p>
|
<div class="review-box">
|
||||||
<p>- Martin Dvořák</p>
|
<p>Oprava byla hotová dříve, než jsem očekával.</p>
|
||||||
</div>
|
<p>⭐⭐⭐</p>
|
||||||
<div class="review-box">
|
<p>- Martin Dvořák</p>
|
||||||
<p>Výborná komunikace a skvělé ceny. Určitě se vrátím.</p>
|
</div>
|
||||||
<p>⭐⭐⭐⭐⭐</p>
|
<div class="review-box">
|
||||||
<p>- Eva Černá</p>
|
<p>Výborná komunikace a skvělé ceny. Určitě se vrátím.</p>
|
||||||
|
<p>⭐⭐⭐⭐⭐</p>
|
||||||
|
<p>- Eva Černá</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="partners" id="partners">
|
||||||
|
<h2>Naši partneři</h2>
|
||||||
|
<div class="partner-list">
|
||||||
|
<div class="partner-item">
|
||||||
|
<img src="{{url_for('static', filename='img/partner1.png')}}" alt="Partner 1">
|
||||||
|
</div>
|
||||||
|
<div class="partner-item">
|
||||||
|
<img src="{{url_for('static', filename='img/partner2.png')}}" alt="Partner 2">
|
||||||
|
</div>
|
||||||
|
<div class="partner-item">
|
||||||
|
<img src="{{url_for('static', filename='img/partner3.png')}}" alt="Partner 3">
|
||||||
|
</div>
|
||||||
|
<div class="partner-item">
|
||||||
|
<img src="{{url_for('static', filename='img/partner4.png')}}" alt="Partner 4">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer class="footer" id="kontakt">
|
<footer class="footer">
|
||||||
<div>Made by Hrachovina and Kirsch</div>
|
<div>Made by Hrachovina and Kirsch</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
@@ -134,8 +164,8 @@
|
|||||||
<input type="text" id="fullName" name="fullName" required>
|
<input type="text" id="fullName" name="fullName" required>
|
||||||
<label for="email">Email: <span class="required">*</span></label>
|
<label for="email">Email: <span class="required">*</span></label>
|
||||||
<input type="email" id="email" name="email" required>
|
<input type="email" id="email" name="email" required>
|
||||||
<label for="date">Datum: <span class="required">*</span></label>
|
<label for="datum_konce">Požadované datum vrácení vozidla: <span class="required">*</span></label>
|
||||||
<input type="text" id="date" name="date" required readonly>
|
<input type="date" id="datum_konce" name="datum_konce" required>
|
||||||
<label for="description">Popis: <span class="required">*</span></label>
|
<label for="description">Popis: <span class="required">*</span></label>
|
||||||
<textarea id="description" name="description" rows="4" required></textarea>
|
<textarea id="description" name="description" rows="4" required></textarea>
|
||||||
<button type="submit" class="button">Odeslat</button>
|
<button type="submit" class="button">Odeslat</button>
|
||||||
@@ -143,7 +173,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='scripts/reservation.js') }}"></script>
|
<script>
|
||||||
|
function openReservationForm() {
|
||||||
|
const now = new Date();
|
||||||
|
const minDate = new Date();
|
||||||
|
minDate.setDate(now.getDate() + 3); // Exclude today and the next 2 days
|
||||||
|
const formattedMinDate = minDate.toISOString().split('T')[0];
|
||||||
|
document.getElementById('datum_konce').setAttribute('min', formattedMinDate);
|
||||||
|
document.getElementById('reservationForm').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeReservationForm() {
|
||||||
|
document.getElementById('reservationForm').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
function showReservationSuccess() {
|
||||||
|
alert('Rezervace byla úspěšně vytvořena.');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,18 +4,12 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Přihlášení</title>
|
<title>Přihlášení</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<h2> Přihlášení </h2>
|
<h2> Přihlášení </h2>
|
||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
||||||
{% if messages %}
|
|
||||||
<ul class="flashes">
|
|
||||||
<li class="{{ messages[-1][0] }}">{{ messages[-1][1] }}</li> <!-- Show only the last message -->
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
<form method="POST" action="{{ url_for('login') }}">
|
<form method="POST" action="{{ url_for('login') }}">
|
||||||
<label for="username">Uživatelské jméno: <span class="required">*</span></label>
|
<label for="username">Uživatelské jméno: <span class="required">*</span></label>
|
||||||
<input type="text" id="username" name="username" required>
|
<input type="text" id="username" name="username" required>
|
||||||
|
|||||||
142
web/templates/managers.html
Normal file
142
web/templates/managers.html
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Správa Manažerů</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
|
<!-- <script src="{{url_for('static', filename='scripts/user_table.js')}}"></script> -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="header">
|
||||||
|
<div class="contact-info">
|
||||||
|
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
|
||||||
|
</div>
|
||||||
|
<h1 class="nazev">
|
||||||
|
<a href="{{ url_for('home') }}" style="text-decoration: none;">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
|
||||||
|
</a>
|
||||||
|
Správa Manažerů
|
||||||
|
</h1>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{{ url_for('home') }}" class="button">Zpět na Domovskou Stránku</a>
|
||||||
|
<a href="{{ url_for('create_user') }}" class="button">Vytvořit Nového Uživatele</a>
|
||||||
|
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<div class="user-table">
|
||||||
|
<nav class="table-header">
|
||||||
|
<h2 id="users-table">Správa Uživatelů</h2>
|
||||||
|
</nav>
|
||||||
|
{% if users %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Jméno</th>
|
||||||
|
<th>Prijmeni</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Username</th>
|
||||||
|
<th>Akce</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in users %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ user['ID_Uzivatele'] }}</td>
|
||||||
|
<td>{{ user['Jmeno'] }}</td>
|
||||||
|
<td>{{ user['Prijmeni'] }}</td>
|
||||||
|
<td>{{ user['Email'] }}</td>
|
||||||
|
<td>
|
||||||
|
{% for role in roles %}
|
||||||
|
{% if role['Role_ID'] == user['Role_ID'] %}
|
||||||
|
{{ role['Nazev'] }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>{{ user['Username'] }}</td>
|
||||||
|
<td>
|
||||||
|
{% if user['Role_ID'] > session.get('role_id') or user['ID_Uzivatele'] == session.get('user_id') %}
|
||||||
|
<a href="{{ url_for('edit_user', user_id=user['ID_Uzivatele']) }}">Edit</a>
|
||||||
|
{% if user['Role_ID'] > session.get('role_id') %}
|
||||||
|
/ <form action="{{ url_for('delete_user', user_id=user['ID_Uzivatele']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tohoto uživatele?');">
|
||||||
|
<button type="submit" class="button-link">Delete</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<p>No users found.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="order-management">
|
||||||
|
<nav class="table-header">
|
||||||
|
<h2 id="orders-table">Správa objednávek</h2>
|
||||||
|
</nav>
|
||||||
|
{% if orders %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Datum začátku</th>
|
||||||
|
<th>Datum konce</th>
|
||||||
|
<th>Stav</th>
|
||||||
|
<th>Přiřazený zaměstnanec</th>
|
||||||
|
<th>Popis</th>
|
||||||
|
<th>Akce</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for order in orders %}
|
||||||
|
<tr style="text-align: center;">
|
||||||
|
<td>{{ order['ID_Objednavky'] }}</td>
|
||||||
|
<td>{{ order['Datum_Zacatku'] }}</td>
|
||||||
|
<td>{{ order['Datum_Konce'] }}</td>
|
||||||
|
<td>{{ order['Stav'] }}</td>
|
||||||
|
<td>
|
||||||
|
{% for user in users %}
|
||||||
|
{% if user['ID_Uzivatele'] == order['ID_Zamestnance'] %}
|
||||||
|
{{ user['Jmeno'] }} {{ user['Prijmeni'] }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>{{ order['Popis'] }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('edit_order', order_id=order['ID_Objednavky']) }}">Edit</a> /
|
||||||
|
<form action="{{ url_for('delete_order', order_id=order['ID_Objednavky']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tuto objednávku?');">
|
||||||
|
<button type="submit" class="button-link">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<table>
|
||||||
|
<tr style="text-align: center;">
|
||||||
|
<td colspan="7">Nenalezeny žádné objednávky k zobrazení.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div>Made by Hrachovina</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -29,8 +29,10 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h2>Opravy</h2>
|
<div class="user-table">
|
||||||
<div class="repair-table">
|
<nav class="table-header">
|
||||||
|
<h2 id="users-table">Správa Oprav</h2>
|
||||||
|
</nav>
|
||||||
{% if repairs %}
|
{% if repairs %}
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
@@ -40,7 +42,7 @@
|
|||||||
<th>Název</th>
|
<th>Název</th>
|
||||||
<th>Popis</th>
|
<th>Popis</th>
|
||||||
<th>Použité Produkty</th>
|
<th>Použité Produkty</th>
|
||||||
<th>Akce</th> <!-- New column for actions -->
|
<th>Akce</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -56,11 +58,11 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('edit_repair', repair_id=repair['ID_Opravy']) }}">Edit</a>
|
<a href="{{ url_for('edit_repair', repair_id=repair['ID_Opravy']) }}" class="button-link">Edit</a> /
|
||||||
<form action="{{ url_for('delete_repair', repair_id=repair['ID_Opravy']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tuto opravu?');">
|
<form action="{{ url_for('delete_repair', repair_id=repair['ID_Opravy']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tuto opravu?');">
|
||||||
<button type="submit" class="button-link">Delete</button>
|
<button type="submit" class="button-link">Delete</button>
|
||||||
</form>
|
</form>
|
||||||
</td> <!-- Edit and Delete buttons -->
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -69,10 +71,61 @@
|
|||||||
<p>No repairs found.</p>
|
<p>No repairs found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="order-management">
|
||||||
|
<nav class="table-header">
|
||||||
|
<h2 id="orders-table">Správa Objednávek</h2>
|
||||||
|
</nav>
|
||||||
|
{% if orders %}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Datum začátku</th>
|
||||||
|
<th>Datum konce</th>
|
||||||
|
<th>Stav</th>
|
||||||
|
<th>Přiřazený zaměstnanec</th>
|
||||||
|
<th>Popis</th>
|
||||||
|
<th>Akce</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for order in orders %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ order['ID_Objednavky'] }}</td>
|
||||||
|
<td>{{ order['Datum_Zacatku'] }}</td>
|
||||||
|
<td>{{ order['Datum_Konce'] }}</td>
|
||||||
|
<td>{{ order['Stav'] }}</td>
|
||||||
|
<td>
|
||||||
|
{% for user in users %}
|
||||||
|
{% if user['ID_Uzivatele'] == order['ID_Zamestnance'] %}
|
||||||
|
{{ user['Jmeno'] }} {{ user['Prijmeni'] }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
<td>{{ order['Popis'] }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ url_for('edit_order', order_id=order['ID_Objednavky']) }}">Edit</a> /
|
||||||
|
<form action="{{ url_for('delete_order', order_id=order['ID_Objednavky']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tuto objednávku?');">
|
||||||
|
<button type="submit" class="button-link">Delete</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% else %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td colspan="7">Nenalezeny žádné objednávky k zobrazení.</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="footer" id="kontakt">
|
<footer class="footer">
|
||||||
<div>Made by Hrachovina</div>
|
<div>Made by Hrachovina</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|||||||
57
web/templates/statistics.html
Normal file
57
web/templates/statistics.html
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Statistiky</title>
|
||||||
|
<link rel="icon" href="{{url_for('static', filename='img/logo.webp')}}" type="image/x-icon">
|
||||||
|
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<div class="header">
|
||||||
|
<div class="contact-info">
|
||||||
|
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
|
||||||
|
</div>
|
||||||
|
<h1 class="nazev">
|
||||||
|
<a href="{{ url_for('home') }}" style="text-decoration: none;">
|
||||||
|
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
|
||||||
|
</a>
|
||||||
|
Statistika Oprav
|
||||||
|
</h1>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="{{ url_for('home') }}" class="button">Zpět na Domovskou Stránku</a>
|
||||||
|
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="statistics-container">
|
||||||
|
<h2 class="statistics-header">Počet Oprav podle Zaměstnance</h2>
|
||||||
|
<canvas id="repairsChart"></canvas>
|
||||||
|
<script id="repairsData" type="application/json">{{ repairs_data | tojson }}</script>
|
||||||
|
</div>
|
||||||
|
<div class="statistics-container">
|
||||||
|
<h2 class="statistics-header">Počet Oprav podle Času</h2>
|
||||||
|
<div class="statistics-form">
|
||||||
|
<label for="startDate">Začátek:</label>
|
||||||
|
<input type="date" id="startDate" name="startDate">
|
||||||
|
<label for="endDate">Konec:</label>
|
||||||
|
<input type="date" id="endDate" name="endDate">
|
||||||
|
<button onclick="fetchRepairsByDate()">Zobrazit</button>
|
||||||
|
</div>
|
||||||
|
<canvas id="timeRepairsChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="footer">
|
||||||
|
<div>Made by Hrachovina</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="{{url_for('static', filename='scripts/statistics.js')}}"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user