127 lines
4.0 KiB
Python
127 lines
4.0 KiB
Python
import logging
|
|
from datetime import datetime
|
|
from telegram import Update
|
|
from telegram.ext import ContextTypes
|
|
from config import PATRICK_ID
|
|
from services.tickets import get_ticket, resoudre_ticket
|
|
from services.faq_service import faq_service
|
|
from services.nextcloud import upload_text
|
|
from utils.produit_detector import detecter_produit
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def _parse_args(args: list[str]) -> tuple[str, str, str, int]:
|
|
"""
|
|
Format : /resolu #2026-047 cause | solution | 45min
|
|
Retourne : (ticket_id, cause, solution, duree_min)
|
|
"""
|
|
texte = " ".join(args)
|
|
ticket_id = texte.split()[0].lstrip("#")
|
|
reste = texte[len(ticket_id) + 1:].strip()
|
|
parties = [p.strip() for p in reste.split("|")]
|
|
cause = parties[0] if len(parties) > 0 else ""
|
|
solution = parties[1] if len(parties) > 1 else ""
|
|
duree_str = parties[2] if len(parties) > 2 else "0"
|
|
duree_min = int("".join(c for c in duree_str if c.isdigit()) or "0")
|
|
return ticket_id, cause, solution, duree_min
|
|
|
|
|
|
def _generer_fiche_md(ticket: dict, cause: str, solution: str, duree_min: int, produit: str) -> str:
|
|
date = datetime.now().strftime("%Y-%m-%d")
|
|
return f"""# SAV Résolu — {ticket['id']}
|
|
|
|
**Chantier :** {ticket['chantier']}
|
|
**Date :** {date}
|
|
**Technicien :** {ticket['username']}
|
|
**Produit :** {produit}
|
|
**Durée :** {duree_min} min
|
|
|
|
## Symptôme
|
|
{ticket['description']}
|
|
|
|
## Cause
|
|
{cause}
|
|
|
|
## Solution
|
|
{solution}
|
|
"""
|
|
|
|
|
|
async def cmd_resolu(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
"""/resolu #2026-047 relais AC défaillant | remplacer ref 4241 | 45min"""
|
|
if update.effective_user.id != PATRICK_ID:
|
|
return
|
|
|
|
if not context.args:
|
|
await update.message.reply_text(
|
|
"Usage : `/resolu #2026-047 cause | solution | 45min`",
|
|
parse_mode="Markdown",
|
|
)
|
|
return
|
|
|
|
try:
|
|
ticket_id, cause, solution, duree_min = _parse_args(context.args)
|
|
except Exception:
|
|
await update.message.reply_text("❌ Format invalide.\nUsage : `/resolu #ID cause | solution | durée`", parse_mode="Markdown")
|
|
return
|
|
|
|
ticket = get_ticket(ticket_id)
|
|
if not ticket:
|
|
await update.message.reply_text(f"❌ Ticket `#{ticket_id}` introuvable.", parse_mode="Markdown")
|
|
return
|
|
|
|
if ticket["status"] == "resolu":
|
|
await update.message.reply_text(f"⚠️ Ticket `#{ticket_id}` déjà résolu.", parse_mode="Markdown")
|
|
return
|
|
|
|
# 1. Clôturer dans SQLite
|
|
resoudre_ticket(ticket_id, cause, solution, duree_min)
|
|
|
|
# 2. Détecter le produit
|
|
produit = detecter_produit(f"{ticket['description']} {cause} {solution}")
|
|
|
|
# 3. Générer fiche .md → Nextcloud
|
|
date_str = datetime.now().strftime("%Y%m%d")
|
|
slug = ticket["chantier"].replace(" ", "_")[:30]
|
|
nc_path = f"SAV/{date_str}_{slug}_{ticket_id}.md"
|
|
fiche_md = _generer_fiche_md(ticket, cause, solution, duree_min, produit)
|
|
try:
|
|
await upload_text(fiche_md, nc_path)
|
|
except Exception as exc:
|
|
log.error("upload fiche SAV : %s", exc)
|
|
|
|
# 4. Indexer dans la FAQ
|
|
faq_service.indexer_fiche_sav(
|
|
ticket_id=ticket_id,
|
|
produit=produit,
|
|
symptome=ticket["description"],
|
|
cause=cause,
|
|
solution=solution,
|
|
chantier=ticket["chantier"],
|
|
date=datetime.now().strftime("%Y-%m-%d"),
|
|
duree_min=duree_min,
|
|
)
|
|
|
|
# 5. Notifier le technicien original
|
|
try:
|
|
await context.bot.send_message(
|
|
chat_id=ticket["chat_id"],
|
|
text=(
|
|
f"✅ *SAV #{ticket_id} résolu*\n\n"
|
|
f"🏠 {ticket['chantier']}\n"
|
|
f"🔧 {produit}\n"
|
|
f"💡 *Solution :* {solution}\n"
|
|
f"⏱ {duree_min} min"
|
|
),
|
|
parse_mode="Markdown",
|
|
)
|
|
except Exception as exc:
|
|
log.error("notify technicien : %s", exc)
|
|
|
|
await update.message.reply_text(
|
|
f"✅ Ticket `#{ticket_id}` clôturé et indexé dans la FAQ.\n"
|
|
f"📁 Fiche : `{nc_path}`",
|
|
parse_mode="Markdown",
|
|
)
|