import os import io import sqlite3 import re from datetime import datetime import pandas as pd from dotenv import load_dotenv from flask import Flask, request, render_template, redirect, url_for, flash, Response from werkzeug.utils import secure_filename env_path = "./.env" load_dotenv(env_path) UPLOAD_FOLDER = os.getenv("UPLOAD_FOLDER", "uploads") DATABASE = "data.db" ALLOWED_EXTENSIONS = {"xlsx"} app = Flask(__name__) app.config["UPLOAD_FOLDER"] = UPLOAD_FOLDER app.secret_key = "9f2a1d3e4c5b6a7d8e9f0a1b2c3d4e5f" @app.route("/clear_db", methods=["POST", "GET"]) def clear_db(): with sqlite3.connect(DATABASE) as conn: cursor = conn.cursor() cursor.execute("DELETE FROM onderhoud") conn.commit() flash("De database is geleegd!", "success") return redirect(url_for("debug_db")) 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": if "file" not in request.files: flash("Geen bestand geselecteerd", "danger") return redirect(request.url) file = request.files["file"] if file.filename == "": flash("Geen bestand geselecteerd", "danger") return redirect(request.url) if file and allowed_file(file.filename): filename = secure_filename(file.filename) 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") return redirect(url_for("upload_file")) return render_template("index.html") @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) def clean_column_name(name): # Vervangt alle niet-alfanumerieke tekens door "_" return re.sub(r"\W+", "_", name) def process_excel(filepath): # Controleer of de database bestaat if not os.path.exists(DATABASE): init_db() df = pd.read_excel(filepath) # Kolomnamen normaliseren df.columns = [clean_column_name(col) for col in df.columns] 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) # Debug: Controleer of de records echt zijn toegevoegd cursor.execute("SELECT COUNT(*) FROM onderhoud") count = cursor.fetchone()[0] print(f"Aantal records in de database: {count}") @app.route("/extrapolate", methods=["GET", "POST"]) def show_result(): today = datetime.today().strftime('%Y-%m-%d') x_str = request.form.get("selected_date") keuze_dagen_omrekenen = request.form.get( 'keuze_dagen_omrekenen', 'D') # Default is "D" (Dagen) if x_str: try: x = datetime.strptime(x_str, "%Y-%m-%d") except ValueError: flash("Ongeldige datum ingevoerd.", "danger") return redirect(url_for("upload_file")) # **Met datum -> gebruik extrapolatie** result = get_extrapolation(x, keuze_dagen_omrekenen) else: # **Zonder datum -> toon ruwe databasegegevens** 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() result = [dict(zip(columns, row)) for row in rows] # Zet om naar dicts voor weergave return render_template("resultaat.html", result=result, selected_date=x_str, today=today, keuze_dagen_omrekenen=keuze_dagen_omrekenen) def get_extrapolation(x, keuze_dagen_omrekenen): if x is None: return [] print(f"keuze {keuze_dagen_omrekenen}") today = datetime.today() 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() raw_data = [dict(zip(columns, row)) for row in rows] result = raw_data.copy() for row in raw_data: vervaldatum = row.get("Vervaldatum") uom = row.get("UOM") frequentie = row.get("Frequentie", 0) print(f"processing {vervaldatum} met {frequentie} uom{uom}") if vervaldatum: extrapolated_dates = extrapolate_vervaldatum( vervaldatum, uom, frequentie, x, keuze_dagen_omrekenen) if not extrapolated_dates: print( f"Geen extrapolatie-data voor vervaldatum: {vervaldatum}") else: print(f"Aantal extrapolaties: {len(extrapolated_dates)}") for i, date in enumerate(extrapolated_dates): new_row = row.copy() begindatum = pd.to_datetime(date) new_row["Overtijd"] = "Ja" if begindatum.date( ) <= today.date() else "Nee" new_row["Begindatum"] = date print(f"Added row: {date}") result.append(new_row) return remove_duplicates(result) # Dubbele records verwijderen def remove_duplicates(data, unique_keys=None): print("removing duplicates") if not data: return data if unique_keys is None: unique_keys = ["Object_code", "Begindatum", "PO_Code", "Object_omschrijving", "Omschrijving_PO", "Frequentie", "UOM"] seen = set() unique_data = [] for record in data: cleaned_record = {k: ("" if pd.isna(v) else v) for k, v in record.items()} if not cleaned_record.get("Begindatum"): continue key_tuple = tuple(cleaned_record.get(k, "") for k in unique_keys) if key_tuple not in seen: seen.add(key_tuple) unique_data.append(cleaned_record) return unique_data def extrapolate_vervaldatum(vervaldatum, uom, frequentie, x, keuze_dagen_omrekenen="D"): print(f"keuze {keuze_dagen_omrekenen}") 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": if keuze_dagen_omrekenen == "D": vervaldatum += pd.DateOffset(days=frequentie) elif keuze_dagen_omrekenen == "W": vervaldatum += pd.DateOffset(weeks=frequentie//7) elif keuze_dagen_omrekenen == "M": vervaldatum += pd.DateOffset(months=frequentie//30) # Als er nog restfrequentie is (zoals 28 dagen), voeg dan extra maand toe. if frequentie % 30 > 0: vervaldatum += pd.DateOffset(months=1) else: break # Onbekende keuze, stop de loop 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)