Many Changes

main
sebastian.serfling 2025-03-05 10:33:58 +00:00
parent 8d5e367d23
commit bf95494ab3
17 changed files with 445 additions and 97 deletions

View File

@ -5,5 +5,7 @@ backgroundColor="#2c3e50"
secondaryBackgroundColor="#34495e" secondaryBackgroundColor="#34495e"
textColor="#ffffff" textColor="#ffffff"
font="sans serif" font="sans serif"
layout="wide" layout="wide"
[browser]
serverAddress = "reporting.stines.de"

151
app.py
View File

@ -1,52 +1,145 @@
import streamlit as st import streamlit as st
from streamlit_option_menu import option_menu
import sites.services_reporting as sr import sites.services_reporting as sr
import sites.userlist as us import sites.userlist as us
import sites.server as s import sites.server as s
import sites.tickets as ti import sites.tickets as ti
import sites.lastrun as lr import sites.lastrun as lr
from datetime import datetime
from dateutil.relativedelta import relativedelta
import mysql.connector
import pandas as pd
import os
# Page Settings # Page Settings
st.set_page_config(page_title="Reporting", layout="wide") st.set_page_config(page_title="Reporting", layout="wide")
start_date = datetime.today().replace(day=1) - relativedelta(months=1)
end_date = datetime.today().replace(day=1) - relativedelta(days=1)
# Datumsformatierung
start_date_format = start_date.strftime("%Y-%m-%d")
end_date_format = end_date.strftime("%Y-%m-%d")
# Load custom CSS # Load custom CSS
def load_css(file_name): def load_css(file_name):
with open(file_name) as f: with open(file_name) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True) st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
load_css('style.css') def get_customer_used_service():
# Define page functions mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
mycursor = mydb.cursor()
mycursor.execute(f"""SELECT c.companyname, c.customer_ID, cs.services_ID,s.name from Kunden.`customers.services` cs
JOIN Kunden.company c ON c.customer_ID = cs.customer_ID
JOIN Kunden.services s ON s.service_ID = cs.services_ID
where 1=1 GROUP by c.companyname , c.customer_ID, cs.services_ID, s.name """)
myresult = mycursor.fetchall()
mydb.close()
return myresult
def load_user_service_list(service_id, customer_id, start_date, end_date):
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
query = f"""
SELECT COUNT(*) AS max_count
FROM (
SELECT
u.user_id,
u.username,
active_users.last_active_timestamp,
active_users.status
FROM Kunden.`users` u
JOIN (
SELECT
us.user_id,
us.`timestamp` AS last_active_timestamp,
us.status
FROM Kunden.`users.services` us
JOIN (
SELECT
user_id,
MAX(`timestamp`) AS last_active_timestamp
FROM Kunden.`users.services`
WHERE `timestamp` <= '{end_date}'
AND customer_id = {customer_id}
AND service_ID = {service_id}
AND user_id NOT IN (
SELECT user_id
FROM Kunden.`users.status`
WHERE status = 0
AND `timestamp` < '{start_date}'
AND customer_id = {customer_id}
)
GROUP BY user_id
) max_timestamps
ON us.user_id = max_timestamps.user_id
AND us.`timestamp` = max_timestamps.last_active_timestamp
WHERE us.customer_id = {customer_id}
AND us.service_ID = {service_id}
AND us.status = 1
) active_users
ON u.user_id = active_users.user_id
) AS max_count;
"""
max_user_count = pd.read_sql_query(query, mydb)
mydb.close()
return max_user_count.iloc[0]['max_count'] if not max_user_count.empty else 0
def home(): def home():
st.title("Home Page") st.title("Dashboard")
st.write("Welcome to the Home Page!") edit_start_date = start_date.strftime("%d.%m.%Y")
edit_end_date = end_date.strftime("%d.%m.%Y")
st.subheader(f"Übersicht {edit_start_date} - {edit_end_date}")
previous_value = None
columns = None
c = 0
for i in get_customer_used_service():
if previous_value != i[1]:
st.subheader(f"{i[0]}")
columns = st.columns(3)
c = 0
if not (load_user_service_list(i[2], i[1], start_date, end_date)):
st.info(f"Kunde {i[0]} - Service {i[3]} - Not Data found!")
else:
columns[c].metric(label=f"Aktive {i[3]} User", value=load_user_service_list(i[2], i[1], start_date, end_date))
c +=1
previous_value = i[1]
# Navigation bar using streamlit-option-menu
with st.sidebar:
selected_page = option_menu(
menu_title="Navigation", # required
options=["Dashboard", "Services Reporting", "User Filter", "Server", "Tickets", "Last-Run"], # required
icons=["house", "bar-chart", "filter", "server", "ticket", "clock"], # optional
menu_icon="cast", # optional
default_index=0, # optional
orientation="vertikal", # horizontal navigation
)
if 'page' not in st.session_state: # Page display logic based on selected option
st.session_state.page = 'Home' if selected_page == "Dashboard":
# Sidebar navigation
st.sidebar.title("Navigation")
if st.sidebar.button('Home'):
st.session_state.page = 'Home'
if st.sidebar.button('Services Reporting'):
st.session_state.page = 'Services Reporting'
if st.sidebar.button('User Filter'):
st.session_state.page = 'User Filter'
if st.sidebar.button('Server'):
st.session_state.page = 'Server'
if st.sidebar.button('Tickets'):
st.session_state.page = 'Tickets'
if st.sidebar.button('Last-Run'):
st.session_state.page = 'Last-Run'
# Page display logic
if st.session_state.page == 'Home':
home() home()
elif st.session_state.page == 'Services Reporting': elif selected_page == "Services Reporting":
sr.services_reporting() sr.services_reporting()
elif st.session_state.page == 'User Filter': elif selected_page == "User Filter":
us.user_filter() us.user_filter()
elif st.session_state.page == 'Server': elif selected_page == "Server":
s.server_filter() s.server_filter()
elif st.session_state.page == 'Tickets': elif selected_page == "Tickets":
ti.ticket_filter() ti.ticket_filter()
elif st.session_state.page == 'Last-Run': elif selected_page == "Last-Run":
lr.user_filter() lr.user_filter()

Binary file not shown.

Binary file not shown.

View File

@ -25,10 +25,11 @@ def fetch_tickets_from_database():
# Tickets abrufen, inklusive customer_ID # Tickets abrufen, inklusive customer_ID
cursor.execute(""" cursor.execute("""
SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID, t.tags
FROM Kunden.tickets t FROM Kunden.tickets t
JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID
JOIN Kunden.services s ON s.service_ID = t.service_ID JOIN Kunden.services s ON s.service_ID = t.service_ID
WHERE closedate >= DATE_SUB(CURDATE(), INTERVAL 32 DAY)
ORDER by t.createdate ASC ORDER by t.createdate ASC
""") """)
tickets = cursor.fetchall() tickets = cursor.fetchall()
@ -136,7 +137,7 @@ def set_cell_border(cell, **kwargs):
def fill_template(doc_path, output_path, data, tickets): def fill_template(doc_path, output_path, data, tickets):
doc = Document(doc_path) doc = Document(doc_path)
print("Korrekt")
# Platzhalter in normalem Text ersetzen # Platzhalter in normalem Text ersetzen
for paragraph in doc.paragraphs: for paragraph in doc.paragraphs:
for key, value in data.items(): for key, value in data.items():
@ -161,8 +162,15 @@ def fill_template(doc_path, output_path, data, tickets):
second_table = doc.tables[1] second_table = doc.tables[1]
for ticket in tickets: for ticket in tickets:
row = second_table.add_row() row = second_table.add_row()
ticket_number, title, createdate, _, _, _, timerange, _, _, tags = ticket
print(ticket[9])
row.cells[0].text = ticket[0] # Ticketnummer row.cells[0].text = ticket[0] # Ticketnummer
row.cells[1].text = ticket[1] # Tickettitel if ticket[9]:
row.cells[1].text = f"{ticket[1]} - {ticket[9]}" # Tickettitel
else:
row.cells[1].text = ticket[1]
row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren
row.cells[3].text = str(ticket[6]) # timerange (time_unit) row.cells[3].text = str(ticket[6]) # timerange (time_unit)
@ -228,11 +236,15 @@ if __name__ == "__main__":
price = next(iter(set(ticket[7] for ticket in tickets))) price = next(iter(set(ticket[7] for ticket in tickets)))
customer_ids = set(ticket[4] for ticket in tickets) customer_ids = set(ticket[4] for ticket in tickets)
print(tickets)
print(customer_ids)
for customer_id in customer_ids: for customer_id in customer_ids:
customer_data = fetch_customer_data(customer_id) customer_data = fetch_customer_data(customer_id)
customer_servicetime = fetch_customer_servicetime(customer_id) customer_servicetime = fetch_customer_servicetime(customer_id)
customer_price = fetch_customer_price(price, customer_id, service_ID) customer_price = fetch_customer_price(price, customer_id, service_ID)
customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id] customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id]
print(customer_data)
if not customer_data: if not customer_data:
print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!") print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!")
@ -257,22 +269,21 @@ if __name__ == "__main__":
"city": customer_data[4], "city": customer_data[4],
"customernumber": customer_data[5], "customernumber": customer_data[5],
"year": datetime.now().year, "year": datetime.now().year,
"ordernumber": "0001", "ordernumber": "1",
"startdate": startdate.strftime("%d.%m.%Y"), "startdate": startdate.strftime("%d.%m.%Y"),
"enddate": enddate.strftime("%d.%m.%Y"), "enddate": enddate.strftime("%d.%m.%Y"),
"today": datetime.now().strftime("%d.%m.%Y"), "today": datetime.now().strftime("%d.%m.%Y"),
"price_per_minute": customer_price, "price_per_minute": customer_price,
"servicetime": customer_servicetime[0], "servicetime": customer_servicetime[0],
"gesamt_time_unit": 0, "gesamt_time_unit": 0,
"price_ex_mwst": 0, "price_ex_mwst": "0,00",
"sl_time_unit": 0, "sl_time_unit": 0,
"sl_minus_unit": 0, "sl_minus_unit": 0,
"zl_time_unit": 0, "zl_time_unit": 0,
"time_unit_sum": 0, "time_unit_sum": 0,
"mwst_set": 0, "mwst_set": "0,00",
"sum": 0, "sum": "0,00",
} }
output_path = f"apps/ticket_export/exports/RE2025.{customer_data[5]}.{data['ordernumber']}.docx"
output_path = f"apps/ticket_export/exports/RE2024.{customer_data[5]}.{data['ordernumber']}.docx"
fill_template('apps/ticket_export/template.docx', output_path, data, customer_tickets) fill_template('apps/ticket_export/template.docx', output_path, data, customer_tickets)
print("True") print("True")

Binary file not shown.

View File

@ -1,8 +1,8 @@
version: "3.5"
services: services:
streamlit: streamlit:
build: . build:
container_name: streamlit context: .
dockerfile: dockerfile
ports: ports:
- 80:80 - 80:80
networks: networks:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,7 @@ from dotenv import load_dotenv
load_dotenv() load_dotenv()
def get_filtered_server(customer_id, service_id, service_status): def get_filtered_server(customer_ids, service_id, service_status, os_type, reporting):
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"), user=os.getenv("MYSQL_USER"),
@ -18,23 +18,30 @@ def get_filtered_server(customer_id, service_id, service_status):
# Prepare the base query # Prepare the base query
query = f""" query = f"""
select s.hostname,s.privat_ipaddress,s.public_ipaddress, s.ram, s.createdate, s.disabledate,s.customer_ID,s.server_ID,hc.name,hc.core select s.hostname, s.privat_ipaddress, s.public_ipaddress, s.ram, s.createdate, s.disabledate, s.os, s.customer_ID, s.server_ID, hc.name, hc.core
from Kunden.server s from Kunden.server s
join Kunden.`hardware.cpu` hc ON hc.cpu_ID = s.cpu_ID join Kunden.`hardware.cpu` hc ON hc.cpu_ID = s.cpu_ID
WHERE 1=1 WHERE 1=1
""" """
if customer_id:
query += f"AND s.customer_ID = {customer_id}" # If multiple customers are selected, use the IN clause
if customer_ids:
customer_ids_str = ', '.join([str(id) for id in customer_ids])
query += f" AND s.customer_ID IN ({customer_ids_str})"
if service_id: if service_id:
query += f" AND s.service_ID = {service_id}" query += f" AND s.service_ID = {service_id}"
if service_status: if service_status:
query += f" AND s.status = {service_status}" query += f" AND s.status = {service_status}"
if os_type:
query += f" AND s.os = '{os_type}'"
if reporting == "True":
query += f" AND licensekey IS NOT NULL"
users = pd.read_sql_query(query, mydb) users = pd.read_sql_query(query, mydb)
mydb.close() mydb.close()
return users return users
def get_initial_data(): def get_initial_data():
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
@ -60,7 +67,6 @@ def get_initial_data():
mydb.close() mydb.close()
return service_ids, customers return service_ids, customers
def server_filter(): def server_filter():
st.title("Server Filter :mag_right:") st.title("Server Filter :mag_right:")
# Get initial data for widgets # Get initial data for widgets
@ -68,15 +74,17 @@ def server_filter():
# Combine service_ID and name for display # Combine service_ID and name for display
service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1) service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1)
# Add selection widget for customer ID # Create a dictionary for customer selection
selected_customer = st.selectbox( customer_dict = {f"{row['companyname']} - {row['customer']}": row['customer_ID'] for _, row in customers.iterrows()}
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}", # Use multiselect for multiple customer selection
axis=1).tolist() selected_customers = st.multiselect(
'Select Customer(s)',
list(customer_dict.keys()) # Display only companyname and customer
) )
# Extract customer_ID from selected option # Get the corresponding customer IDs
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0]) selected_customer_ids = [customer_dict[customer] for customer in selected_customers]
# Add selection widget for service ID # Add selection widget for service ID
selected_service = st.selectbox( selected_service = st.selectbox(
@ -96,13 +104,33 @@ def server_filter():
# Extract status from selected option # Extract status from selected option
service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0]) service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0])
# Add SPLA server selection
reporting_box = st.selectbox(
'Select SPLA Server',
["Nein", "Ja"]
)
# Extract reporting status
reporting = None if reporting_box == "Nein" else "True"
# Add OS type selection
os_box = st.selectbox(
'Select OS Type',
["All", "Linux", "Windows"]
)
# Extract OS type
os_type = None if os_box == "All" else os_box
# Add a button to apply filters # Add a button to apply filters
if st.button('Apply Filters'): if st.button('Apply Filters'):
# Fetch filtered data from the database # Fetch filtered data from the database
filtered_data = get_filtered_server(selected_customer_id, selected_service_id, service_status) filtered_data = get_filtered_server(selected_customer_ids, selected_service_id, service_status, os_type, reporting)
# Display the filtered data # Display the filtered data
if not filtered_data.empty: if not filtered_data.empty:
st.dataframe(filtered_data) st.dataframe(filtered_data)
st.text(f"CPU SUMME = {sum(filtered_data['core'])}" )
st.text(f"Berechung der Core-Pakete: Anzahl der Cores({filtered_data['core'].count()}) * Core-Pakete aus SPLA (8) / 2")
st.text(f"Reporting Core-Pakete = {(filtered_data['core'].count())*8/2}".split('.')[0])
else: else:
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")

View File

@ -4,11 +4,14 @@ import mysql.connector
from datetime import datetime, date from datetime import datetime, date
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
import altair as alt
load_dotenv() load_dotenv()
def get_filtered_data(customer_id, service_id, start_date, end_date): def get_filtered_data(customer_id, service_id, start_date, end_date):
"""
Fetches the user count data grouped by month within the specified date range.
"""
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"), user=os.getenv("MYSQL_USER"),
@ -16,9 +19,8 @@ def get_filtered_data(customer_id, service_id, start_date, end_date):
database=os.getenv("MYSQL_DATABASE") database=os.getenv("MYSQL_DATABASE")
) )
# Prepare the query
query = f""" query = f"""
SELECT DATE_FORMAT(sr.reportingdate, '%Y-%m') AS month, SELECT DATE_FORMAT(sr.reportingdate, '%Y-%m') AS day,
COUNT(DISTINCT sr.username) as count COUNT(DISTINCT sr.username) as count
FROM Kunden.`services.reporting` sr FROM Kunden.`services.reporting` sr
JOIN Kunden.services s ON sr.service_ID = s.service_ID JOIN Kunden.services s ON sr.service_ID = s.service_ID
@ -36,6 +38,163 @@ def get_filtered_data(customer_id, service_id, start_date, end_date):
return service_reporting return service_reporting
def get_user_online(customer_id,service_id,start_date,end_date):
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
if service_id == 100:
user_info = "u.primarymail as username"
else:
user_info = "u.username"
query = f"""
SELECT DATE_FORMAT(sr.reportingdate, '%Y-%m') AS day,
sr.username
FROM Kunden.`services.reporting` sr
JOIN Kunden.services s ON sr.service_ID = s.service_ID
WHERE sr.customer_ID = {customer_id}
AND sr.service_ID = {service_id}
AND sr.username NOT LIKE '%admin%'
AND sr.username NOT LIKE '%test%'
AND sr.reportingdate BETWEEN '{start_date}' AND '{end_date}'
GROUP BY day, sr.username
ORDER BY sr.username;
"""
user_online = pd.read_sql_query(query, mydb)
user_online_count= user_online.shape[0]
mydb.close()
return user_online, user_online_count
def get_max_user_count(customer_id, service_id, start_date, end_date):
"""
Fetches the maximum user count within the specified date range.
"""
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
query = f"""
SELECT MAX(user_counts.count) as max_count
FROM (
SELECT DATE_FORMAT(sr.reportingdate, '%Y-%m') AS day,
COUNT(DISTINCT sr.username) as count
FROM Kunden.`services.reporting` sr
JOIN Kunden.services s ON sr.service_ID = s.service_ID
WHERE sr.customer_ID = {customer_id}
AND sr.service_ID = {service_id}
AND sr.username NOT LIKE '%admin%'
AND sr.username NOT LIKE '%test%'
AND sr.reportingdate BETWEEN '{start_date}' AND '{end_date}'
GROUP BY DATE_FORMAT(sr.reportingdate, '%Y-%m')
) as user_counts;
"""
max_user_count = pd.read_sql_query(query, mydb)
mydb.close()
return max_user_count.iloc[0]['max_count'] if not max_user_count.empty else 0
def get_active_users(customer_id, service_id, start_date, end_date):
"""
Fetch all active users for the given customer, service, and date range
based on the most recent activity and status.
"""
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
if service_id == 100:
user_info = "u.primarymail as username"
else:
user_info = "u.username"
query = f"""
SELECT
{user_info}
FROM Kunden.`users` u
JOIN (
SELECT
us.user_id,
us.`timestamp` AS last_active_timestamp,
us.status
FROM Kunden.`users.services` us
JOIN (
SELECT
user_id,
MAX(`timestamp`) AS last_active_timestamp
FROM Kunden.`users.services`
WHERE `timestamp` <= '{end_date}'
AND customer_id = {customer_id}
AND service_ID = {service_id}
AND user_id NOT IN (
SELECT user_id
FROM Kunden.`users.status`
WHERE status = 0
AND `timestamp` < '{start_date}'
AND customer_id = {customer_id}
)
GROUP BY user_id
) max_timestamps ON us.user_id = max_timestamps.user_id
AND us.`timestamp` = max_timestamps.last_active_timestamp
WHERE us.customer_id = {customer_id}
AND us.service_ID = {service_id}
AND us.status = 1
) active_users ON u.user_id = active_users.user_id
GROUP BY u.user_id, u.username, active_users.last_active_timestamp, active_users.status ORDER by u.username ASC;
"""
active_users = pd.read_sql_query(query, mydb)
user_active_count = active_users.shape[0]
mydb.close()
return active_users, user_active_count
def get_user_not_online(customer_id,service_id,start_date,end_date):
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
query = f"""
SELECT u.username, ss.service_ID
FROM Kunden.users u
JOIN Kunden.`users.services` ss ON ss.user_ID = u.user_ID
JOIN (
SELECT user_id,
MAX(CASE WHEN status = 1 THEN timestamp END) AS latest_active_timestamp,
MAX(CASE WHEN status = 0 THEN timestamp END) AS latest_inactive_timestamp
FROM Kunden.`users.status`
GROUP BY user_id
) us ON u.user_ID = us.user_id
WHERE ss.service_ID = {service_id}
AND (
(us.latest_active_timestamp IS NOT NULL AND
(us.latest_inactive_timestamp IS NULL OR us.latest_active_timestamp > us.latest_inactive_timestamp))
OR us.latest_inactive_timestamp IS NULL
)
AND u.username NOT IN (
SELECT sr.username
FROM Kunden.`services.reporting` sr
WHERE sr.service_ID = {service_id}
AND sr.reportingdate BETWEEN '{start_date}' AND '{end_date}'
)
AND u.user_ID != 95
AND u.user_ID != 102
AND u.customer_ID = {customer_id}
AND u.username NOT LIKE "%ad-test-user%"
"""
not_active_users = pd.read_sql_query(query, mydb)
user_not_online_count = not_active_users.shape[0]
mydb.close()
return not_active_users, user_not_online_count
def get_initial_data(): def get_initial_data():
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
@ -43,6 +202,7 @@ def get_initial_data():
password=os.getenv("MYSQL_PASSWORD"), password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE") database=os.getenv("MYSQL_DATABASE")
) )
# Fetch unique service IDs and names # Fetch unique service IDs and names
service_id_query = """ service_id_query = """
SELECT DISTINCT s.service_ID, s.name SELECT DISTINCT s.service_ID, s.name
@ -71,61 +231,98 @@ def get_initial_data():
return service_ids, customers, date_range return service_ids, customers, date_range
def generate_month_range(min_date, max_date):
months = pd.date_range(start=min_date, end=max_date, freq='MS').strftime("%Y-%m").tolist()
return months
def services_reporting(): def services_reporting():
st.title("Reporting :mag_right:") st.title("Reporting :mag_right:")
# Get initial data for widgets # Get initial data for widgets
initial_service_ids, customers, initial_date_range = get_initial_data() initial_service_ids, customers, initial_date_range = get_initial_data()
# Combine service_ID and name for display
service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1) service_options = initial_service_ids.apply(lambda row: f"{row['service_ID']} - {row['name']}", axis=1)
# Add selection widget for customer ID # Selection widget for customer ID
customer_dict = {f"{row['companyname']} - {row['customer']}": row['customer_ID'] for _, row in customers.iterrows()}
# Selectbox with only the customer name and company displayed
selected_customer = st.selectbox( selected_customer = st.selectbox(
'Select Customer', 'Select Customer',
customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}", axis=1).tolist() list(customer_dict.keys()) # Display only companyname and customer
) )
# Extract customer_ID from selected option # Get the corresponding customer ID
selected_customer_id = int(selected_customer.split(' - ')[0]) selected_customer_id = customer_dict[selected_customer]
# Add selection widget for service ID # Selection widget for service ID
selected_service = st.selectbox( selected_service = st.selectbox(
'Select Service', 'Select Service',
service_options.tolist() service_options.tolist()
) )
# Extract service_ID from selected option
selected_service_id = int(selected_service.split(' - ')[0]) selected_service_id = int(selected_service.split(' - ')[0])
# Convert date range to datetime objects # Convert date range to datetime objects
min_date = initial_date_range['min_date'][0] min_date = initial_date_range['min_date'][0]
max_date = initial_date_range['max_date'][0] max_date = initial_date_range['max_date'][0]
# Generate month options for dropdown # Date input for start and end date
month_options = generate_month_range(min_date, max_date) start_date = st.date_input('Start Date', min_date)
end_date = st.date_input('End Date', max_date)
# Add dropdown for start and end months
start_month = st.selectbox('Start Month', month_options)
end_month = st.selectbox('End Month', month_options, index=len(month_options) - 1)
# Convert 'YYYY-MM' to 'YYYY-MM-DD' format for SQL query
start_date = datetime.strptime(start_month, '%Y-%m').date().replace(day=1)
end_date = datetime.strptime(end_month, '%Y-%m').date().replace(day=1)
end_date = (end_date.replace(day=28) + pd.DateOffset(days=4)).replace(day=1) - pd.DateOffset(days=1) # last day of the month
# Add a button to apply filters
if st.button('Apply Filters'): if st.button('Apply Filters'):
# Fetch filtered data from the database # Fetch filtered data from the database
filtered_data = get_filtered_data(selected_customer_id, selected_service_id, start_date, end_date) filtered_data = get_filtered_data(selected_customer_id, selected_service_id, start_date, end_date)
# Sort the data by month # Fetch max user count in the selected range
filtered_data = filtered_data.sort_values('month') max_count = get_max_user_count(selected_customer_id, selected_service_id, start_date, end_date)
# Sort the data by day
filtered_data = filtered_data.sort_values('day')
# Create a bar chart with the filtered data
if not filtered_data.empty: if not filtered_data.empty:
st.bar_chart(filtered_data.set_index('month')['count']) # Highlight the max value in the chart
filtered_data['color'] = filtered_data['count'].apply(lambda x: 'red' if x == max_count else 'steelblue')
# Create an Altair bar chart
bars = alt.Chart(filtered_data).mark_bar().encode(
x='day:O',
y='count:Q',
color=alt.Color('color:N', scale=None, legend=None)
)
# Add text labels to bars
text = bars.mark_text(
align='center',
baseline='middle',
dy=-10
).encode(
text='count:Q'
)
# Combine bars and text into a single chart
chart = (bars + text).properties(
title='Daily Service Usage with Highlighted Maximum'
)
# Fetch the data for users not online, online, and active users
not_user_online, max_count_user_not_online = get_user_not_online(selected_customer_id, selected_service_id, start_date, end_date)
user_online, user_online_count = get_user_online(selected_customer_id, selected_service_id, start_date, end_date)
active_users_data, user_active_count = get_active_users(selected_customer_id, selected_service_id, start_date, end_date)
# Create three columns for each DataFrame
col1, col2, col3, col4, col5 = st.columns([2,2,2,2,2])
# Display each DataFrame in a separate column
with col4:
st.subheader(f"{selected_service.split(' - ')[1]} - User not Online")
st.metric(label="1",label_visibility="hidden", value=max_count_user_not_online)
st.data_editor(not_user_online['username'],use_container_width=True, hide_index=True)
with col2:
st.subheader(f"{selected_service.split(' - ')[1]} - User Online")
st.metric(label="1",label_visibility="hidden", value=user_online_count)
st.data_editor(user_online['username'],use_container_width=True, hide_index=True)
with col3:
st.subheader(f"{selected_service.split(' - ')[1]} - Active Users")
st.metric(label="1",label_visibility="hidden", value=user_active_count)
st.data_editor(active_users_data['username'],key=active_users_data,use_container_width=True, hide_index=True)
st.altair_chart(chart, use_container_width=True)
else: else:
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")

View File

@ -20,7 +20,7 @@ def get_filtered_users(customer_id, start_date, end_date):
# Prepare the base query with date filter # Prepare the base query with date filter
query = f""" query = f"""
SELECT number, title, createdate, time FROM Kunden.tickets SELECT number, title, createdate, time FROM Kunden.tickets
WHERE createdate BETWEEN '{start_date}' AND '{end_date}' WHERE closedate BETWEEN '{start_date}' AND '{end_date}'
""" """
if customer_id: if customer_id:
query += f" AND customer_ID = {customer_id}" query += f" AND customer_ID = {customer_id}"

1
streamlit.sh Normal file
View File

@ -0,0 +1 @@
streamlit run app.py --server.port=80 --server.address=0.0.0.0

View File

@ -33,3 +33,19 @@
.st-d7 , .st-d6 ,.st-d5 ,.st-d4 { .st-d7 , .st-d6 ,.st-d5 ,.st-d4 {
border-color: #fcbb2e; border-color: #fcbb2e;
} }
.st-emotion-cache-1gwvy71{
padding: 0;
padding-left: 30px;
}
.e1f1d6gn4 > .stButton > button{
width: 100%;
justify-content: left;
border: 0;
}
[data-testid="baseButton-secondary"]:focus{
background-color: #f4f3f366 !important;
}
[data-testid="baseButton-secondary"]:active{
background-color: #f4f3f366!important;
}