#!/usr/bin/env python3 import sqlite3 import random from datetime import datetime, timedelta import math # Configuration de la base de données DB_PATH = 'database/sqdc.db' # Catégories CATEGORIES = [ {'id': 1, 'name': 'Sécurité', 'emoji': '🛡️', 'description': 'Indicateurs de sécurité et prévention des accidents'}, {'id': 2, 'name': 'Qualité', 'emoji': '🎯', 'description': 'Indicateurs de qualité des produits'}, {'id': 3, 'name': 'Délais & Livraison', 'emoji': '⏱️', 'description': 'Indicateurs de délais et livraison'}, {'id': 4, 'name': 'Coûts', 'emoji': '💰', 'description': 'Indicateurs de coûts de production'}, {'id': 5, 'name': 'Maintenance', 'emoji': '🔧', 'description': 'Indicateurs de maintenance'} ] # KPIs avec fréquences KPIS = [ # SÉCURITÉ (1 mesure par jour) {'id': 1, 'category_id': 1, 'name': 'Taux de Fréquence (TF)', 'unit': 'par 1M heures', 'target': 1.0, 'frequency': 'daily', 'formula': '(Nombre d\'Accidents avec Arrêt / Nombre d\'Heures Travaillées) × 1000000', 'description': 'Mesurer la fréquence des accidents avec arrêt.'}, {'id': 2, 'category_id': 1, 'name': 'Nombre d\'Incidents/Near Miss', 'unit': 'incidents', 'target': 8, 'frequency': 'daily', 'formula': 'Compte des rapports d\'incidents', 'description': 'Évaluer la culture de sécurité.'}, {'id': 3, 'category_id': 1, 'name': 'Taux de Conformité aux Audits', 'unit': '%', 'target': 95, 'frequency': 'weekly', 'formula': '(Points Conformes / Total Points) × 100', 'description': 'Mesurer le respect des procédures.'}, # QUALITÉ (toutes les 10 minutes) {'id': 4, 'category_id': 2, 'name': 'Taux de Rebut (Scrap Rate)', 'unit': '%', 'target': 1.5, 'frequency': 'per_10min', 'formula': '(Unités Rebutées / Unités Produites) × 100', 'description': 'Mesurer le % d\'unités jetées.'}, {'id': 5, 'category_id': 2, 'name': 'Taux de Retouche (Rework Rate)', 'unit': '%', 'target': 2.0, 'frequency': 'per_10min', 'formula': '(Unités Retouchées / Unités Totales) × 100', 'description': 'Mesurer le % d\'unités retouchées.'}, {'id': 6, 'category_id': 2, 'name': 'Nombre de Défauts par Unité (DPU)', 'unit': 'défauts/unité', 'target': 0.5, 'frequency': 'per_10min', 'formula': 'Défauts Totaux / Unités Inspectées', 'description': 'Mesurer le nombre moyen de défauts.'}, {'id': 7, 'category_id': 2, 'name': 'Taux de Retours Clients', 'unit': '%', 'target': 0.8, 'frequency': 'daily', 'formula': '(Unités Retournées / Unités Vendues) × 100', 'description': 'Mesurer l\'impact de la non-qualité.'}, {'id': 8, 'category_id': 2, 'name': 'Taux de rendement synthétique (TRS)', 'unit': '%', 'target': 85, 'frequency': 'per_30min', 'formula': 'Pièces bonnes × Temps cycle / Temps ouverture', 'description': 'Rendement global de la ligne.'}, {'id': 9, 'category_id': 2, 'name': 'Efficacité Globale de l\'Équipement (OEE)', 'unit': '%', 'target': 80, 'frequency': 'per_30min', 'formula': 'Disponibilité × Performance × Qualité', 'description': 'Mesurer l\'efficacité combinée.'}, # DÉLAIS (toutes les heures) {'id': 10, 'category_id': 3, 'name': 'Taux de Respect du Plan', 'unit': '%', 'target': 95, 'frequency': 'hourly', 'formula': '(Produite / Planifiée) × 100', 'description': 'Mesurer la capacité à atteindre le volume.'}, {'id': 11, 'category_id': 3, 'name': 'Temps de Cycle (Cycle Time)', 'unit': 'min/unité', 'target': 50, 'frequency': 'per_10min', 'formula': 'Temps Total / Nombre d\'Unités', 'description': 'Mesurer le temps par unité.'}, {'id': 12, 'category_id': 3, 'name': 'Tack Time', 'unit': 'min/unité', 'target': 50, 'frequency': 'per_10min', 'formula': 'Temps production / Pièces demandées', 'description': 'Temps de production requis par unité.'}, {'id': 13, 'category_id': 3, 'name': 'Temps d\'Arrêt Imprévu (Downtime)', 'unit': 'h/jour', 'target': 1.5, 'frequency': 'daily', 'formula': 'Somme des Arrêts Non Planifiés', 'description': 'Mesurer l\'arrêt non planifié.'}, # COÛTS (quotidiennement) {'id': 14, 'category_id': 4, 'name': 'Coût par Unité (CPU)', 'unit': '€', 'target': 240, 'frequency': 'daily', 'formula': 'Coût Total / Unités Produites', 'description': 'Mesurer l\'efficacité des coûts.'}, {'id': 15, 'category_id': 4, 'name': 'Productivité de la Main-d\'œuvre', 'unit': 'unités/h', 'target': 8.0, 'frequency': 'hourly', 'formula': 'Unités Produites / Heures Main-d\'œuvre', 'description': 'Mesurer l\'efficacité de l\'équipe.'}, {'id': 16, 'category_id': 4, 'name': 'Coût des Non-Qualité (CNQ)', 'unit': '€', 'target': 10000, 'frequency': 'daily', 'formula': 'Rebuts + Retouches + Retours', 'description': 'Mesurer le coût des défauts.'}, # MAINTENANCE (tous les 3 jours) {'id': 17, 'category_id': 5, 'name': 'Temps Moyen Entre Pannes (MTBF)', 'unit': 'heures', 'target': 400, 'frequency': 'per_3days', 'formula': 'Temps Fonctionnement / Pannes', 'description': 'Mesurer la fiabilité.'}, {'id': 18, 'category_id': 5, 'name': 'Temps Moyen de Réparation (MTTR)', 'unit': 'heures', 'target': 2.5, 'frequency': 'per_3days', 'formula': 'Temps Réparation / Pannes', 'description': 'Mesurer la rapidité.'}, {'id': 19, 'category_id': 5, 'name': 'Ratio Maintenance Préventive/Corrective', 'unit': '%', 'target': 70, 'frequency': 'weekly', 'formula': 'Heures MP / (MP + MC)', 'description': 'Évaluer la stratégie.'}, {'id': 20, 'category_id': 5, 'name': 'Taux d\'Achèvement du Plan Préventif', 'unit': '%', 'target': 95, 'frequency': 'weekly', 'formula': '(Tâches Terminées / Tâches Planifiées) × 100', 'description': 'Mesurer le respect du plan.'}, {'id': 21, 'category_id': 5, 'name': 'Coût de Maintenance par Unité Produite', 'unit': '€', 'target': 30, 'frequency': 'daily', 'formula': 'Coûts Maintenance / Unités Produites', 'description': 'Relier dépenses à production.'} ] def get_frequency_minutes(frequency): """Retourne le nombre de minutes entre les mesures""" frequencies = { 'per_10min': 10, 'per_30min': 30, 'hourly': 60, 'daily': 1440, # 24h 'weekly': 10080, # 7 jours 'per_3days': 4320 # 3 jours } return frequencies.get(frequency, 1440) def generate_value(kpi_id, target, variance_range=0.2): """Génère une valeur réaliste autour de la cible""" variance = (random.random() - 0.5) * 2 * variance_range value = target * (1 + variance) # Ajouter du bruit réaliste pour certains KPI if kpi_id in [4, 5, 6, 11, 12]: # Qualité et délais - plus de variabilité noise = (random.random() - 0.5) * 0.3 * target value += noise return max(0, round(value, 2)) def determine_status(kpi_id, value, target): """Détermine le statut (good, warning, critical)""" tolerance = abs(target * 0.1) # KPI où plus bas est mieux if kpi_id in [2, 4, 5, 6, 13, 16]: if value > target + tolerance * 2: return 'critical' elif value > target + tolerance: return 'warning' else: # KPI où plus haut est mieux if value < target - tolerance * 2: return 'critical' elif value < target - tolerance: return 'warning' return 'good' def populate_database(): """Remplit la base de données sur 1 an""" conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # Créer les tables d'abord print("🔄 Création du schéma...") cursor.execute(''' CREATE TABLE IF NOT EXISTS categories ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, emoji TEXT, description TEXT ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS kpis ( id INTEGER PRIMARY KEY, category_id INTEGER NOT NULL, name TEXT NOT NULL, unit TEXT, target REAL, frequency TEXT, formula TEXT, description TEXT, FOREIGN KEY(category_id) REFERENCES categories(id) ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS measurements ( id INTEGER PRIMARY KEY AUTOINCREMENT, kpi_id INTEGER NOT NULL, measurement_date DATETIME NOT NULL, value REAL NOT NULL, status TEXT, FOREIGN KEY(kpi_id) REFERENCES kpis(id) ) ''') cursor.execute(''' CREATE TABLE IF NOT EXISTS alerts ( id INTEGER PRIMARY KEY AUTOINCREMENT, kpi_id INTEGER NOT NULL, alert_type TEXT, severity TEXT, message TEXT, created_at DATETIME, FOREIGN KEY(kpi_id) REFERENCES kpis(id) ) ''') # Supprimer les anciennes données cursor.execute('DELETE FROM measurements') cursor.execute('DELETE FROM alerts') cursor.execute('DELETE FROM kpis') cursor.execute('DELETE FROM categories') # Insérer les catégories for cat in CATEGORIES: cursor.execute( 'INSERT INTO categories (id, name, emoji, description) VALUES (?, ?, ?, ?)', (cat['id'], cat['name'], cat['emoji'], cat['description']) ) # Insérer les KPI for kpi in KPIS: cursor.execute( 'INSERT INTO kpis (id, category_id, name, unit, target, frequency, formula, description) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', (kpi['id'], kpi['category_id'], kpi['name'], kpi['unit'], kpi['target'], kpi['frequency'], kpi['formula'], kpi['description']) ) # Générer les mesures sur 1 an end_date = datetime.now() start_date = end_date - timedelta(days=365) print("🔄 Génération des mesures sur 1 an...") measurements_count = 0 for kpi in KPIS: kpi_id = kpi['id'] target = kpi['target'] frequency_minutes = get_frequency_minutes(kpi['frequency']) current_date = start_date while current_date <= end_date: value = generate_value(kpi_id, target) status = determine_status(kpi_id, value, target) cursor.execute( 'INSERT INTO measurements (kpi_id, measurement_date, value, status) VALUES (?, ?, ?, ?)', (kpi_id, current_date.isoformat(), value, status) ) measurements_count += 1 current_date += timedelta(minutes=frequency_minutes) conn.commit() conn.close() print(f"✅ Base de données remplie avec succès!") print(f"📊 {measurements_count} mesures créées") print(f"🎯 {len(KPIS)} KPI configurés") print(f"📁 Fichier: {DB_PATH}") if __name__ == '__main__': populate_database()