Files
projet_gestion_commande/scripts/import_clients.py
T
2026-04-21 09:23:43 +02:00

180 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Import clients depuis data.txt (format psql pipe-séparé) vers PostgreSQL.
Usage : python3 import_clients.py [--dry-run]
"""
import os
import sys
import psycopg2
# ── Connexion ──────────────────────────────────────────────────────────────────
DB_CONFIG = {
"host": "localhost",
"port": 5432,
"user": "",
"password": "",
"dbname": "",
}
DATA_FILE = os.path.join(os.path.dirname(__file__), "data.txt")
DRY_RUN = "--dry-run" in sys.argv
# ── Ordre des colonnes dans data.txt (DB production, construite incrémentalement)
# None = colonne inconnue/obsolète à ignorer
SOURCE_COLUMNS = [
"id",
"username",
"password",
"nom",
"prenom",
"telephone",
"command",
"amende",
"cancel_commande",
"referral_balance", # position 9 : NUMERIC(10,2) → "0.00"
"cancellations_count", # position 10 : INTEGER → "0"
None, # position 11 : colonne obsolète/inconnue, ignorée
"last_penalty_reason", # position 12 : TEXT
"updated_at",
"created_at",
"must_change_password", # position 15 : BOOLEAN → "f"/"t"
]
def parse_value(v: str):
"""Convertit une valeur brute psql en type Python (None si vide)."""
v = v.strip()
if v == "" or v.lower() == "null":
return None
if v.lower() == "t":
return True
if v.lower() == "f":
return False
return v
def load_data(path: str) -> list[list]:
rows = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.rstrip("\n")
if not line.strip():
continue
# Lignes séparateur psql (ex: "----+----")
if (
set(
line.replace("|", "")
.replace("+", "")
.replace("-", "")
.replace(" ", "")
)
== set()
):
continue
parts = line.split("|")
values = (
[parse_value(p) for p in parts[:-1]]
if parts[-1].strip() == ""
else [parse_value(p) for p in parts]
)
if values:
rows.append(values)
return rows
def main():
rows = load_data(DATA_FILE)
if not rows:
print("❌ Aucune ligne trouvée dans data.txt")
sys.exit(1)
print(f"📂 {len(rows)} lignes lues depuis {DATA_FILE}")
data_col_count = len(rows[0])
print(
f"📋 Colonnes data.txt : {data_col_count} | SOURCE_COLUMNS définis : {len(SOURCE_COLUMNS)}"
)
if data_col_count != len(SOURCE_COLUMNS):
print(
f"⚠️ Ajuste SOURCE_COLUMNS dans le script ({len(SOURCE_COLUMNS)} définis, {data_col_count} dans le fichier)"
)
sys.exit(1)
# Colonnes à insérer (on filtre les None = colonnes ignorées)
insert_cols = [col for col in SOURCE_COLUMNS if col is not None and col != "id"]
# On conserve aussi l'id pour FORCE_ID
insert_cols_with_id = ["id"] + insert_cols
placeholders = ", ".join(["%s"] * len(insert_cols_with_id))
col_names = ", ".join(insert_cols_with_id)
update_expr = ", ".join(f"{c} = EXCLUDED.{c}" for c in insert_cols)
sql = f"""
INSERT INTO clients ({col_names})
VALUES ({placeholders})
ON CONFLICT (username) DO UPDATE SET {update_expr}
"""
conn = psycopg2.connect(**DB_CONFIG)
conn.autocommit = False
cur = conn.cursor()
inserted = 0
updated = 0
errors = 0
for i, row in enumerate(rows, 1):
# Construire un dict {col_name: value} depuis SOURCE_COLUMNS
row_dict = {}
for pos, col in enumerate(SOURCE_COLUMNS):
if col is None:
continue
row_dict[col] = row[pos] if pos < len(row) else None
values = [row_dict.get(c) for c in insert_cols_with_id]
username = row_dict.get("username", "?")
try:
if DRY_RUN:
print(f" [DRY-RUN] ligne {i} : {username}{row_dict}")
inserted += 1
continue
cur.execute("SELECT 1 FROM clients WHERE username = %s", (username,))
exists = cur.fetchone() is not None
cur.execute(sql, values)
if exists:
updated += 1
else:
inserted += 1
except Exception as e:
print(f" ❌ Erreur ligne {i} ({username}) : {e}")
conn.rollback()
errors += 1
continue
if not DRY_RUN:
cur.execute(
"SELECT setval('clients_id_seq', COALESCE((SELECT MAX(id) FROM clients), 1))"
)
conn.commit()
cur.close()
conn.close()
print(f"\n{'🔍 DRY-RUN — ' if DRY_RUN else ''}✅ Terminé")
print(f" Insérés : {inserted}")
print(f" Mis à jour : {updated}")
print(f" Erreurs : {errors}")
print(f" ️ Séquence clients_id_seq resynchronisée sur MAX(id)")
if __name__ == "__main__":
main()