first commit
This commit is contained in:
commit
e6c52820cd
227 changed files with 16156 additions and 0 deletions
172
modules/crm/handler.py
Normal file
172
modules/crm/handler.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
from datetime import date
|
||||
import os
|
||||
import json
|
||||
from .client import Client
|
||||
from core.data import Data
|
||||
|
||||
class ClientHandler:
|
||||
def __init__(self, clients_folder="Data/clients"):
|
||||
self.clients_folder = clients_folder
|
||||
self.clients = []
|
||||
self.load_clients()
|
||||
|
||||
def load_clients(self):
|
||||
"""Charge tous les clients depuis les fichiers existants"""
|
||||
self.clients = []
|
||||
# Charger les clients depuis les fichiers JSON existants
|
||||
if os.path.exists(self.clients_folder):
|
||||
for filename in os.listdir(self.clients_folder):
|
||||
if filename.endswith('.json'):
|
||||
client_path = os.path.join(self.clients_folder, filename)
|
||||
try:
|
||||
# Utiliser le gestionnaire de données pour charger le fichier JSON
|
||||
data_manager = Data(client_path)
|
||||
client_data = data_manager.load_data()
|
||||
|
||||
# Si le fichier a la structure d'un client, créer un objet Client
|
||||
if "client_name" in client_data:
|
||||
# Conversion du format existant vers le format Client
|
||||
client_obj = {
|
||||
"name": client_data.get("client_name", ""),
|
||||
"email": client_data.get("client_email", ""),
|
||||
"phone": client_data.get("client_phone", ""),
|
||||
"notes": client_data.get("additional_info", ""),
|
||||
"company": client_data.get("project_name", ""),
|
||||
"tags": [], # Pas de tags dans les données existantes
|
||||
"next_action": "", # Pas d'action suivante dans les données existantes
|
||||
"linked_docs": self._find_linked_docs(client_data.get("client_name", ""))
|
||||
}
|
||||
client = Client(**client_obj)
|
||||
self.clients.append(client)
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement du client {filename}: {e}")
|
||||
|
||||
return self.clients
|
||||
|
||||
def _find_linked_docs(self, client_name):
|
||||
"""Trouve les documents associés à un client"""
|
||||
linked_docs = {"devis": [], "propositions": [], "factures": []}
|
||||
client_name_normalized = client_name.replace(" ", "_").lower()
|
||||
|
||||
# Rechercher les devis
|
||||
devis_folder = "output/devis"
|
||||
if os.path.exists(devis_folder):
|
||||
for filename in os.listdir(devis_folder):
|
||||
if filename.startswith(client_name_normalized) and filename.endswith(".pdf"):
|
||||
linked_docs["devis"].append(os.path.join(devis_folder, filename))
|
||||
|
||||
# Rechercher les propositions
|
||||
propositions_folder = "output/propositions"
|
||||
if os.path.exists(propositions_folder):
|
||||
for filename in os.listdir(propositions_folder):
|
||||
if filename.startswith(client_name_normalized) and filename.endswith(".pdf"):
|
||||
linked_docs["propositions"].append(os.path.join(propositions_folder, filename))
|
||||
|
||||
# Rechercher les factures (si elles existent)
|
||||
factures_folder = "output/factures"
|
||||
if os.path.exists(factures_folder):
|
||||
for filename in os.listdir(factures_folder):
|
||||
if filename.startswith(client_name_normalized) and filename.endswith(".pdf"):
|
||||
linked_docs["factures"].append(os.path.join(factures_folder, filename))
|
||||
|
||||
return linked_docs
|
||||
|
||||
def get_all_clients(self):
|
||||
"""Retourne tous les clients"""
|
||||
return self.clients
|
||||
|
||||
def get_client_by_id(self, client_id):
|
||||
"""Retourne un client par son ID"""
|
||||
for client in self.clients:
|
||||
if client.id == client_id:
|
||||
return client
|
||||
return None
|
||||
|
||||
def get_client_by_name(self, client_name):
|
||||
"""Retourne un client par son nom"""
|
||||
for client in self.clients:
|
||||
if client.name.lower() == client_name.lower():
|
||||
return client
|
||||
return None
|
||||
|
||||
def add_client(self, client):
|
||||
"""Ajoute un nouveau client"""
|
||||
self.clients.append(client)
|
||||
# Sauvegarder le client dans un fichier JSON
|
||||
self._save_client(client)
|
||||
return client
|
||||
|
||||
def update_client(self, client):
|
||||
"""Met à jour un client existant"""
|
||||
for i, existing_client in enumerate(self.clients):
|
||||
if existing_client.id == client.id:
|
||||
self.clients[i] = client
|
||||
# Sauvegarder le client mis à jour
|
||||
self._save_client(client)
|
||||
return client
|
||||
return None
|
||||
|
||||
def delete_client(self, client_id):
|
||||
"""Supprime un client"""
|
||||
for i, client in enumerate(self.clients):
|
||||
if client.id == client_id:
|
||||
deleted_client = self.clients.pop(i)
|
||||
# Supprimer le fichier JSON du client
|
||||
client_file = os.path.join(self.clients_folder, f"{deleted_client.name.replace(' ', '_').lower()}.json")
|
||||
if os.path.exists(client_file):
|
||||
os.remove(client_file)
|
||||
return deleted_client
|
||||
return None
|
||||
|
||||
def _save_client(self, client):
|
||||
"""Sauvegarde un client dans un fichier JSON"""
|
||||
client_data = {
|
||||
"client_name": client.name,
|
||||
"client_email": client.email,
|
||||
"client_phone": client.phone,
|
||||
"additional_info": client.notes,
|
||||
"project_name": client.company,
|
||||
# Autres champs pour maintenir la compatibilité avec le format existant
|
||||
"project_type": "",
|
||||
"project_description": "",
|
||||
"features": [],
|
||||
"budget": "",
|
||||
"payment_terms": "",
|
||||
"contact_info": f"{client.name}, {client.phone}",
|
||||
"deadline": ""
|
||||
}
|
||||
|
||||
client_file = os.path.join(self.clients_folder, f"{client.name.replace(' ', '_').lower()}.json")
|
||||
data_manager = Data(client_file)
|
||||
data_manager.save_data(client_data)
|
||||
|
||||
return client_file
|
||||
|
||||
def add_task_for_client(self, client_id: str, title: str, due_date: str, description: str = "", priority: str = "normale", metadata: dict = None):
|
||||
"""
|
||||
Crée une tâche liée à un client.
|
||||
:param client_id: ID du client
|
||||
:param title: Titre de la tâche
|
||||
:param due_date: Date d'échéance au format ISO (YYYY-MM-DD)
|
||||
:param description: Description optionnelle
|
||||
:param priority: 'basse' | 'normale' | 'haute'
|
||||
:param metadata: métadonnées optionnelles
|
||||
:return: ID de la tâche créée ou None si client introuvable
|
||||
"""
|
||||
client = self.get_client_by_id(client_id)
|
||||
if not client:
|
||||
return None
|
||||
# Import local pour éviter dépendances circulaires au chargement
|
||||
from modules.tasks.task import Task
|
||||
from modules.tasks.task_handler import TaskHandler
|
||||
|
||||
task = Task(
|
||||
title=title,
|
||||
due_date=due_date,
|
||||
description=description,
|
||||
entity_type="client",
|
||||
entity_id=client_id,
|
||||
priority=priority,
|
||||
metadata=metadata or {},
|
||||
)
|
||||
return TaskHandler().add_task(task)
|
||||
Loading…
Add table
Add a link
Reference in a new issue