diff --git a/delfland/ppo-insight/data.db b/delfland/ppo-insight/data.db new file mode 100644 index 0000000..540ff0a Binary files /dev/null and b/delfland/ppo-insight/data.db differ diff --git a/delfland/ppo-insight/database.py b/delfland/ppo-insight/database.py deleted file mode 100644 index fb30e3a..0000000 --- a/delfland/ppo-insight/database.py +++ /dev/null @@ -1,18 +0,0 @@ -import mariadb -import os -from dotenv import load_dotenv - -# Configuratie laden uit .env-bestand -load_dotenv() - - -def get_db_connection(): - """Maakt een verbinding met de MariaDB-database en retourneert de cursor en verbinding.""" - conn = mariadb.connect( - host=os.getenv("DB_HOST"), - user=os.getenv("DB_USER"), - password=os.getenv("DB_PASSWORD"), - database=os.getenv("DB_NAME"), - port=int(os.getenv("DB_PORT")) - ) - return conn, conn.cursor() diff --git a/delfland/ppo-insight/ppo_insight.py b/delfland/ppo-insight/ppo_insight.py index fc26d50..0d31b3d 100644 --- a/delfland/ppo-insight/ppo_insight.py +++ b/delfland/ppo-insight/ppo_insight.py @@ -1,5 +1,7 @@ import os import io +import sqlite3 +import re from datetime import datetime import pandas as pd @@ -7,12 +9,11 @@ from dotenv import load_dotenv from flask import Flask, request, render_template, redirect, url_for, flash, Response from werkzeug.utils import secure_filename -from database import get_db_connection - env_path = "./.env" load_dotenv(env_path) -UPLOAD_FOLDER = os.getenv("UPLOAD_FOLDER") +UPLOAD_FOLDER = os.getenv("UPLOAD_FOLDER", "uploads") +DATABASE = "data.db" ALLOWED_EXTENSIONS = {"xlsx"} app = Flask(__name__) @@ -20,10 +21,74 @@ app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER app.secret_key = "9f2a1d3e4c5b6a7d8e9f0a1b2c3d4e5f" +def init_db(): + with sqlite3.connect(DATABASE) as conn: + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS onderhoud ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + Object_code TEXT, + Object_omschrijving TEXT, + Afdeling_object TEXT, + PO_Code TEXT, + Omschrijving_PO TEXT, + Vervaldatum TEXT, + Frequentie INTEGER, + UOM TEXT, + PO_schema_Niet_gebruikt TEXT, + Cluster TEXT, + Locatie TEXT, + Locatie_omschrijving TEXT, + Klasse_object TEXT, + Categorie TEXT + ) + """) + conn.commit() + + def allowed_file(filename): return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS +@app.route("/download", methods=["GET"]) +def download_excel(): + x_str = request.args.get("x") + if not x_str: + flash("Geen datum opgegeven voor download.", "danger") + return redirect(url_for("upload_file")) + + try: + x = datetime.strptime(x_str, "%Y-%m-%d") + except ValueError: + flash("Ongeldige datum opgegeven.", "danger") + return redirect(url_for("upload_file")) + + result = get_extrapolation(x) + + if not result: + flash("Geen resultaten beschikbaar voor de geselecteerde datum.", "warning") + return redirect(url_for("upload_file")) + + df = pd.DataFrame(result) + + # Verwijder de Vervaldatum kolom + if 'Vervaldatum' in df.columns: + df = df.drop(columns=['Vervaldatum']) + # df.rename(columns={"Begindatum": "Vervaldatum"}, inplace=True) + output = io.BytesIO() + with pd.ExcelWriter(output, engine="openpyxl") as writer: + df.to_excel(writer, index=False, + sheet_name=f"Extrapolatie_{x.strftime('%Y-%m-%d')}") + output.seek(0) + + filename = f"extrapolatie_{x.strftime('%Y-%m-%d')}.xlsx" + return Response( + output, + mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + headers={"Content-Disposition": f"attachment; filename={filename}"} + ) + + @app.route("/", methods=["GET", "POST"]) def upload_file(): if request.method == "POST": @@ -41,102 +106,77 @@ def upload_file(): filepath = os.path.join(app.config["UPLOAD_FOLDER"], filename) file.save(filepath) process_excel(filepath) - flash( - "Bestand geüpload en verwerkt! Bekijk de resultaten", - "success", - ) + flash("Bestand geüpload en verwerkt! Bekijk de resultaten", "success") return redirect(url_for("upload_file")) return render_template("index.html") -@app.route("/extrapolate", methods=["GET", "POST"]) -def show_result(): - x_str = request.form.get("selected_date") - print(x_str) - try: - if x_str is not None: - x = datetime.strptime(x_str, "%Y-%m-%d") - else: - # Handle the case where x_str is None, for example: - x = None # or raise an exception or use a default date - flash("Ongeldige datum ingevoerd.", "danger") - except ValueError: - flash("Ongeldige datum ingevoerd.", "danger") - return redirect(url_for("upload_file")) - - result = getextrapolation(x) - return render_template("resultaat.html", result=result, selected_date=x_str) +@app.route("/debug_db", methods=["GET"]) +def debug_db(): + with sqlite3.connect(DATABASE) as conn: + cursor = conn.cursor() + cursor.execute("SELECT * FROM onderhoud") + columns = [desc[0] for desc in cursor.description] + rows = cursor.fetchall() + return render_template("debug.html", columns=columns, rows=rows) -@app.route("/download", methods=["GET"]) -def download_excel(): - x_str = request.args.get("x") - x = datetime.strptime(x_str, "%Y-%m-%d") - result = getextrapolation(x) - - df = pd.DataFrame(result) - output = io.BytesIO() - with pd.ExcelWriter(output, engine="openpyxl") as writer: - df.to_excel(writer, index=False, - sheet_name=f"Extrapolatie_{x.strftime('%Y-%m-%d')}") - output.seek(0) - filename = f"extrapolatie_{x.strftime('%Y-%m-%d')}.xlsx" - return Response( - output, - mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - headers={"Content-Disposition": f"attachment; filename={filename}"}, - ) +def clean_column_name(name): + # Vervangt alle niet-alfanumerieke tekens door "_" + return re.sub(r"\W+", "_", name) -def extrapolate_vervaldatum(vervaldatum, uom, frequentie, x): - if vervaldatum is None or pd.isna(vervaldatum): - print("Ongeldige vervaldatum:", vervaldatum) - return [] # Geef een lege lijst terug in plaats van een fout te veroorzaken +def process_excel(filepath): + df = pd.read_excel(filepath) + # Kolomnamen normaliseren + df.columns = [clean_column_name(col) for col in df.columns] - vervaldatum = pd.to_datetime(str(vervaldatum), errors="coerce") + with sqlite3.connect(DATABASE) as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM onderhoud") # Leeg de tabel eerst + df.to_sql("onderhoud", conn, if_exists="append", index=False) - if pd.isna(vervaldatum): # Extra controle als de conversie mislukt - print("Kon datum niet omzetten:", vervaldatum) - return [] + # Debug: Controleer of de records echt zijn toegevoegd + cursor.execute("SELECT COUNT(*) FROM onderhoud") + count = cursor.fetchone()[0] + # Controleer of data correct is ingevoerd + print(f"Aantal records in de database: {count}") - result = [] - while vervaldatum <= x: - result.append(vervaldatum.strftime("%Y-%m-%d")) +@app.route("/extrapolate", methods=["GET", "POST"]) +def show_result(): + # Haal de huidige datum op voor de standaardwaarde + today = datetime.today().strftime('%Y-%m-%d') - if uom == "D": - vervaldatum += pd.DateOffset(days=frequentie) - elif uom == "W": - vervaldatum += pd.DateOffset(weeks=frequentie) - elif uom == "M": - vervaldatum += pd.DateOffset(months=frequentie) - elif uom == "Y": - vervaldatum += pd.DateOffset(years=frequentie) - else: - print("Onbekende eenheid:", uom) - break # Voorkom oneindige lus bij een onbekende eenheid + x_str = request.form.get("selected_date") + try: + x = datetime.strptime(x_str, "%Y-%m-%d") if x_str else datetime.today() + except ValueError: + flash("Ongeldige datum ingevoerd.", "danger") + return redirect(url_for("upload_file")) - return result + result = get_extrapolation(x) + return render_template("resultaat.html", result=result, selected_date=x_str, today=today) -def getextrapolation(x): +def get_extrapolation(x): if x is None: - print("Geen geldige datum opgegeven voor extrapolatie.") return [] - conn, cursor = get_db_connection() - cursor.execute(""" - SELECT Object_code, Object_omschrijving, Afdeling_object, PO_Code, Omschrijving_PO, Vervaldatum, Frequentie, UOM, - PO_schema_Niet_gebruikt, Cluster, Locatie, Locatie_omschrijving, Klasse_object, Categorie - FROM onderhoud - """) - - columns = [desc[0] for desc in cursor.description] - rows = cursor.fetchall() - cursor.close() - conn.close() + + today = datetime.today() + with sqlite3.connect(DATABASE) as conn: + cursor = conn.cursor() + cursor.execute(""" + SELECT Object_code, Object_omschrijving, Afdeling_object, PO_Code, Omschrijving_PO, + Vervaldatum, Frequentie, UOM, PO_schema_Niet_gebruikt, Cluster, Locatie, + Locatie_omschrijving, Klasse_object, Categorie + FROM onderhoud + """) + columns = [desc[0] for desc in cursor.description] + rows = cursor.fetchall() raw_data = [dict(zip(columns, row)) for row in rows] result = [] @@ -149,14 +189,51 @@ def getextrapolation(x): if vervaldatum: extrapolated_dates = extrapolate_vervaldatum( vervaldatum, uom, frequentie, x) - for date in extrapolated_dates: + for i, date in enumerate(extrapolated_dates): new_row = row.copy() - new_row["Vervaldatum"] = date + begindatum = pd.to_datetime(date) + if begindatum <= today: + new_row["Overtijd"] = "Ja" + else: + new_row["Overtijd"] = "Nee" + new_row["Begindatum"] = date + + if i == 0: + new_row["Parent"] = "*" + else: + new_row["Parent"] = "" + result.append(new_row) return result +def extrapolate_vervaldatum(vervaldatum, uom, frequentie, x): + vervaldatum = pd.to_datetime(str(vervaldatum), errors="coerce") + if pd.isna(vervaldatum): + return [] + + result = [] + while vervaldatum <= x: + result.append(vervaldatum.strftime("%Y-%m-%d")) + if uom == "D": + vervaldatum += pd.DateOffset(days=frequentie) + # vervaldatum += pd.DateOffset(weeks=frequentie // 7) + # vervaldatum += pd.DateOffset(months=frequentie // 30) + elif uom == "W": + vervaldatum += pd.DateOffset(weeks=frequentie) + elif uom == "M": + vervaldatum += pd.DateOffset(months=frequentie) + elif uom == "Y": + vervaldatum += pd.DateOffset(years=frequentie) + else: + break + if vervaldatum > x: + break + return result + + if __name__ == "__main__": os.makedirs(UPLOAD_FOLDER, exist_ok=True) + init_db() app.run(debug=True) diff --git a/delfland/ppo-insight/templates/debug.html b/delfland/ppo-insight/templates/debug.html new file mode 100644 index 0000000..b7dcf15 --- /dev/null +++ b/delfland/ppo-insight/templates/debug.html @@ -0,0 +1,39 @@ + + + + + + Database Debug + + + +

Onderhoud Database Debug

+ {% if rows %} + + + + {% for col in columns %} + + {% endfor %} + + + + {% for row in rows %} + + {% for value in row %} + + {% endfor %} + + {% endfor %} + +
{{ col }}
{{ value }}
+ {% else %} +

Geen records gevonden in de database.

+ {% endif %} + + diff --git a/delfland/ppo-insight/templates/resultaat.html b/delfland/ppo-insight/templates/resultaat.html index 16a951a..6486c6d 100644 --- a/delfland/ppo-insight/templates/resultaat.html +++ b/delfland/ppo-insight/templates/resultaat.html @@ -20,8 +20,9 @@ Terug naar upload
- - + + +
@@ -35,7 +36,7 @@ Afdeling_object PO_Code Omschrijving_PO - Vervaldatum + Begindatum Frequentie UOM PO_schema_Niet_gebruikt @@ -49,13 +50,14 @@ {% for row in result %} - + {{ row['Object_code'] }} {{ row['Object_omschrijving'] }} {{ row['Afdeling_object'] }} {{ row['PO_Code'] }} {{ row['Omschrijving_PO'] }} - {{ row['Vervaldatum'] }} + {{ row['Begindatum'] }} {{ row['Frequentie'] }} {{ row['UOM'] }} {{ row['PO_schema_Niet_gebruikt'] }} diff --git a/delfland/ppo-insight/uploads/Preventief_onderhoud_WK_dump_1.xlsx b/delfland/ppo-insight/uploads/Preventief_onderhoud_WK_dump_1.xlsx new file mode 100644 index 0000000..e53539e Binary files /dev/null and b/delfland/ppo-insight/uploads/Preventief_onderhoud_WK_dump_1.xlsx differ