Compare commits

..

13 Commits

Author SHA1 Message Date
sebastian.serfling aeee08c4c9 Merge branch 'main' of https://gitlab.stines.de/sebastian.serfling/Reports-Visual 2024-09-02 07:44:54 +00:00
root 000f698f98 add dockerfile 2024-09-02 07:38:06 +00:00
sebastianserfling 379998a459 Change EXPORT PORT 80 2024-08-29 10:14:17 +02:00
sebastianserfling b6093780a4 Change EXPORT PORT 80 2024-08-29 10:11:10 +02:00
sebastianserfling ab5965cb13 Fixed app.py 2024-08-29 10:03:02 +02:00
sebastianserfling 89de7ab364 requirements.txt add 2024-08-29 09:57:15 +02:00
sebastianserfling 110f9d705b ADD Dockerfile 2024-08-29 09:50:21 +02:00
sebastian.serfling 64c7793b4e add Ticket Export as APP 2024-08-21 17:35:08 +02:00
sebastian.serfling 47100302ee add Server page 2024-08-15 12:36:53 +02:00
sebastian.serfling 28a95748a3 change Folder name pages to sites 2024-08-15 11:38:17 +02:00
sebastian.serfling f705131322 change daly Reporting to Month, set use date to month 2024-08-15 11:33:46 +02:00
sebastian.serfling 59b7575c53 add %Y-%m-%d to select 2024-08-15 08:38:34 +02:00
sebastian.serfling f3383bbc40 add %Y-%m-%d to select 2024-08-15 08:36:30 +02:00
13 changed files with 867 additions and 54 deletions
+8
View File
@@ -3,3 +3,11 @@ MYSQL_USER="root"
MYSQL_PASSWORD="N53yBCswuawzBzS445VNAhWVMs3N59Gb9szEsrzXRBzarDqpdETpQeyt5v5CGe" MYSQL_PASSWORD="N53yBCswuawzBzS445VNAhWVMs3N59Gb9szEsrzXRBzarDqpdETpQeyt5v5CGe"
MYSQL_DATABASE="Kunden" MYSQL_DATABASE="Kunden"
MYSQL_AUTH='mysql_native_password' MYSQL_AUTH='mysql_native_password'
## Ticketsystem
ZAMMAD_URL = "https://ticket.stines.de/api/v1"
ZAMMAD_API_TOKEN ="1v4XGY7cZpBXSfb4s_tIBbywQjcaDV6q65IXQyVXrrBDqVtmAtLxM5tOqIAp0VXZ"
## API-Server
API_SERVER = "http://api.stines.de:8001"
API_TOKEN = "^YWUbG7yX*V!tV^KBSd*2c&vdN3wV9a2i7f3hfGFMBYFxi6#mMiJGiaA5KEHE%B*miK%qb7rQ67gmcYP@gqmux8"
+2
View File
@@ -5,3 +5,5 @@ backgroundColor="#2c3e50"
secondaryBackgroundColor="#34495e" secondaryBackgroundColor="#34495e"
textColor="#ffffff" textColor="#ffffff"
font="sans serif" font="sans serif"
layout="wide"
+52
View File
@@ -0,0 +1,52 @@
import streamlit as st
import sites.services_reporting as sr
import sites.userlist as us
import sites.server as s
import sites.tickets as ti
import sites.lastrun as lr
# Page Settings
st.set_page_config(page_title="Reporting",layout="wide")
# Load custom CSS
def load_css(file_name):
with open(file_name) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
load_css('style.css')
# Define page functions
def home():
st.title("Home Page")
st.write("Welcome to the Home Page!")
if 'page' not in st.session_state:
st.session_state.page = 'Home'
# 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()
elif st.session_state.page == 'Services Reporting':
sr.services_reporting()
elif st.session_state.page == 'User Filter':
us.user_filter()
elif st.session_state.page == 'Server':
s.server_filter()
elif st.session_state.page == 'Tickets':
ti.ticket_filter()
elif st.session_state.page == 'Last-Run':
lr.user_filter()
+13
View File
@@ -0,0 +1,13 @@
MYSQL_HOST="172.17.1.21"
MYSQL_USER="root"
MYSQL_PASSWORD="N53yBCswuawzBzS445VNAhWVMs3N59Gb9szEsrzXRBzarDqpdETpQeyt5v5CGe"
MYSQL_DATABASE="Kunden"
MYSQL_AUTH='mysql_native_password'
## Ticketsystem
ZAMMAD_URL = "https://ticket.stines.de/api/v1"
ZAMMAD_API_TOKEN ="1v4XGY7cZpBXSfb4s_tIBbywQjcaDV6q65IXQyVXrrBDqVtmAtLxM5tOqIAp0VXZ"
## API-Server
API_SERVER = "http://api.stines.de:8001"
API_TOKEN = "^YWUbG7yX*V!tV^KBSd*2c&vdN3wV9a2i7f3hfGFMBYFxi6#mMiJGiaA5KEHE%B*miK%qb7rQ67gmcYP@gqmux8"
+278
View File
@@ -0,0 +1,278 @@
import mysql.connector
from docx import Document
from datetime import datetime
from docx.shared import Pt
from docx.oxml.ns import qn
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.oxml import OxmlElement
import os
from datetime import datetime, timedelta
from dotenv import load_dotenv
from dateutil.relativedelta import relativedelta
load_dotenv()
def fetch_tickets_from_database():
# Verbindung zur Datenbank herstellen
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
cursor = mydb.cursor()
# Tickets abrufen, inklusive customer_ID
cursor.execute("""
SELECT t.`number`, t.title, t.createdate, t.`type`, t.customer_ID, tct.firstdate, t.time, s.price, t.service_ID
FROM Kunden.tickets t
JOIN Kunden.`tickets.customer.timerange` tct ON t.customer_ID = tct.customer_ID
JOIN Kunden.services s ON s.service_ID = t.service_ID
ORDER by t.createdate ASC
""")
tickets = cursor.fetchall()
mydb.close()
return tickets
def fetch_customer_data(customer_id):
# Verbindung zur Datenbank herstellen
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
cursor = mydb.cursor()
# Kundendaten basierend auf customer_ID abrufen
cursor.execute("""SELECT co.companyname, co.street,co.housenumber, co.postcode, co.city, c.customer FROM company co
JOIN customers c ON c.customer_ID = co.customer_ID
WHERE co.customer_id = %s""", (customer_id,))
customer_data = cursor.fetchone()
mydb.close()
return customer_data
def fetch_customer_servicetime(customer_id):
# Verbindung zur Datenbank herstellen
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
cursor = mydb.cursor()
# Kundendaten basierend auf customer_ID abrufen
cursor.execute("""SELECT servicetime FROM `tickets.customers.servicetime`
WHERE customer_id = %s""", (customer_id,))
customer_servicetime = cursor.fetchone()
mydb.close()
return customer_servicetime
def fetch_customer_price(price, customer_ID, service_ID):
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
cursor = mydb.cursor()
# Prozentwert aus der Datenbank abrufen
cursor.execute(f"""SELECT percent FROM `customers.pricechange`
WHERE customer_ID = {customer_ID} and service_ID = {service_ID}""")
customer_price_percent = cursor.fetchone()
mydb.close()
# Preis in Minuten umrechnen (da der aktuelle Preis in Stunden angegeben ist)
price_per_minute = price / 60 # Umrechnung von Stunden auf Minuten
# Falls ein Prozentwert existiert, diesen auf den Minutenpreis anwenden
if customer_price_percent:
price_per_minute += price_per_minute * (customer_price_percent[0] / 100)
# print(f"Preis pro Minute nach Aufschlag von {customer_price_percent[0]}%: {price_per_minute:.2f} €")
else:
print(f"Standard Preis pro Minute: {price_per_minute:.2f}")
return price_per_minute
def replace_text_in_run_with_format(run, key, value):
if f"{{{key}}}" in run.text:
run.text = run.text.replace(f"{{{key}}}", str(value))
run.font.name = 'Verdana'
run.font.size = Pt(10)
run.font.bold = False
run.font.italic = False
def insert_page_break(paragraph):
run = paragraph.add_run()
run.add_break(WD_BREAK.PAGE)
def replace_text_in_paragraph(paragraph, key, value):
for run in paragraph.runs:
replace_text_in_run_with_format(run, key, value)
def set_cell_border(cell, **kwargs):
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
borders = OxmlElement('w:tcBorders')
for border_name in ["top", "left", "bottom", "right"]:
border = kwargs.get(border_name, None)
if border:
element = OxmlElement(f"w:{border_name}")
element.set(qn("w:val"), border.get("val", "single"))
element.set(qn("w:sz"), border.get("sz", "4"))
element.set(qn("w:space"), border.get("space", "0"))
element.set(qn("w:color"), border.get("color", "000000"))
borders.append(element)
tcPr.append(borders)
def fill_template(doc_path, output_path, data, tickets):
doc = Document(doc_path)
# Platzhalter in normalem Text ersetzen
for paragraph in doc.paragraphs:
for key, value in data.items():
if f"{{{key}}}" in paragraph.text:
replace_text_in_paragraph(paragraph, key, value)
if "{page_breaker}" in paragraph.text:
if len(tickets) >= 7:
paragraph.text = paragraph.text.replace("{page_breaker}", "")
insert_page_break(paragraph)
else:
paragraph.text = paragraph.text.replace("{page_breaker}", "")
# Platzhalter in der ersten Tabelle ersetzen
first_table = doc.tables[0]
for row in first_table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
for key, value in data.items():
replace_text_in_paragraph(paragraph, key, value)
# Bearbeiten der zweiten Tabelle für Ticketdaten
second_table = doc.tables[1]
for ticket in tickets:
row = second_table.add_row()
row.cells[0].text = ticket[0] # Ticketnummer
row.cells[1].text = ticket[1] # Tickettitel
row.cells[2].text = ticket[2].strftime("%d.%m.%Y") # createdate als String formatieren
row.cells[3].text = str(ticket[6]) # timerange (time_unit)
# Formatierung und Ausrichtung für jede Zelle der neuen Zeile setzen
for idx, cell in enumerate(row.cells):
for paragraph in cell.paragraphs:
if idx == 1:
paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
else:
paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
for run in paragraph.runs:
run.font.name = 'Verdana'
run.font.size = Pt(10)
run.font.bold = False
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
set_cell_border(cell, top={"val": "single", "sz": "4", "color": "000000"},
bottom={"val": "single", "sz": "4", "color": "000000"},
left={"val": "single", "sz": "4", "color": "000000"},
right={"val": "single", "sz": "4", "color": "000000"})
# Berechnungen (z.B. Gesamtzeit, Preise)
gesamt_time_unit = sum(int(ticket[6]) for ticket in tickets)
data['gesamt_time_unit'] = gesamt_time_unit
# Zeit größer als Servicetime
if gesamt_time_unit >= customer_servicetime[0]:
data['sl_time_unit'] = gesamt_time_unit + customer_servicetime[0]
data['sl_minus_unit'] = gesamt_time_unit - customer_servicetime[0]
data['time_unit_sum'] = gesamt_time_unit + data['zl_time_unit']
data['price_per_minute'] = customer_price
data['price_ex_mwst'] = gesamt_time_unit * data['price_per_minute']
data['mwst_set'] = data['price_ex_mwst'] * 0.19
data['sum'] = data['price_ex_mwst'] + data['mwst_set']
data['price_ex_mwst'] = f"{data['price_ex_mwst']:.2f}".replace(".",",")
data['mwst_set'] = f"{data['mwst_set']:.2f}".replace(".",",")
data['sum'] = f"{data['sum']:.2f}".replace(".",",")
# Platzhalter in der dritten Tabelle ersetzen
third_table = doc.tables[2]
for row in third_table.rows:
for cell in row.cells:
for paragraph in cell.paragraphs:
for key, value in data.items():
if key == "sum":
# Setze den Text und mache ihn fett
for run in paragraph.runs:
if f"{{{key}}}" in run.text:
run.text = run.text.replace(f"{{{key}}}", str(value))
run.font.bold = True # Fett setzen
else:
replace_text_in_paragraph(paragraph, key, value)
doc.save(output_path)
# Hauptprogramm
if __name__ == "__main__":
tickets = fetch_tickets_from_database()
service_ID = next(iter(set(ticket[8] for ticket in tickets)))
price = next(iter(set(ticket[7] for ticket in tickets)))
customer_ids = set(ticket[4] for ticket in tickets)
for customer_id in customer_ids:
customer_data = fetch_customer_data(customer_id)
customer_servicetime = fetch_customer_servicetime(customer_id)
customer_price = fetch_customer_price(price, customer_id, service_ID)
customer_tickets = [ticket for ticket in tickets if ticket[4] == customer_id]
if not customer_data:
print(f"Keine Kundendaten für Kunden-ID {customer_id} gefunden!")
continue
day = customer_tickets[0][5]
now = datetime.now()
if now.month == 1:
last_month = 12
year = now.year - 1
else:
last_month = now.month - 1
year = now.year
startdate = datetime(year, last_month, day)
enddate = startdate + relativedelta(months=1) - timedelta(days=1)
data = {
"name": customer_data[0],
"street": customer_data[1],
"housenumber": customer_data[2],
"postcode": customer_data[3],
"city": customer_data[4],
"customernumber": customer_data[5],
"year": datetime.now().year,
"ordernumber": "0001",
"startdate": startdate.strftime("%d.%m.%Y"),
"enddate": enddate.strftime("%d.%m.%Y"),
"today": datetime.now().strftime("%d.%m.%Y"),
"price_per_minute": customer_price,
"servicetime": customer_servicetime[0],
"gesamt_time_unit": 0,
"price_ex_mwst": 0,
"sl_time_unit": 0,
"sl_minus_unit": 0,
"zl_time_unit": 0,
"time_unit_sum": 0,
"mwst_set": 0,
"sum": 0,
}
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)
print("True")
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
FROM python:3.9-slim
WORKDIR /app
RUN apt-get update && apt-get install -y \
build-essential \
curl \
software-properties-common \
git \
&& rm -rf /var/lib/apt/lists/*
RUN git clone https://gitlab.stines.de/sebastian.serfling/Reports-Visual.git .
RUN pip3 install -r requirements.txt
EXPOSE 80
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
+5
View File
@@ -0,0 +1,5 @@
mysql-connector-python~=9.0.0
python-dotenv~=1.0.1
python-dateutil~=2.9.0.post0
streamlit~=1.37.1
pandas~=2.2.2
+94
View File
@@ -0,0 +1,94 @@
import streamlit as st
import pandas as pd
import mysql.connector
from datetime import datetime
import os
from dotenv import load_dotenv
load_dotenv()
def get_filtered_users(customer_id, service_id):
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 * FROM Kunden.`services.reporting` where DATE(reportingdate) = CURDATE() """
if customer_id:
query += f"AND customer_ID = {customer_id}"
if service_id:
query += f" AND service_ID = {service_id}"
query += " ORDER BY reportingdate DESC"
users = pd.read_sql_query(query, mydb)
print(query)
mydb.close()
return users
def get_initial_data():
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
# Fetch unique service IDs and names
service_id_query = """
SELECT DISTINCT s.service_ID, s.name
FROM Kunden.services s
"""
service_ids = pd.read_sql_query(service_id_query, mydb)
# Fetch customer information
customer_query = """
SELECT DISTINCT c.customer_ID, c.customer, co.companyname
FROM Kunden.company co
JOIN Kunden.customers c ON co.customer_ID = c.customer_ID
"""
customers = pd.read_sql_query(customer_query, mydb)
mydb.close()
return service_ids, customers
def user_filter():
st.title("User Filter :mag_right:")
# Get initial data for widgets
initial_service_ids, customers = 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)
# Add selection widget for customer ID
selected_customer = st.selectbox(
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}",
axis=1).tolist()
)
# Extract customer_ID from selected option
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0])
# Add selection widget for service ID
selected_service = st.selectbox(
'Select Service',
["All"] + service_options.tolist()
)
# Extract service_ID from selected option
selected_service_id = None if selected_service == "All" else int(selected_service.split(' - ')[0])
# Add a button to apply filters
if st.button('Apply Filters'):
# Fetch filtered data from the database
filtered_data = get_filtered_users(selected_customer_id, selected_service_id)
# Display the filtered data
if not filtered_data.empty:
st.dataframe(filtered_data)
else:
st.write("No data available for the selected filters.")
+108
View File
@@ -0,0 +1,108 @@
import streamlit as st
import pandas as pd
import mysql.connector
from datetime import datetime
import os
from dotenv import load_dotenv
load_dotenv()
def get_filtered_server(customer_id, service_id, service_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")
)
# Prepare the base query
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
from Kunden.server s
join Kunden.`hardware.cpu` hc ON hc.cpu_ID = s.cpu_ID
WHERE 1=1
"""
if customer_id:
query += f"AND s.customer_ID = {customer_id}"
if service_id:
query += f" AND s.service_ID = {service_id}"
if service_status:
query += f" AND s.status = {service_status}"
users = pd.read_sql_query(query, mydb)
mydb.close()
return users
def get_initial_data():
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
# Fetch unique service IDs and names
service_id_query = """
SELECT DISTINCT s.service_ID, s.name
FROM Kunden.services s
"""
service_ids = pd.read_sql_query(service_id_query, mydb)
# Fetch customer information
customer_query = """
SELECT DISTINCT c.customer_ID, c.customer, co.companyname
FROM Kunden.company co
JOIN Kunden.customers c ON co.customer_ID = c.customer_ID
"""
customers = pd.read_sql_query(customer_query, mydb)
mydb.close()
return service_ids, customers
def server_filter():
st.title("Server Filter :mag_right:")
# Get initial data for widgets
initial_service_ids, customers = 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)
# Add selection widget for customer ID
selected_customer = st.selectbox(
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}",
axis=1).tolist()
)
# Extract customer_ID from selected option
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0])
# Add selection widget for service ID
selected_service = st.selectbox(
'Select Service',
["All"] + service_options.tolist()
)
# Extract service_ID from selected option
selected_service_id = None if selected_service == "All" else int(selected_service.split(' - ')[0])
# Add selection widget for service status
selected_status = st.selectbox(
'Select Service Status',
["All", "1 - Active", "0 - Inactive"]
)
# Extract status from selected option
service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0])
# Add a button to apply filters
if st.button('Apply Filters'):
# Fetch filtered data from the database
filtered_data = get_filtered_server(selected_customer_id, selected_service_id, service_status)
# Display the filtered data
if not filtered_data.empty:
st.dataframe(filtered_data)
else:
st.write("No data available for the selected filters.")
+15 -51
View File
@@ -1,25 +1,13 @@
import streamlit as st import streamlit as st
import pandas as pd import pandas as pd
import mysql.connector import mysql.connector
from datetime import datetime from datetime import datetime, date
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv() load_dotenv()
# Set Page Name
st.set_page_config(page_title="Reporting")
# Load custom CSS
def load_css(file_name):
with open(file_name) as f:
st.markdown(f'<style>{f.read()}</style>', unsafe_allow_html=True)
load_css('style.css')
# Function to get filtered data from the database
def get_filtered_data(customer_id, service_id, start_date, end_date): def get_filtered_data(customer_id, service_id, start_date, end_date):
mydb = mysql.connector.connect( mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"), host=os.getenv("MYSQL_HOST"),
@@ -48,7 +36,6 @@ def get_filtered_data(customer_id, service_id, start_date, end_date):
return service_reporting return service_reporting
# Fetch initial data for default selections
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"),
@@ -78,19 +65,15 @@ def get_initial_data():
date_query = """ date_query = """
SELECT MIN(reportingdate) AS min_date, MAX(reportingdate) AS max_date SELECT MIN(reportingdate) AS min_date, MAX(reportingdate) AS max_date
FROM Kunden.`services.reporting` FROM Kunden.`services.reporting`
WHERE customer_ID = 5
""" """
date_range = pd.read_sql_query(date_query, mydb) date_range = pd.read_sql_query(date_query, mydb)
mydb.close() mydb.close()
return service_ids, customers, date_range return service_ids, customers, date_range
def generate_month_range(min_date, max_date):
# Define page functions months = pd.date_range(start=min_date, end=max_date, freq='MS').strftime("%Y-%m").tolist()
def home(): return months
st.title("Home Page")
st.write("Welcome to the Home Page!")
def services_reporting(): def services_reporting():
st.title("Reporting :mag_right:") st.title("Reporting :mag_right:")
@@ -121,22 +104,22 @@ def services_reporting():
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]
# Add date range selection widget # Generate month options for dropdown
selected_date_range = st.date_input( month_options = generate_month_range(min_date, max_date)
'Select date range',
value=[min_date, max_date],
min_value=min_date,
max_value=max_date
)
# Format the selected dates as 'YYYY-MM-DD' # Add dropdown for start and end months
start_date_str = selected_date_range[0].strftime("%Y-%m-%d") start_month = st.selectbox('Start Month', month_options)
end_date_str = selected_date_range[1].strftime("%Y-%m-%d") 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 # 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_str, end_date_str) filtered_data = get_filtered_data(selected_customer_id, selected_service_id, start_date, end_date)
# Sort the data by month # Sort the data by month
filtered_data = filtered_data.sort_values('month') filtered_data = filtered_data.sort_values('month')
@@ -146,22 +129,3 @@ def services_reporting():
st.bar_chart(filtered_data.set_index('month')['count']) st.bar_chart(filtered_data.set_index('month')['count'])
else: else:
st.write("No data available for the selected filters.") st.write("No data available for the selected filters.")
if 'page' not in st.session_state:
st.session_state.page = 'Home'
# 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'
# Page display logic
if st.session_state.page == 'Home':
home()
elif st.session_state.page == 'Services Reporting':
services_reporting()
+152
View File
@@ -0,0 +1,152 @@
import streamlit as st
import pandas as pd
import subprocess
import mysql.connector
from datetime import datetime, timedelta
import os
from dotenv import load_dotenv
load_dotenv()
total_time_unit = []
def get_filtered_users(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")
)
# Prepare the base query with date filter
query = f"""
SELECT number, title, createdate, time FROM Kunden.tickets
WHERE createdate BETWEEN '{start_date}' AND '{end_date}'
"""
if customer_id:
query += f" AND customer_ID = {customer_id}"
query += " ORDER BY createdate"
users = pd.read_sql_query(query, mydb)
mydb.close()
# Format date columns
for column in users.select_dtypes(include=['datetime64[ns]', 'datetime64[ns, UTC]']).columns:
users[column] = users[column].dt.strftime('%d.%m.%Y')
# Convert 'time' to integer
users.iloc[:, 3] = users.iloc[:, 3].str.split('.').str[0]
users['time'] = users['time'].astype(int)
# Create hyperlink for ticket number
base_url = "https://ticket.stines.de/#ticket/zoom/number/"
users['Link'] = users['number'].apply(lambda x: f'<a href="{base_url}{x}" target="_blank">{x}</a>')
return users
def get_initial_data():
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
# Fetch unique service IDs and names
service_id_query = """
SELECT DISTINCT s.service_ID, s.name
FROM Kunden.services s
"""
service_ids = pd.read_sql_query(service_id_query, mydb)
# Fetch customer information
customer_query = """
SELECT DISTINCT c.customer_ID, c.customer, co.companyname
FROM Kunden.company co
JOIN Kunden.customers c ON co.customer_ID = c.customer_ID
"""
customers = pd.read_sql_query(customer_query, mydb)
mydb.close()
return service_ids, customers
def run_script_and_list_documents():
output_area = st.empty() # Placeholder for output
document_paths = [] # List to store generated document paths
# Directory where the script should be run
working_directory = "apps/ticket_export/exports"
# Run the script in the specified directory
result = subprocess.run(
["python3", "apps/ticket_export/main.py"],
capture_output=True,
text=True
)
# Search for generated documents in the working directory
for filename in os.listdir(working_directory):
if filename.endswith(".docx"):
full_path = os.path.join(working_directory, filename)
document_paths.append(full_path)
# Display the list of generated documents and offer them for download
if document_paths:
st.write("Generated Documents:")
for doc_path in document_paths:
with open(doc_path, "rb") as file:
st.download_button(
label=f"Download {os.path.basename(doc_path)}",
data=file,
file_name=os.path.basename(doc_path),
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)
else:
st.write("No documents found.")
def ticket_filter():
st.title("Ticket Filter :mag_right:")
# Get initial data for widgets
initial_service_ids, customers = get_initial_data()
# Add selection widget for customer ID
selected_customer = st.selectbox(
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}",
axis=1).tolist()
)
# Extract customer_ID from selected option
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0])
# Add date range picker
start_date = st.date_input("Start Date", datetime.now() - timedelta(days=30))
end_date = st.date_input("End Date", datetime.now())
if st.button("Create Invoice"):
st.write("Running the script...")
run_script_and_list_documents()
# Add a button to apply filters
if st.button('Apply Filters'):
if start_date > end_date:
st.error("Error: End date must be greater than or equal to start date.")
else:
# Fetch filtered data from the database
filtered_data = get_filtered_users(selected_customer_id, start_date, end_date)
if not filtered_data.empty:
st.markdown(filtered_data.to_html(escape=False), unsafe_allow_html=True)
# Convert DataFrame to CSV
csv = filtered_data.drop(columns=['Link']).to_csv(index=False)
st.write(f"Total Time Unit: {filtered_data['time'].sum()}")
# Create a download button with a custom file name
st.download_button(
label="Download CSV",
data=csv,
file_name=f"filtered_data_{selected_customer}.csv", # Custom file name
mime='text/csv',
)
else:
st.write("No data available for the selected filters.")
if __name__ == "__main__":
ticket_filter()
+116
View File
@@ -0,0 +1,116 @@
import streamlit as st
import pandas as pd
import mysql.connector
from datetime import datetime
import os
from dotenv import load_dotenv
load_dotenv()
def get_filtered_users(customer_id, service_id, service_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")
)
# Prepare the base query
query = f"""
SELECT us.user_id, u.username, s.service_ID, uss.status, uss.timestamp, c.companyname
FROM Kunden.`users.status` us
JOIN (
SELECT user_id, MAX(timestamp) AS latest_timestamp
FROM Kunden.`users.status`
GROUP BY user_id
) latest ON us.user_id = latest.user_id AND us.timestamp = latest.latest_timestamp
JOIN Kunden.users u ON u.user_ID = us.user_id
JOIN Kunden.`users.services` uss ON us.user_id = uss.user_id
JOIN Kunden.services s ON uss.service_ID = s.service_ID
JOIN Kunden.company c ON c.customer_ID = us.customer_ID
WHERE 1=1
"""
if customer_id:
query += f"AND us.customer_ID = {customer_id}"
if service_id:
query += f" AND s.service_ID = {service_id}"
if service_status:
query += f" AND uss.status = {service_status}"
query += " ORDER BY uss.status DESC"
users = pd.read_sql_query(query, mydb)
mydb.close()
return users
def get_initial_data():
mydb = mysql.connector.connect(
host=os.getenv("MYSQL_HOST"),
user=os.getenv("MYSQL_USER"),
password=os.getenv("MYSQL_PASSWORD"),
database=os.getenv("MYSQL_DATABASE")
)
# Fetch unique service IDs and names
service_id_query = """
SELECT DISTINCT s.service_ID, s.name
FROM Kunden.services s
"""
service_ids = pd.read_sql_query(service_id_query, mydb)
# Fetch customer information
customer_query = """
SELECT DISTINCT c.customer_ID, c.customer, co.companyname
FROM Kunden.company co
JOIN Kunden.customers c ON co.customer_ID = c.customer_ID
"""
customers = pd.read_sql_query(customer_query, mydb)
mydb.close()
return service_ids, customers
def user_filter():
st.title("User Filter :mag_right:")
# Get initial data for widgets
initial_service_ids, customers = 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)
# Add selection widget for customer ID
selected_customer = st.selectbox(
'Select Customer',
["All"] + customers.apply(lambda row: f"{row['customer_ID']} - {row['companyname']} - {row['customer']}",
axis=1).tolist()
)
# Extract customer_ID from selected option
selected_customer_id = None if selected_customer == "All" else int(selected_customer.split(' - ')[0])
# Add selection widget for service ID
selected_service = st.selectbox(
'Select Service',
["All"] + service_options.tolist()
)
# Extract service_ID from selected option
selected_service_id = None if selected_service == "All" else int(selected_service.split(' - ')[0])
# Add selection widget for service status
selected_status = st.selectbox(
'Select Service Status',
["All", "1 - Active", "0 - Inactive"]
)
# Extract status from selected option
service_status = None if selected_status == "All" else int(selected_status.split(' - ')[0])
# Add a button to apply filters
if st.button('Apply Filters'):
# Fetch filtered data from the database
filtered_data = get_filtered_users(selected_customer_id, selected_service_id, service_status)
# Display the filtered data
if not filtered_data.empty:
st.dataframe(filtered_data)
else:
st.write("No data available for the selected filters.")