2390 lines
92 KiB
Python
2390 lines
92 KiB
Python
|
|
"""
|
|||
|
|
Panel centralise — Container V2 (discord.py 2.7)
|
|||
|
|
Menus adaptatifs selon les roles de l'utilisateur.
|
|||
|
|
Banquiers : UserSelect pour choisir l'utilisateur cible.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import discord
|
|||
|
|
from discord.ext import commands
|
|||
|
|
from discord import app_commands
|
|||
|
|
import json
|
|||
|
|
import math
|
|||
|
|
import random
|
|||
|
|
import string
|
|||
|
|
import os
|
|||
|
|
import asyncio
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
from utils.guild_config import (
|
|||
|
|
has_role, get_guild_role, get_guild_channel, get_guild_category,
|
|||
|
|
load_guild_config, save_guild_config, set_config_value,
|
|||
|
|
ROLE_LABELS, CHANNEL_LABELS, CATEGORY_LABELS, get_role_id
|
|||
|
|
)
|
|||
|
|
from utils.data_manager import DataManager
|
|||
|
|
|
|||
|
|
C_MAIN = 0x2F3136
|
|||
|
|
C_BANK = 0xF1C40F
|
|||
|
|
C_GOV = 0x1ABC9C
|
|||
|
|
C_ID = 0x3498DB
|
|||
|
|
C_TICKET = 0xE74C3C
|
|||
|
|
C_SESSION = 0x9B59B6
|
|||
|
|
C_CONFIG = 0x95A5A6
|
|||
|
|
C_FUN = 0xE67E22
|
|||
|
|
C_BANQ_OP = 0x2ECC71
|
|||
|
|
|
|||
|
|
BANQUES = ["Victoria's Credit Bank", "NGC Bank"]
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _load_json(path, default=None):
|
|||
|
|
if default is None:
|
|||
|
|
default = {}
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
return default
|
|||
|
|
try:
|
|||
|
|
with open(path, "r", encoding="utf-8") as f:
|
|||
|
|
return json.load(f)
|
|||
|
|
except (json.JSONDecodeError, IOError):
|
|||
|
|
return default
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _save_json(path, data):
|
|||
|
|
with open(path, "w", encoding="utf-8") as f:
|
|||
|
|
json.dump(data, f, indent=4, ensure_ascii=False)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _find_account_by_rib(rib, comptes, entreprises, banque_nom=None):
|
|||
|
|
if banque_nom:
|
|||
|
|
if banque_nom in comptes:
|
|||
|
|
for uid, data in comptes[banque_nom].items():
|
|||
|
|
if data.get("rib") == rib:
|
|||
|
|
return comptes, banque_nom, uid, False
|
|||
|
|
if banque_nom in entreprises:
|
|||
|
|
for nom, data in entreprises[banque_nom].items():
|
|||
|
|
if data.get("rib") == rib:
|
|||
|
|
return entreprises, banque_nom, nom, True
|
|||
|
|
for bq, users in comptes.items():
|
|||
|
|
for uid, data in users.items():
|
|||
|
|
if data.get("rib") == rib:
|
|||
|
|
return comptes, bq, uid, False
|
|||
|
|
for bq, ents in entreprises.items():
|
|||
|
|
for nom, data in ents.items():
|
|||
|
|
if data.get("rib") == rib:
|
|||
|
|
return entreprises, bq, nom, True
|
|||
|
|
return None, None, None, None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _get_user_accounts(uid_str, comptes):
|
|||
|
|
accounts = []
|
|||
|
|
for banque, users in comptes.items():
|
|||
|
|
if uid_str in users:
|
|||
|
|
c = users[uid_str]
|
|||
|
|
accounts.append((banque, c))
|
|||
|
|
return accounts
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# USER SELECT (Banquiers uniquement)
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class TargetUserSelect(discord.ui.UserSelect):
|
|||
|
|
def __init__(self, custom_id="pnl_usel", placeholder="Choisir un utilisateur (defaut: vous)"):
|
|||
|
|
super().__init__(placeholder=placeholder, custom_id=custom_id, min_values=1, max_values=1)
|
|||
|
|
|
|||
|
|
async def callback(self, interaction: discord.Interaction):
|
|||
|
|
self.view.selected_user = self.values[0]
|
|||
|
|
await interaction.response.defer()
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — COMPTES (tout le monde)
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class CompteModal(discord.ui.Modal, title="💰 Voir un Compte"):
|
|||
|
|
def __init__(self, target_user=None):
|
|||
|
|
super().__init__()
|
|||
|
|
self.target_user = target_user
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if self.target_user:
|
|||
|
|
uid_str = str(self.target_user.id)
|
|||
|
|
member = self.target_user
|
|||
|
|
else:
|
|||
|
|
uid_str = str(interaction.user.id)
|
|||
|
|
member = interaction.user
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
accounts = _get_user_accounts(uid_str, comptes)
|
|||
|
|
if not accounts:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Aucun compte trouvé pour **{member.display_name}**.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title=f"💰 Comptes de {member.display_name}",
|
|||
|
|
color=C_BANK,
|
|||
|
|
)
|
|||
|
|
for banque, c in accounts:
|
|||
|
|
txs = c.get("transactions", [])
|
|||
|
|
tx_text = ""
|
|||
|
|
for t in txs[-3:]:
|
|||
|
|
tx_text += (
|
|||
|
|
f"> 📅 {t.get('date', 'N/A')} — **{t.get('type', 'N/A')}** — "
|
|||
|
|
f"{t.get('montant', 0)}€\n"
|
|||
|
|
)
|
|||
|
|
if not tx_text:
|
|||
|
|
tx_text = "> Aucune transaction récente.\n"
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"🏦 {banque}",
|
|||
|
|
value=(
|
|||
|
|
f"**RIB** : `{c.get('rib', 'N/A')}`\n"
|
|||
|
|
f"**Solde** : **{c.get('solde', 0):.2f}€**\n"
|
|||
|
|
f"**Dernières transactions** :\n{tx_text}"
|
|||
|
|
),
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VirementModal(discord.ui.Modal, title="📤 Effectuer un Virement"):
|
|||
|
|
rib_dest = discord.ui.TextInput(
|
|||
|
|
label="RIB destinataire", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (laisser vide = auto)", required=False, max_length=50
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if montant_val <= 0:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Le montant doit être supérieur à 0.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
rib_dest_val = self.rib_dest.value.strip()
|
|||
|
|
banque_nom = self.banque.value.strip() if self.banque.value else None
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
uid_str = str(interaction.user.id)
|
|||
|
|
source = None
|
|||
|
|
source_bq = None
|
|||
|
|
for bq, users in comptes.items():
|
|||
|
|
if uid_str in users:
|
|||
|
|
source = users[uid_str]
|
|||
|
|
source_bq = bq
|
|||
|
|
break
|
|||
|
|
if not source:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Vous n'avez pas de compte bancaire.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if source["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
dest_store, dest_bq, dest_id, dest_ent = _find_account_by_rib(
|
|||
|
|
rib_dest_val, comptes, entreprises, banque_nom
|
|||
|
|
)
|
|||
|
|
if not dest_store:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ RIB destinataire introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
source["solde"] -= montant_val
|
|||
|
|
source.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement",
|
|||
|
|
"source": f"Vers {rib_dest_val}",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
dest_store[dest_bq][dest_id]["solde"] += montant_val
|
|||
|
|
dest_store[dest_bq][dest_id].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu",
|
|||
|
|
"source": interaction.user.name,
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Virement de **{montant_val:.2f}€** effectué vers `{rib_dest_val}` dans **{dest_bq}**.",
|
|||
|
|
ephemeral=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class AbonnementModal(discord.ui.Modal, title="🔄 Créer un Abonnement"):
|
|||
|
|
nom = discord.ui.TextInput(
|
|||
|
|
label="Nom de l'abonnement", required=True, max_length=50
|
|||
|
|
)
|
|||
|
|
rib_emetteur = discord.ui.TextInput(
|
|||
|
|
label="RIB émetteur", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
rib_receveur = discord.ui.TextInput(
|
|||
|
|
label="RIB receveur", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
banque = discord.ui.TextInput(label="Banque", required=True, max_length=50)
|
|||
|
|
jour = discord.ui.TextInput(
|
|||
|
|
label="Jour (lundi, mardi...)", required=True, max_length=10
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
JOURS = [
|
|||
|
|
"lundi", "mardi", "mercredi", "jeudi",
|
|||
|
|
"vendredi", "samedi", "dimanche",
|
|||
|
|
]
|
|||
|
|
jour_val = self.jour.value.strip().lower()
|
|||
|
|
if jour_val not in JOURS:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Jour invalide. {', '.join(JOURS)}", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
abos = _load_json("abonnements.json", [])
|
|||
|
|
abos.append(
|
|||
|
|
{
|
|||
|
|
"nom": self.nom.value.strip(),
|
|||
|
|
"rib_emetteur": self.rib_emetteur.value.strip(),
|
|||
|
|
"rib_receveur": self.rib_receveur.value.strip(),
|
|||
|
|
"montant": montant_val,
|
|||
|
|
"banque": self.banque.value.strip(),
|
|||
|
|
"jour": jour_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("abonnements.json", abos)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Abonnement **{self.nom.value.strip()}** enregistré. "
|
|||
|
|
f"Virement automatique tous les **{jour_val}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — OPERATIONS BANQUIER
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class OuvrirCompteModal(discord.ui.Modal, title="🏦 Ouvrir un Compte"):
|
|||
|
|
def __init__(self, target_user=None):
|
|||
|
|
super().__init__()
|
|||
|
|
self.target_user = target_user
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
member = self.target_user or interaction.user
|
|||
|
|
uid = member.id
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🏦 Ouvrir un Compte",
|
|||
|
|
description=f"Compte pour : **{member.display_name}**",
|
|||
|
|
color=C_BANQ_OP,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
async def _actual_open(self, interaction, banque_nom, uid, member):
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
if banque_nom not in comptes:
|
|||
|
|
comptes[banque_nom] = {}
|
|||
|
|
uid_str = str(uid)
|
|||
|
|
if uid_str in comptes[banque_nom]:
|
|||
|
|
return False, f"{member.mention} a déjà un compte dans **{banque_nom}**."
|
|||
|
|
rib = (
|
|||
|
|
f"{random.randint(10000, 99999)} {random.randint(10000, 99999)} "
|
|||
|
|
f"{random.randint(10000000000, 99999999999)} {random.randint(10, 99)}"
|
|||
|
|
)
|
|||
|
|
comptes[banque_nom][uid_str] = {
|
|||
|
|
"rib": rib,
|
|||
|
|
"solde": 0.0,
|
|||
|
|
"transactions": [],
|
|||
|
|
}
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
try:
|
|||
|
|
await member.send(
|
|||
|
|
f"🏦 Un compte **{banque_nom}** a été créé pour vous.\nRIB : `{rib}`"
|
|||
|
|
)
|
|||
|
|
except discord.Forbidden:
|
|||
|
|
pass
|
|||
|
|
return True, f"✅ Compte créé pour {member.mention} dans **{banque_nom}**. RIB: `{rib}`"
|
|||
|
|
|
|||
|
|
|
|||
|
|
class OuvrirCompteSimpleModal(discord.ui.Modal, title="🏦 Ouvrir Compte Personnel"):
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def __init__(self, target_user=None):
|
|||
|
|
super().__init__()
|
|||
|
|
self.target_user = target_user
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
if banque_nom not in BANQUES:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Banque invalide. Choisissez : {', '.join(BANQUES)}",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
member = self.target_user or interaction.user
|
|||
|
|
uid = member.id
|
|||
|
|
uid_str = str(uid)
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
if banque_nom not in comptes:
|
|||
|
|
comptes[banque_nom] = {}
|
|||
|
|
if uid_str in comptes[banque_nom]:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ {member.mention} a déjà un compte dans **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
rib = (
|
|||
|
|
f"{random.randint(10000, 99999)} {random.randint(10000, 99999)} "
|
|||
|
|
f"{random.randint(10000000000, 99999999999)} {random.randint(10, 99)}"
|
|||
|
|
)
|
|||
|
|
comptes[banque_nom][uid_str] = {
|
|||
|
|
"rib": rib,
|
|||
|
|
"solde": 0.0,
|
|||
|
|
"transactions": [],
|
|||
|
|
}
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
try:
|
|||
|
|
await member.send(
|
|||
|
|
f"🏦 Un compte **{banque_nom}** a été créé pour vous.\nRIB : `{rib}`"
|
|||
|
|
)
|
|||
|
|
except discord.Forbidden:
|
|||
|
|
pass
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Compte créé pour {member.mention} dans **{banque_nom}**. RIB: `{rib}`",
|
|||
|
|
ephemeral=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class OuvrirCompteEntModal(discord.ui.Modal, title="🏢 Ouvrir Compte Entreprise"):
|
|||
|
|
entreprise = discord.ui.TextInput(
|
|||
|
|
label="Nom de l'entreprise", required=True, max_length=50
|
|||
|
|
)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
tva = discord.ui.TextInput(label="TVA (2, 5, 10 ou 20)", required=True, max_length=3)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
if banque_nom not in BANQUES:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Banque invalide. Choisissez : {', '.join(BANQUES)}",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
tva_val = int(self.tva.value.strip())
|
|||
|
|
if tva_val not in (2, 5, 10, 20):
|
|||
|
|
raise ValueError
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ TVA invalide (2, 5, 10 ou 20).", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
nom_ent = self.entreprise.value.strip()
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
if banque_nom not in entreprises:
|
|||
|
|
entreprises[banque_nom] = {}
|
|||
|
|
if nom_ent in entreprises[banque_nom]:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Un compte existe déjà pour **{nom_ent}** dans **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
rib = " ".join(
|
|||
|
|
["".join(random.choices(string.digits, k=5)) for _ in range(4)]
|
|||
|
|
)
|
|||
|
|
mdp = "".join(random.choices(string.ascii_letters + string.digits, k=8))
|
|||
|
|
entreprises[banque_nom][nom_ent] = {
|
|||
|
|
"rib": rib,
|
|||
|
|
"solde": 0,
|
|||
|
|
"mdp": mdp,
|
|||
|
|
"tva": tva_val,
|
|||
|
|
"transactions": [],
|
|||
|
|
}
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
try:
|
|||
|
|
await interaction.user.send(
|
|||
|
|
f"🏦 Compte entreprise **{nom_ent}** ouvert dans **{banque_nom}** !\n"
|
|||
|
|
f"💳 RIB : `{rib}`\n🔐 Mot de passe : `{mdp}`\n💼 TVA : `{tva_val}%`"
|
|||
|
|
)
|
|||
|
|
except discord.Forbidden:
|
|||
|
|
pass
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Compte entreprise **{nom_ent}** créé dans **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VirementBanquierModal(discord.ui.Modal, title="🏦 Virement Banquier"):
|
|||
|
|
rib_emetteur = discord.ui.TextInput(
|
|||
|
|
label="RIB émetteur", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
rib_destinataire = discord.ui.TextInput(
|
|||
|
|
label="RIB destinataire", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
if banque_nom not in comptes:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Banque introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
emetteur_id = None
|
|||
|
|
destinataire_id = None
|
|||
|
|
for uid, data in comptes[banque_nom].items():
|
|||
|
|
if data.get("rib") == self.rib_emetteur.value.strip():
|
|||
|
|
emetteur_id = uid
|
|||
|
|
if data.get("rib") == self.rib_destinataire.value.strip():
|
|||
|
|
destinataire_id = uid
|
|||
|
|
if not emetteur_id:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ RIB émetteur introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if not destinataire_id:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ RIB destinataire introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if comptes[banque_nom][emetteur_id]["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
comptes[banque_nom][emetteur_id]["solde"] -= montant_val
|
|||
|
|
comptes[banque_nom][emetteur_id]["transactions"].append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement banquier",
|
|||
|
|
"source": f"Vers {self.rib_destinataire.value}",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
comptes[banque_nom][destinataire_id]["solde"] += montant_val
|
|||
|
|
comptes[banque_nom][destinataire_id]["transactions"].append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu (banquier)",
|
|||
|
|
"source": f"De {self.rib_emetteur.value}",
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Virement banquier de **{montant_val:.2f}€** de "
|
|||
|
|
f"`{self.rib_emetteur.value}` vers `{self.rib_destinataire.value}` "
|
|||
|
|
f"dans **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VirementBanquierEntModal(discord.ui.Modal, title="🏢 Vir. Banquier → Entreprise"):
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
entreprise = discord.ui.TextInput(
|
|||
|
|
label="Nom entreprise", required=True, max_length=50
|
|||
|
|
)
|
|||
|
|
mdp = discord.ui.TextInput(
|
|||
|
|
label="Mot de passe entreprise", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
rib_dest = discord.ui.TextInput(
|
|||
|
|
label="RIB destinataire", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
if (
|
|||
|
|
banque_nom not in entreprises
|
|||
|
|
or self.entreprise.value.strip() not in entreprises[banque_nom]
|
|||
|
|
):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Compte entreprise introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
compte_ent = entreprises[banque_nom][self.entreprise.value.strip()]
|
|||
|
|
if compte_ent.get("mdp") != self.mdp.value.strip():
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Mot de passe incorrect.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if compte_ent["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
dest_store, dest_bq, dest_id, _ = _find_account_by_rib(
|
|||
|
|
self.rib_dest.value.strip(), comptes, entreprises
|
|||
|
|
)
|
|||
|
|
if not dest_store:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ RIB destinataire introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
compte_ent["solde"] -= montant_val
|
|||
|
|
compte_ent.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement",
|
|||
|
|
"source": f"Vers {self.rib_dest.value}",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
dest_store[dest_bq][dest_id]["solde"] += montant_val
|
|||
|
|
dest_store[dest_bq][dest_id].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu",
|
|||
|
|
"source": self.entreprise.value.strip(),
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Virement de **{montant_val:.2f}€** depuis "
|
|||
|
|
f"**{self.entreprise.value.strip()}** vers `{self.rib_dest.value.strip()}`.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class AjouterArgentModal(discord.ui.Modal, title="➕ Ajouter de l'Argent"):
|
|||
|
|
rib = discord.ui.TextInput(label="RIB du compte", required=True, max_length=40)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (optionnel)", required=False, max_length=50
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if montant_val <= 0:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant doit être > 0.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip() if self.banque.value else None
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
store, bq, uid, is_ent = _find_account_by_rib(
|
|||
|
|
self.rib.value.strip(), comptes, entreprises, banque_nom
|
|||
|
|
)
|
|||
|
|
if not store:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Aucun compte trouvé avec ce RIB.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
store[bq][uid]["solde"] += montant_val
|
|||
|
|
store[bq][uid].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Dépôt",
|
|||
|
|
"source": "Banque",
|
|||
|
|
"montant": montant_val,
|
|||
|
|
"emetteur": str(interaction.user.id),
|
|||
|
|
"destinataire": uid,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
if is_ent:
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
else:
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
try:
|
|||
|
|
user = await interaction.client.fetch_user(int(uid))
|
|||
|
|
await user.send(
|
|||
|
|
f"💰 Dépôt de **{montant_val:.2f}€** sur votre compte **{bq}**."
|
|||
|
|
)
|
|||
|
|
except Exception:
|
|||
|
|
pass
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ **{montant_val:.2f}€** ajoutés au compte `{self.rib.value.strip()}` dans **{bq}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class RetirerArgentModal(discord.ui.Modal, title="➖ Retirer de l'Argent"):
|
|||
|
|
rib = discord.ui.TextInput(label="RIB du compte", required=True, max_length=40)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (optionnel)", required=False, max_length=50
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip() if self.banque.value else None
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
store, bq, uid, is_ent = _find_account_by_rib(
|
|||
|
|
self.rib.value.strip(), comptes, entreprises, banque_nom
|
|||
|
|
)
|
|||
|
|
if not store:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Aucun compte trouvé avec ce RIB.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if store[bq][uid]["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
store[bq][uid]["solde"] -= montant_val
|
|||
|
|
store[bq][uid].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Retrait",
|
|||
|
|
"source": "Banque",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
"emetteur": str(interaction.user.id),
|
|||
|
|
"destinataire": uid,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
if is_ent:
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
else:
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="💸 Retrait effectué",
|
|||
|
|
description=(
|
|||
|
|
f"💼 Banque : **{bq}**\n"
|
|||
|
|
f"RIB : `{self.rib.value.strip()}`\n"
|
|||
|
|
f"Montant : **{montant_val:.2f}€**"
|
|||
|
|
),
|
|||
|
|
color=discord.Color.red(),
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=False)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TransactionsModal(discord.ui.Modal, title="📜 Voir Transactions"):
|
|||
|
|
def __init__(self, target_user=None):
|
|||
|
|
super().__init__()
|
|||
|
|
self.target_user = target_user
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "banquier"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux banquiers.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
member = self.target_user or interaction.user
|
|||
|
|
uid_str = str(member.id)
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
all_txs = []
|
|||
|
|
for banque, users in comptes.items():
|
|||
|
|
if uid_str in users:
|
|||
|
|
for t in users[uid_str].get("transactions", []):
|
|||
|
|
all_txs.append(t)
|
|||
|
|
if not all_txs:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"📜 {member.mention} n'a aucune transaction.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title=f"📜 Transactions de {member.display_name}",
|
|||
|
|
color=discord.Color.gold(),
|
|||
|
|
)
|
|||
|
|
for t in all_txs[-10:]:
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"📅 {t.get('date', 'N/A')}",
|
|||
|
|
value=(
|
|||
|
|
f"**Type**: {t.get('type', 'N/A')}\n"
|
|||
|
|
f"💰 **Montant**: {t.get('montant', 0)}€\n"
|
|||
|
|
f"📤 **Source**: {t.get('source', 'N/A')}"
|
|||
|
|
),
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
embed.set_footer(text="10 dernières transactions")
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — GOUVERNEMENT
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class GouvVirerModal(discord.ui.Modal, title="💸 Virement Gouvernement"):
|
|||
|
|
rib = discord.ui.TextInput(
|
|||
|
|
label="RIB destinataire", required=True, max_length=40
|
|||
|
|
)
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (optionnel)", required=False, max_length=50
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if montant_val <= 0:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant doit être > 0.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip() if self.banque.value else None
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
gouv = entreprises.get("Gouvernement", {}).get("GOUV")
|
|||
|
|
if not gouv:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Compte Gouvernement introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if gouv["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Fonds insuffisants.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
dest_store, dest_bq, dest_id, _ = _find_account_by_rib(
|
|||
|
|
self.rib.value.strip(), comptes, entreprises, banque_nom
|
|||
|
|
)
|
|||
|
|
if not dest_store:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ RIB destinataire introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
gouv["solde"] -= montant_val
|
|||
|
|
gouv.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement",
|
|||
|
|
"source": "Gouvernement",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
"destinataire": self.rib.value.strip(),
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
dest_store[dest_bq][dest_id]["solde"] += montant_val
|
|||
|
|
dest_store[dest_bq][dest_id].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu",
|
|||
|
|
"source": "Gouvernement",
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🏛️ Virement Gouvernemental effectué",
|
|||
|
|
description=(
|
|||
|
|
f"RIB : `{self.rib.value.strip()}`\n"
|
|||
|
|
f"Montant : **{montant_val:.2f}€**\n"
|
|||
|
|
f"Banque : **{dest_bq}**"
|
|||
|
|
),
|
|||
|
|
color=discord.Color.gold(),
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class RetraitGouvModal(discord.ui.Modal, title="🏦 Retrait Gouvernement"):
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
gouv = entreprises.get("Gouvernement", {}).get("GOUV")
|
|||
|
|
if not gouv:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Compte Gouvernement introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if gouv["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Fonds insuffisants.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
gouv["solde"] -= montant_val
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
gouv.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Retrait",
|
|||
|
|
"source": "Gouvernement",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🏦 Retrait Gouvernement",
|
|||
|
|
description=(
|
|||
|
|
f"Montant : **{montant_val:.2f}€**\n"
|
|||
|
|
f"Solde restant : **{gouv['solde']:.2f}€**"
|
|||
|
|
),
|
|||
|
|
color=discord.Color.gold(),
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VirementFBMModal(discord.ui.Modal, title="📤 Virement vers FBM"):
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if montant_val <= 0:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant doit être > 0.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
uid_str = str(interaction.user.id)
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
if banque_nom not in comptes or uid_str not in comptes[banque_nom]:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Vous n'avez pas de compte dans cette banque.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
compte = comptes[banque_nom][uid_str]
|
|||
|
|
if compte["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if "fbm" not in entreprises:
|
|||
|
|
entreprises["fbm"] = {}
|
|||
|
|
if "FBM" not in entreprises["fbm"]:
|
|||
|
|
entreprises["fbm"]["FBM"] = {
|
|||
|
|
"rib": "00000 00000 00000000000 03",
|
|||
|
|
"solde": 0.0,
|
|||
|
|
"transactions": [],
|
|||
|
|
}
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
compte["solde"] -= montant_val
|
|||
|
|
compte.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement",
|
|||
|
|
"source": "Vers FBM",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
entreprises["fbm"]["FBM"]["solde"] += montant_val
|
|||
|
|
entreprises["fbm"]["FBM"].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu",
|
|||
|
|
"source": interaction.user.name,
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Virement de **{montant_val:.2f}€** envoyé à **FBM** depuis **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VirementURSAFFModal(discord.ui.Modal, title="📤 Virement vers URSAFF"):
|
|||
|
|
montant = discord.ui.TextInput(label="Montant", required=True, max_length=10)
|
|||
|
|
banque = discord.ui.TextInput(
|
|||
|
|
label="Banque (V'Toria's Credit Bank / NGC Bank)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=50,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
try:
|
|||
|
|
montant_val = float(self.montant.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if montant_val <= 0:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Montant doit être > 0.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
banque_nom = self.banque.value.strip()
|
|||
|
|
uid_str = str(interaction.user.id)
|
|||
|
|
comptes = _load_json("comptes_bancaires.json")
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
if banque_nom not in comptes or uid_str not in comptes[banque_nom]:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Vous n'avez pas de compte dans cette banque.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
compte = comptes[banque_nom][uid_str]
|
|||
|
|
if compte["solde"] < montant_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Solde insuffisant.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if "ursaff" not in entreprises:
|
|||
|
|
entreprises["ursaff"] = {}
|
|||
|
|
if "URSAFF" not in entreprises["ursaff"]:
|
|||
|
|
entreprises["ursaff"]["URSAFF"] = {
|
|||
|
|
"rib": "00000 00000 00000000000 02",
|
|||
|
|
"solde": 0.0,
|
|||
|
|
"transactions": [],
|
|||
|
|
}
|
|||
|
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
|||
|
|
compte["solde"] -= montant_val
|
|||
|
|
compte.setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement",
|
|||
|
|
"source": "Vers URSAFF",
|
|||
|
|
"montant": -montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
entreprises["ursaff"]["URSAFF"]["solde"] += montant_val
|
|||
|
|
entreprises["ursaff"]["URSAFF"].setdefault("transactions", []).append(
|
|||
|
|
{
|
|||
|
|
"date": now,
|
|||
|
|
"type": "Virement reçu",
|
|||
|
|
"source": interaction.user.name,
|
|||
|
|
"montant": montant_val,
|
|||
|
|
}
|
|||
|
|
)
|
|||
|
|
_save_json("comptes_bancaires.json", comptes)
|
|||
|
|
_save_json("comptes_entreprises.json", entreprises)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Virement de **{montant_val:.2f}€** envoyé à **URSAFF** depuis **{banque_nom}**.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — IDENTITE
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class CreerCarteModal(discord.ui.Modal, title="🪪 Créer une Carte d'Identité"):
|
|||
|
|
utilisateur = discord.ui.TextInput(
|
|||
|
|
label="ID Utilisateur", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
nom_complet = discord.ui.TextInput(
|
|||
|
|
label="Nom complet (Ex: Dupont Jean)", required=True, max_length=100
|
|||
|
|
)
|
|||
|
|
date_naissance = discord.ui.TextInput(
|
|||
|
|
label="Date de naissance", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
lieu_naissance = discord.ui.TextInput(
|
|||
|
|
label="Lieu de naissance", required=True, max_length=50
|
|||
|
|
)
|
|||
|
|
sexe = discord.ui.TextInput(
|
|||
|
|
label="Sexe (Homme/Femme/Autre)", required=True, max_length=6
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
uid = self.utilisateur.value.strip()
|
|||
|
|
parts = self.nom_complet.value.strip().split(maxsplit=1)
|
|||
|
|
nom_val = parts[0].upper() if parts else ""
|
|||
|
|
prenom_val = parts[1].capitalize() if len(parts) > 1 else ""
|
|||
|
|
dm = DataManager()
|
|||
|
|
date_creation = datetime.now()
|
|||
|
|
date_exp = (date_creation + timedelta(days=730)).strftime("%d/%m/%Y")
|
|||
|
|
dm.identities[uid] = {
|
|||
|
|
"nom": nom_val,
|
|||
|
|
"prenom": prenom_val,
|
|||
|
|
"date_naissance": self.date_naissance.value.strip(),
|
|||
|
|
"lieu_naissance": self.lieu_naissance.value.strip(),
|
|||
|
|
"sexe": self.sexe.value.strip().capitalize(),
|
|||
|
|
"date_expiration": date_exp,
|
|||
|
|
}
|
|||
|
|
dm.save_data()
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Carte d'identité créée pour <@{uid}>.", ephemeral=False
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VoirCarteModal(discord.ui.Modal, title="🪪 Voir une Carte d'Identité"):
|
|||
|
|
def __init__(self, target_user=None):
|
|||
|
|
super().__init__()
|
|||
|
|
self.target_user = target_user
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if self.target_user:
|
|||
|
|
uid = str(self.target_user.id)
|
|||
|
|
member = self.target_user
|
|||
|
|
else:
|
|||
|
|
uid = str(interaction.user.id)
|
|||
|
|
member = interaction.user
|
|||
|
|
dm = DataManager()
|
|||
|
|
identity = dm.identities.get(uid)
|
|||
|
|
if not identity:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Aucune carte trouvée.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
from utils.card_generator import CardGenerator
|
|||
|
|
|
|||
|
|
cg = CardGenerator()
|
|||
|
|
card_buffer = await cg.create_identity_card(member, identity)
|
|||
|
|
file = discord.File(card_buffer, filename="carte_identite.png")
|
|||
|
|
embed = discord.Embed(title="🪪 Carte d'identité", color=C_ID)
|
|||
|
|
embed.set_image(url="attachment://carte_identite.png")
|
|||
|
|
await interaction.response.send_message(file=file, embed=embed)
|
|||
|
|
except Exception as e:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Erreur : {e}", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class PermisModal(discord.ui.Modal, title="🚗 Ajouter un Permis"):
|
|||
|
|
membre = discord.ui.TextInput(label="ID du membre", required=True, max_length=20)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "auto_ecole"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé à l'auto-école.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
member = await interaction.guild.fetch_member(
|
|||
|
|
int(self.membre.value.strip())
|
|||
|
|
)
|
|||
|
|
role = get_guild_role(interaction.guild, "permis")
|
|||
|
|
if not role:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Rôle permis introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
await member.add_roles(role)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Permis attribué à {member.mention}.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
except (ValueError, discord.NotFound):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Membre introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VisiteMedModal(discord.ui.Modal, title="🏥 Valider Visite Médicale"):
|
|||
|
|
membre = discord.ui.TextInput(label="ID du membre", required=True, max_length=20)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not has_role(interaction.user, "ems"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux EMS.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
member = await interaction.guild.fetch_member(
|
|||
|
|
int(self.membre.value.strip())
|
|||
|
|
)
|
|||
|
|
role = get_guild_role(interaction.guild, "visite_medicale")
|
|||
|
|
if not role:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Rôle visite médicale introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
await member.add_roles(role)
|
|||
|
|
fichier = "visite_médicale.json"
|
|||
|
|
data = _load_json(fichier)
|
|||
|
|
expiration = (datetime.now() + timedelta(days=30)).strftime(
|
|||
|
|
"%Y-%m-%d %H:%M:%S"
|
|||
|
|
)
|
|||
|
|
data[str(member.id)] = {"role_id": role.id, "expiration": expiration}
|
|||
|
|
_save_json(fichier, data)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Visite médicale validée pour {member.mention} jusqu'au {expiration}.",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
except (ValueError, discord.NotFound):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Membre introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — TICKETS & MESSAGES
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class MessageModal(discord.ui.Modal, title="✉️ Envoyer un MP"):
|
|||
|
|
membre = discord.ui.TextInput(
|
|||
|
|
label="ID du membre", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
message = discord.ui.TextInput(
|
|||
|
|
label="Message",
|
|||
|
|
style=discord.TextStyle.paragraph,
|
|||
|
|
required=True,
|
|||
|
|
max_length=2000,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not interaction.user.guild_permissions.administrator:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux administrateurs.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
user = await interaction.client.fetch_user(int(self.membre.value.strip()))
|
|||
|
|
await user.send(self.message.value)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ MP envoyé à {user.name}.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
except (ValueError, discord.NotFound):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Membre introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
except discord.Forbidden:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Impossible d'envoyer le MP.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MessageTousModal(discord.ui.Modal, title="📢 MP à Tous"):
|
|||
|
|
message = discord.ui.TextInput(
|
|||
|
|
label="Message",
|
|||
|
|
style=discord.TextStyle.paragraph,
|
|||
|
|
required=True,
|
|||
|
|
max_length=2000,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not interaction.user.guild_permissions.administrator:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux administrateurs.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
await interaction.response.defer(ephemeral=True)
|
|||
|
|
sent, failed = 0, 0
|
|||
|
|
for member in interaction.guild.members:
|
|||
|
|
if not member.bot:
|
|||
|
|
try:
|
|||
|
|
await member.send(self.message.value)
|
|||
|
|
sent += 1
|
|||
|
|
except Exception:
|
|||
|
|
failed += 1
|
|||
|
|
await interaction.followup.send(
|
|||
|
|
f"✅ MP envoyés : {sent} | Échecs : {failed}", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — SESSIONS
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class AnnonceSessionModal(discord.ui.Modal, title="📢 Annoncer une Session"):
|
|||
|
|
date = discord.ui.TextInput(
|
|||
|
|
label="Date (ex: Vendredi 20 Juin à 20h45)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=100,
|
|||
|
|
)
|
|||
|
|
reminder1 = discord.ui.TextInput(
|
|||
|
|
label="1er rappel (ex: Jeudi 19 Juin à 19h)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=100,
|
|||
|
|
)
|
|||
|
|
reminder2 = discord.ui.TextInput(
|
|||
|
|
label="2e rappel (ex: Vendredi 20 Juin à 15h)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=100,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
import dateparser
|
|||
|
|
from datetime import timezone
|
|||
|
|
|
|||
|
|
session_date = dateparser.parse(
|
|||
|
|
self.date.value,
|
|||
|
|
languages=["fr"],
|
|||
|
|
settings={
|
|||
|
|
"TIMEZONE": "Europe/Paris",
|
|||
|
|
"RETURN_AS_TIMEZONE_AWARE": True,
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
r1 = dateparser.parse(
|
|||
|
|
self.reminder1.value,
|
|||
|
|
languages=["fr"],
|
|||
|
|
settings={
|
|||
|
|
"TIMEZONE": "Europe/Paris",
|
|||
|
|
"RETURN_AS_TIMEZONE_AWARE": True,
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
r2 = dateparser.parse(
|
|||
|
|
self.reminder2.value,
|
|||
|
|
languages=["fr"],
|
|||
|
|
settings={
|
|||
|
|
"TIMEZONE": "Europe/Paris",
|
|||
|
|
"RETURN_AS_TIMEZONE_AWARE": True,
|
|||
|
|
},
|
|||
|
|
)
|
|||
|
|
if not session_date or not r1 or not r2:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Une des dates n'a pas été comprise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
session_date = session_date.astimezone(timezone.utc)
|
|||
|
|
r1 = r1.astimezone(timezone.utc)
|
|||
|
|
r2 = r2.astimezone(timezone.utc)
|
|||
|
|
ping_role_id = get_role_id(interaction.guild.id, "citoyen")
|
|||
|
|
message = (
|
|||
|
|
"# <:VV:1339237574593609780> - **SESSION VICTORIA'S VICE**\n\n"
|
|||
|
|
"```📅 - HORAIRE DE LA SESSION```\n"
|
|||
|
|
f"> - Nous vous donnons rendez-vous le **{self.date.value}** "
|
|||
|
|
"pour une **session officielle** sur Victoria's Vice. 🗓️\n"
|
|||
|
|
"---\n"
|
|||
|
|
"```🤔 - COMMENT REJOINDRE LA SESSION ?```\n"
|
|||
|
|
"> - Pour lancer la Map, entrez le code sur la barre de recherche de Fortnite.\n"
|
|||
|
|
"> - **`CODE DE LA MAP`** <:arrow:1297491509201080362> [0986-1836-1625]\n"
|
|||
|
|
"> - **`LIEN DIRECT`** <:arrow:1297491509201080362> "
|
|||
|
|
"<https://play.fn.gg/island/0986-1836-1625>\n"
|
|||
|
|
"---\n"
|
|||
|
|
"```🖐 - SEREZ-VOUS PRÉSENT(E) ?```\n"
|
|||
|
|
"> - Je serai présent : <:check:1297296859206778911> **(0)**\n"
|
|||
|
|
"> - Je serai absent : <:uncheck:1297296882778902598> **(0)**\n"
|
|||
|
|
"> - Je serai en retard : ⏰ **(0)**\n"
|
|||
|
|
"---\n"
|
|||
|
|
f"> - **`PING`** : <@&{ping_role_id}>"
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(content=message)
|
|||
|
|
msg = await interaction.original_response()
|
|||
|
|
from commandes.annonces_sessions import PresenceView
|
|||
|
|
|
|||
|
|
await msg.edit(view=PresenceView(msg.id))
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ListePresenceModal(discord.ui.Modal, title="📋 Liste des Présences"):
|
|||
|
|
message_id = discord.ui.TextInput(
|
|||
|
|
label="ID du message d'annonce", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
from commandes.annonces_sessions import presence_data
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
mid = int(self.message_id.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ ID invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if mid not in presence_data:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Aucune donnée de présence pour ce message.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
data = presence_data[mid]
|
|||
|
|
|
|||
|
|
def mentions(ids):
|
|||
|
|
return (
|
|||
|
|
", ".join(f"<@{uid}>" for uid in ids) if ids else "Aucun"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"**Présents ({len(data['present'])})** : {mentions(data['present'])}\n"
|
|||
|
|
f"**Absents ({len(data['absent'])})** : {mentions(data['absent'])}\n"
|
|||
|
|
f"**En retard ({len(data['retard'])})** : {mentions(data['retard'])}",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — CONFIG
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class ConfigRoleModal(discord.ui.Modal, title="🎭 Définir un Rôle"):
|
|||
|
|
cle = discord.ui.TextInput(
|
|||
|
|
label="Clé (banquier, citoyen, ems...)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=30,
|
|||
|
|
)
|
|||
|
|
role_id = discord.ui.TextInput(
|
|||
|
|
label="ID du rôle Discord", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not interaction.user.guild_permissions.manage_guild:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Permission requise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
cle = self.cle.value.strip().lower()
|
|||
|
|
try:
|
|||
|
|
rid = int(self.role_id.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ ID invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
role = interaction.guild.get_role(rid)
|
|||
|
|
if not role:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Rôle introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
set_config_value(interaction.guild.id, "roles", cle, rid)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Rôle **{ROLE_LABELS.get(cle, cle)}** → {role.mention}",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ConfigChannelModal(discord.ui.Modal, title="📢 Définir un Salon"):
|
|||
|
|
cle = discord.ui.TextInput(
|
|||
|
|
label="Clé (welcome, candidature...)",
|
|||
|
|
required=True,
|
|||
|
|
max_length=30,
|
|||
|
|
)
|
|||
|
|
channel_id = discord.ui.TextInput(
|
|||
|
|
label="ID du salon Discord", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not interaction.user.guild_permissions.manage_guild:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Permission requise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
cle = self.cle.value.strip().lower()
|
|||
|
|
try:
|
|||
|
|
cid = int(self.channel_id.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ ID invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
ch = interaction.guild.get_channel(cid)
|
|||
|
|
if not ch:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Salon introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
set_config_value(interaction.guild.id, "channels", cle, cid)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Salon **{CHANNEL_LABELS.get(cle, cle)}** → {ch.mention}",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ConfigCategoryModal(discord.ui.Modal, title="📁 Définir une Catégorie"):
|
|||
|
|
cle = discord.ui.TextInput(label="Clé (ticket)", required=True, max_length=30)
|
|||
|
|
category_id = discord.ui.TextInput(
|
|||
|
|
label="ID de la catégorie Discord", required=True, max_length=20
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
if not interaction.user.guild_permissions.manage_guild:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Permission requise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
cle = self.cle.value.strip().lower()
|
|||
|
|
try:
|
|||
|
|
cid = int(self.category_id.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ ID invalide.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
cat = interaction.guild.get_channel(cid)
|
|||
|
|
if not cat:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Catégorie introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
set_config_value(interaction.guild.id, "categories", cle, cid)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"✅ Catégorie **{CATEGORY_LABELS.get(cle, cle)}** → **{cat.name}**",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# MODALS — UTILITAIRES
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class RollModal(discord.ui.Modal, title="🎲 Lancer un Dé"):
|
|||
|
|
minimum = discord.ui.TextInput(
|
|||
|
|
label="Valeur minimale", required=True, max_length=5
|
|||
|
|
)
|
|||
|
|
maximum = discord.ui.TextInput(
|
|||
|
|
label="Valeur maximale", required=True, max_length=5
|
|||
|
|
)
|
|||
|
|
raison = discord.ui.TextInput(label="Raison", required=True, max_length=100)
|
|||
|
|
|
|||
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|||
|
|
try:
|
|||
|
|
min_val = int(self.minimum.value.strip())
|
|||
|
|
max_val = int(self.maximum.value.strip())
|
|||
|
|
except ValueError:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Valeurs invalides.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
if min_val > max_val:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Min > Max.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
result = random.randint(min_val, max_val)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🎲 Résultat du dé",
|
|||
|
|
description=(
|
|||
|
|
f"**{result}** (entre {min_val} et {max_val})\n"
|
|||
|
|
f"*Raison : {self.raison.value.strip()}*"
|
|||
|
|
),
|
|||
|
|
color=C_FUN,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# PANELS — VUES
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
def _btn(label, style, cid, cb):
|
|||
|
|
b = discord.ui.Button(label=label, style=style, custom_id=cid)
|
|||
|
|
b.callback = cb
|
|||
|
|
return b
|
|||
|
|
|
|||
|
|
|
|||
|
|
def _back_btn(cid, cb):
|
|||
|
|
return _btn("◀ Retour", discord.ButtonStyle.secondary, cid, cb)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── MON COMPTE (tout le monde, banquiers ont UserSelect) ───────
|
|||
|
|
|
|||
|
|
class ComptePanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
self.selected_user = None
|
|||
|
|
|
|||
|
|
is_banquier = has_role(author, "banquier")
|
|||
|
|
target_label = "👤 **Vous-même**"
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 💰 Mes Comptes"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Consultez vos comptes, faites des virements et gérez vos abonnements."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
if is_banquier:
|
|||
|
|
items.append(discord.ui.ActionRow(TargetUserSelect()))
|
|||
|
|
items.append(
|
|||
|
|
discord.ui.TextDisplay("* Sélectionnez un utilisateur ci-dessus pour opérer sur son compte."
|
|||
|
|
))
|
|||
|
|
items.append(discord.ui.Separator())
|
|||
|
|
|
|||
|
|
items.extend([
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("💰 Voir Compte", discord.ButtonStyle.primary, "cp_voir", self._voir),
|
|||
|
|
_btn("📤 Virement", discord.ButtonStyle.primary, "cp_vir", self._vir),
|
|||
|
|
_btn("🔄 Abonnement", discord.ButtonStyle.primary, "cp_abo", self._abo),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🏛️ Vir. Gouvernement", discord.ButtonStyle.primary, "cp_vg", self._vg),
|
|||
|
|
_btn("🏢 Vir. FBM", discord.ButtonStyle.primary, "cp_vfbm", self._vfbm),
|
|||
|
|
_btn("🏢 Vir. URSAFF", discord.ButtonStyle.primary, "cp_vurs", self._vurs),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_cp", self._back)),
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_BANK),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
def _target(self, interaction):
|
|||
|
|
return self.selected_user or interaction.user
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _voir(self, interaction):
|
|||
|
|
await interaction.response.send_modal(
|
|||
|
|
CompteModal(target_user=self._target(interaction))
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _vir(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementModal())
|
|||
|
|
|
|||
|
|
async def _abo(self, interaction):
|
|||
|
|
await interaction.response.send_modal(AbonnementModal())
|
|||
|
|
|
|||
|
|
async def _vg(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementModal())
|
|||
|
|
|
|||
|
|
async def _vfbm(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementFBMModal())
|
|||
|
|
|
|||
|
|
async def _vurs(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementURSAFFModal())
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── OPERATIONS BANQUIER (banquiers uniquement) ──────────────────
|
|||
|
|
|
|||
|
|
class BanquierPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
self.selected_user = None
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 🏦 Opérations Banquier"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Ouvrez des comptes, ajoutez/retirez de l'argent et consultez les transactions."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(TargetUserSelect(custom_id="bp_usel")),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🏦 Ouvrir Compte", discord.ButtonStyle.success, "bp_ouvrir", self._ouvrir),
|
|||
|
|
_btn("🏢 Ouvrir Compte ENT", discord.ButtonStyle.success, "bp_ouvrir_ent", self._ouvrir_ent),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("➕ Ajouter Argent", discord.ButtonStyle.primary, "bp_ajouter", self._ajouter),
|
|||
|
|
_btn("➖ Retirer Argent", discord.ButtonStyle.danger, "bp_retirer", self._retirer),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🏦 Vir. Banquier", discord.ButtonStyle.primary, "bp_vir_bq", self._vir_bq),
|
|||
|
|
_btn("🏢 Vir. Banquier ENT", discord.ButtonStyle.primary, "bp_vir_bq_ent", self._vir_bq_ent),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📜 Transactions", discord.ButtonStyle.secondary, "bp_tx", self._tx),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_bp", self._back)),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_BANQ_OP),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
def _target(self, interaction):
|
|||
|
|
return self.selected_user or interaction.user
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _ouvrir(self, interaction):
|
|||
|
|
await interaction.response.send_modal(
|
|||
|
|
OuvrirCompteSimpleModal(target_user=self._target(interaction))
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _ouvrir_ent(self, interaction):
|
|||
|
|
await interaction.response.send_modal(OuvrirCompteEntModal())
|
|||
|
|
|
|||
|
|
async def _ajouter(self, interaction):
|
|||
|
|
await interaction.response.send_modal(AjouterArgentModal())
|
|||
|
|
|
|||
|
|
async def _retirer(self, interaction):
|
|||
|
|
await interaction.response.send_modal(RetirerArgentModal())
|
|||
|
|
|
|||
|
|
async def _vir_bq(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementBanquierModal())
|
|||
|
|
|
|||
|
|
async def _vir_bq_ent(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementBanquierEntModal())
|
|||
|
|
|
|||
|
|
async def _tx(self, interaction):
|
|||
|
|
await interaction.response.send_modal(
|
|||
|
|
TransactionsModal(target_user=self._target(interaction))
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── GOUVERNEMENT (gouvernement uniquement) ─────────────────────
|
|||
|
|
|
|||
|
|
class GouvernementPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 🏛️ Gouvernement"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Comptes étatiques, FBM, URSAFF, Banque Nationale."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🏛️ Compte Gouv", discord.ButtonStyle.primary, "gp_cg", self._cg),
|
|||
|
|
_btn("💸 Virement Gouv", discord.ButtonStyle.primary, "gp_vg", self._vg),
|
|||
|
|
_btn("🏦 Retrait Gouv", discord.ButtonStyle.danger, "gp_rg", self._rg),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📄 Compte FBM", discord.ButtonStyle.primary, "gp_cfbm", self._cfbm),
|
|||
|
|
_btn("📤 Virement FBM", discord.ButtonStyle.primary, "gp_vfbm", self._vfbm),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📄 Compte URSAFF", discord.ButtonStyle.primary, "gp_curs", self._curs),
|
|||
|
|
_btn("📤 Virement URSAFF", discord.ButtonStyle.primary, "gp_vurs", self._vurs),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🏦 Banque Nationale", discord.ButtonStyle.primary, "gp_bn", self._bn),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_gp", self._back)),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_GOV),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _cg(self, interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
gouv = entreprises.get("Gouvernement", {}).get("GOUV")
|
|||
|
|
if not gouv:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Compte Gouvernement introuvable.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
solde = gouv.get("solde", 0)
|
|||
|
|
txs = gouv.get("transactions", [])
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🏛️ Compte Gouvernement",
|
|||
|
|
color=discord.Color.dark_gold(),
|
|||
|
|
)
|
|||
|
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
|||
|
|
for tx in txs[-5:]:
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"📄 {tx.get('date', 'N/A')}",
|
|||
|
|
value=(
|
|||
|
|
f"**{tx.get('type', 'N/A')}** — "
|
|||
|
|
f"{tx.get('montant', 0)}€ — {tx.get('source', 'N/A')}"
|
|||
|
|
),
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
if txs:
|
|||
|
|
embed.set_footer(text=f"{len(txs)} transaction(s) au total")
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
async def _vg(self, interaction):
|
|||
|
|
await interaction.response.send_modal(GouvVirerModal())
|
|||
|
|
|
|||
|
|
async def _rg(self, interaction):
|
|||
|
|
await interaction.response.send_modal(RetraitGouvModal())
|
|||
|
|
|
|||
|
|
async def _cfbm(self, interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
fbm = entreprises.get("fbm", {}).get("FBM", {})
|
|||
|
|
solde = fbm.get("solde", 0)
|
|||
|
|
txs = fbm.get("transactions", [])
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="📄 Compte FBM", color=discord.Color.orange()
|
|||
|
|
)
|
|||
|
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
|||
|
|
for tx in txs[-5:]:
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"📄 {tx.get('date', 'N/A')}",
|
|||
|
|
value=f"**{tx.get('type', 'N/A')}** — {tx.get('montant', 0)}€",
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
async def _vfbm(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementFBMModal())
|
|||
|
|
|
|||
|
|
async def _curs(self, interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
urs = entreprises.get("ursaff", {}).get("URSAFF", {})
|
|||
|
|
solde = urs.get("solde", 0)
|
|||
|
|
txs = urs.get("transactions", [])
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="📄 Compte URSAFF", color=discord.Color.orange()
|
|||
|
|
)
|
|||
|
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
|||
|
|
for tx in txs[-5:]:
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"📄 {tx.get('date', 'N/A')}",
|
|||
|
|
value=f"**{tx.get('type', 'N/A')}** — {tx.get('montant', 0)}€",
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
async def _vurs(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VirementURSAFFModal())
|
|||
|
|
|
|||
|
|
async def _bn(self, interaction):
|
|||
|
|
if not has_role(interaction.user, "gouvernement"):
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé au gouvernement.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
entreprises = _load_json("comptes_entreprises.json")
|
|||
|
|
bn = entreprises.get("banque_nationale", {}).get("BN", {})
|
|||
|
|
solde = bn.get("solde", 0)
|
|||
|
|
txs = bn.get("transactions", [])
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="🏦 Banque Nationale", color=discord.Color.blue()
|
|||
|
|
)
|
|||
|
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
|||
|
|
for tx in txs[-5:]:
|
|||
|
|
embed.add_field(
|
|||
|
|
name=f"📄 {tx.get('date', 'N/A')}",
|
|||
|
|
value=f"**{tx.get('type', 'N/A')}** — {tx.get('montant', 0)}€",
|
|||
|
|
inline=False,
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── IDENTITE (tout le monde, boutons conditionnels) ────────────
|
|||
|
|
|
|||
|
|
class IdentitePanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 🪪 Identité"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Cartes d'identité, permis, visites médicales."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🪪 Ma Carte", discord.ButtonStyle.primary, "ip_carte", self._carte),
|
|||
|
|
),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
if has_role(author, "gouvernement"):
|
|||
|
|
items.append(
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🪪 Créer Carte", discord.ButtonStyle.success, "ip_ccar", self._ccar),
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
action_items = []
|
|||
|
|
if has_role(author, "auto_ecole"):
|
|||
|
|
action_items.append(
|
|||
|
|
_btn("🚗 Permis", discord.ButtonStyle.primary, "ip_permis", self._permis)
|
|||
|
|
)
|
|||
|
|
if has_role(author, "ems"):
|
|||
|
|
action_items.append(
|
|||
|
|
_btn("🏥 Visite Médicale", discord.ButtonStyle.primary, "ip_vismed", self._vismed)
|
|||
|
|
)
|
|||
|
|
if action_items:
|
|||
|
|
items.append(discord.ui.ActionRow(*action_items))
|
|||
|
|
|
|||
|
|
items.extend([
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_ip", self._back)),
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_ID),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _carte(self, interaction):
|
|||
|
|
uid = str(interaction.user.id)
|
|||
|
|
dm = DataManager()
|
|||
|
|
identity = dm.identities.get(uid)
|
|||
|
|
if not identity:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Aucune carte trouvée.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
try:
|
|||
|
|
from utils.card_generator import CardGenerator
|
|||
|
|
|
|||
|
|
cg = CardGenerator()
|
|||
|
|
card_buffer = await cg.create_identity_card(interaction.user, identity)
|
|||
|
|
file = discord.File(card_buffer, filename="carte_identite.png")
|
|||
|
|
embed = discord.Embed(title="🪪 Carte d'identité", color=C_ID)
|
|||
|
|
embed.set_image(url="attachment://carte_identite.png")
|
|||
|
|
await interaction.response.send_message(file=file, embed=embed)
|
|||
|
|
except Exception as e:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"❌ Erreur : {e}", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _ccar(self, interaction):
|
|||
|
|
await interaction.response.send_modal(CreerCarteModal())
|
|||
|
|
|
|||
|
|
async def _permis(self, interaction):
|
|||
|
|
await interaction.response.send_modal(PermisModal())
|
|||
|
|
|
|||
|
|
async def _vismed(self, interaction):
|
|||
|
|
await interaction.response.send_modal(VisiteMedModal())
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── TICKETS & MESSAGES (admin uniquement) ──────────────────────
|
|||
|
|
|
|||
|
|
class TicketsPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 📩 Tickets & Messages"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Gestion des tickets et messages privés."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📑 Embed Ticket", discord.ButtonStyle.success, "tp_ticket", self._ticket),
|
|||
|
|
_btn("✉️ Envoyer MP", discord.ButtonStyle.primary, "tp_mp", self._mp),
|
|||
|
|
_btn("📢 MP à Tous", discord.ButtonStyle.danger, "tp_mptous", self._mptous),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_tp", self._back)),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_TICKET),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _ticket(self, interaction):
|
|||
|
|
if not interaction.user.guild_permissions.manage_guild:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Permission requise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="📩 Ticket Whitelist",
|
|||
|
|
description=(
|
|||
|
|
"Pour réaliser votre whitelist, ouvrez un ticket "
|
|||
|
|
"et remplissez le formulaire."
|
|||
|
|
),
|
|||
|
|
color=0x00FF00,
|
|||
|
|
)
|
|||
|
|
from commandes.ticket import TicketView
|
|||
|
|
|
|||
|
|
await interaction.channel.send(embed=embed, view=TicketView())
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"✅ Embed des tickets envoyé.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _mp(self, interaction):
|
|||
|
|
await interaction.response.send_modal(MessageModal())
|
|||
|
|
|
|||
|
|
async def _mptous(self, interaction):
|
|||
|
|
await interaction.response.send_modal(MessageTousModal())
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── SESSIONS RP (tout le monde) ────────────────────────────────
|
|||
|
|
|
|||
|
|
class SessionsPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 📅 Sessions RP"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Annonces de sessions et gestion des présences."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📢 Annoncer Session", discord.ButtonStyle.success, "sp_annonce", self._annonce),
|
|||
|
|
_btn("📋 Liste Présences", discord.ButtonStyle.primary, "sp_liste", self._liste),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_sp", self._back)),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_SESSION),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _annonce(self, interaction):
|
|||
|
|
await interaction.response.send_modal(AnnonceSessionModal())
|
|||
|
|
|
|||
|
|
async def _liste(self, interaction):
|
|||
|
|
await interaction.response.send_modal(ListePresenceModal())
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── CONFIGURATION (admin uniquement) ───────────────────────────
|
|||
|
|
|
|||
|
|
class ConfigPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## ⚙️ Configuration"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Configurer les rôles, salons et catégories de ce serveur."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🎭 Définir Rôle", discord.ButtonStyle.primary, "cfg_role", self._crole),
|
|||
|
|
_btn("📢 Définir Salon", discord.ButtonStyle.primary, "cfg_chan", self._cchan),
|
|||
|
|
_btn("📁 Définir Catégorie", discord.ButtonStyle.primary, "cfg_cat", self._ccat),
|
|||
|
|
),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("👁️ Voir Config", discord.ButtonStyle.secondary, "cfg_voir", self._cvoir),
|
|||
|
|
_btn("🗑️ Reset Config", discord.ButtonStyle.danger, "cfg_reset", self._creset),
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_cfg", self._back)),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_CONFIG),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _crole(self, interaction):
|
|||
|
|
await interaction.response.send_modal(ConfigRoleModal())
|
|||
|
|
|
|||
|
|
async def _cchan(self, interaction):
|
|||
|
|
await interaction.response.send_modal(ConfigChannelModal())
|
|||
|
|
|
|||
|
|
async def _ccat(self, interaction):
|
|||
|
|
await interaction.response.send_modal(ConfigCategoryModal())
|
|||
|
|
|
|||
|
|
async def _cvoir(self, interaction):
|
|||
|
|
if not interaction.user.guild_permissions.manage_guild:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Permission requise.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
config = load_guild_config(interaction.guild.id)
|
|||
|
|
embed = discord.Embed(
|
|||
|
|
title="⚙️ Configuration actuelle", color=C_CONFIG
|
|||
|
|
)
|
|||
|
|
roles_text = ""
|
|||
|
|
for key, label in ROLE_LABELS.items():
|
|||
|
|
rid = config.get("roles", {}).get(key)
|
|||
|
|
if rid:
|
|||
|
|
role = interaction.guild.get_role(int(rid))
|
|||
|
|
roles_text += f"> {label} : {role.mention if role else f'❌ {rid}'}\n"
|
|||
|
|
else:
|
|||
|
|
roles_text += f"> {label} : ⚠️ Non défini\n"
|
|||
|
|
embed.add_field(name="🎭 Rôles", value=roles_text, inline=False)
|
|||
|
|
channels_text = ""
|
|||
|
|
for key, label in CHANNEL_LABELS.items():
|
|||
|
|
cid = config.get("channels", {}).get(key)
|
|||
|
|
if cid:
|
|||
|
|
ch = interaction.guild.get_channel(int(cid))
|
|||
|
|
channels_text += (
|
|||
|
|
f"> {label} : {ch.mention if ch else f'❌ {cid}'}\n"
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
channels_text += f"> {label} : ⚠️ Non défini\n"
|
|||
|
|
embed.add_field(name="📢 Salons", value=channels_text, inline=False)
|
|||
|
|
cats_text = ""
|
|||
|
|
for key, label in CATEGORY_LABELS.items():
|
|||
|
|
catid = config.get("categories", {}).get(key)
|
|||
|
|
if catid:
|
|||
|
|
cat = interaction.guild.get_channel(int(catid))
|
|||
|
|
cats_text += (
|
|||
|
|
f"> {label} : **{cat.name}**\n" if cat
|
|||
|
|
else f"> {label} : ❌ {catid}\n"
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
cats_text += f"> {label} : ⚠️ Non défini\n"
|
|||
|
|
embed.add_field(name="📁 Catégories", value=cats_text, inline=False)
|
|||
|
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
|||
|
|
|
|||
|
|
async def _creset(self, interaction):
|
|||
|
|
if not interaction.user.guild_permissions.administrator:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"❌ Réservé aux administrateurs.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
save_guild_config(
|
|||
|
|
interaction.guild.id,
|
|||
|
|
{"roles": {}, "channels": {}, "categories": {}},
|
|||
|
|
)
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"✅ Configuration réinitialisée.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─── DIVERS (tout le monde) ─────────────────────────────────────
|
|||
|
|
|
|||
|
|
class DiversPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
|
|||
|
|
items = [
|
|||
|
|
discord.ui.TextDisplay("## 🎲 Divers"),
|
|||
|
|
discord.ui.TextDisplay("Lancer de dé et autres outils."),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("🎲 Lancer un Dé", discord.ButtonStyle.primary, "dp_roll", self._roll),
|
|||
|
|
),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
if author.guild_permissions.administrator:
|
|||
|
|
items.append(
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
_btn("📊 Stats Bot", discord.ButtonStyle.secondary, "dp_stats", self._stats),
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
items.extend([
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(_back_btn("back_dp", self._back)),
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
*items,
|
|||
|
|
accent_colour=discord.Colour(C_FUN),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def _back(self, interaction):
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=MainPanelView(interaction.user, self.bot_ref)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
async def _roll(self, interaction):
|
|||
|
|
await interaction.response.send_modal(RollModal())
|
|||
|
|
|
|||
|
|
async def _stats(self, interaction):
|
|||
|
|
from utils.stats_manager import get_stats_detailed
|
|||
|
|
import io
|
|||
|
|
|
|||
|
|
stats = get_stats_detailed()
|
|||
|
|
if not stats:
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
"📊 Aucune statistique disponible.", ephemeral=True
|
|||
|
|
)
|
|||
|
|
return
|
|||
|
|
await interaction.response.send_message(
|
|||
|
|
f"📊 **Statistiques du bot**\n```json\n{json.dumps(stats, indent=2, ensure_ascii=False)[:1800]}\n```",
|
|||
|
|
ephemeral=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# PANEL PRINCIPAL — MENU ADAPTATIF
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class CategorySelect(discord.ui.Select):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
options = [
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Mes Comptes",
|
|||
|
|
description="Comptes, virements, abonnements",
|
|||
|
|
emoji="💰",
|
|||
|
|
value="compte",
|
|||
|
|
),
|
|||
|
|
]
|
|||
|
|
if has_role(author, "banquier"):
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Opérations Banquier",
|
|||
|
|
description="Ouvrir comptes, ajouter/retirer, transactions",
|
|||
|
|
emoji="🏦",
|
|||
|
|
value="banquier",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
if has_role(author, "gouvernement"):
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Gouvernement",
|
|||
|
|
description="Comptes étatiques, FBM, URSAFF",
|
|||
|
|
emoji="🏛️",
|
|||
|
|
value="gouvernement",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Identité",
|
|||
|
|
description="Cartes d'identité, permis, visite médicale",
|
|||
|
|
emoji="🪪",
|
|||
|
|
value="identite",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
if author.guild_permissions.administrator:
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Tickets & Messages",
|
|||
|
|
description="Tickets, MP privés",
|
|||
|
|
emoji="📩",
|
|||
|
|
value="tickets",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Sessions RP",
|
|||
|
|
description="Annonces, présences",
|
|||
|
|
emoji="📅",
|
|||
|
|
value="sessions",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Divers",
|
|||
|
|
description="Dé, stats",
|
|||
|
|
emoji="🎲",
|
|||
|
|
value="divers",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
if author.guild_permissions.manage_guild:
|
|||
|
|
options.append(
|
|||
|
|
discord.SelectOption(
|
|||
|
|
label="Configuration",
|
|||
|
|
description="Configurer le bot",
|
|||
|
|
emoji="⚙️",
|
|||
|
|
value="config",
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
super().__init__(
|
|||
|
|
placeholder="Sélectionnez une catégorie...",
|
|||
|
|
options=options,
|
|||
|
|
custom_id="pnl_catselect",
|
|||
|
|
)
|
|||
|
|
self._bot = bot
|
|||
|
|
|
|||
|
|
async def callback(self, interaction: discord.Interaction):
|
|||
|
|
view_map = {
|
|||
|
|
"compte": ComptePanelView,
|
|||
|
|
"banquier": BanquierPanelView,
|
|||
|
|
"gouvernement": GouvernementPanelView,
|
|||
|
|
"identite": IdentitePanelView,
|
|||
|
|
"tickets": TicketsPanelView,
|
|||
|
|
"sessions": SessionsPanelView,
|
|||
|
|
"config": ConfigPanelView,
|
|||
|
|
"divers": DiversPanelView,
|
|||
|
|
}
|
|||
|
|
cls = view_map.get(self.values[0])
|
|||
|
|
if cls:
|
|||
|
|
await interaction.response.edit_message(
|
|||
|
|
view=cls(interaction.user, self._bot)
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class MainPanelView(discord.ui.LayoutView):
|
|||
|
|
def __init__(self, author, bot):
|
|||
|
|
super().__init__(timeout=300)
|
|||
|
|
self.author = author
|
|||
|
|
self.bot_ref = bot
|
|||
|
|
self.message = None
|
|||
|
|
|
|||
|
|
role_parts = []
|
|||
|
|
if has_role(author, "banquier"):
|
|||
|
|
role_parts.append("🏦 Banquier")
|
|||
|
|
if has_role(author, "gouvernement"):
|
|||
|
|
role_parts.append("🏛️ Gouvernement")
|
|||
|
|
if has_role(author, "ems"):
|
|||
|
|
role_parts.append("🏥 EMS")
|
|||
|
|
if has_role(author, "auto_ecole"):
|
|||
|
|
role_parts.append("🚗 Auto-école")
|
|||
|
|
if author.guild_permissions.administrator:
|
|||
|
|
role_parts.append("👑 Admin")
|
|||
|
|
role_text = " • ".join(role_parts) if role_parts else "👤 Citoyen"
|
|||
|
|
|
|||
|
|
self.add_item(discord.ui.Container(
|
|||
|
|
discord.ui.TextDisplay("## 🏦 Victoria's Vice — Panel de Commandes"),
|
|||
|
|
discord.ui.TextDisplay(f"**Vos rôles :** {role_text}"),
|
|||
|
|
discord.ui.TextDisplay(
|
|||
|
|
"Sélectionnez une catégorie ci-dessous pour accéder aux commandes."
|
|||
|
|
),
|
|||
|
|
discord.ui.Separator(),
|
|||
|
|
discord.ui.ActionRow(
|
|||
|
|
CategorySelect(author, bot)
|
|||
|
|
),
|
|||
|
|
accent_colour=discord.Colour(C_MAIN),
|
|||
|
|
))
|
|||
|
|
|
|||
|
|
async def on_timeout(self):
|
|||
|
|
if self.message:
|
|||
|
|
try:
|
|||
|
|
await self.message.edit(
|
|||
|
|
content="⏰ Panel expiré. Utilisez `/panel` pour le rouvrir.",
|
|||
|
|
view=None,
|
|||
|
|
)
|
|||
|
|
except discord.HTTPException:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
# COG
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class Panel(commands.Cog):
|
|||
|
|
def __init__(self, bot):
|
|||
|
|
self.bot = bot
|
|||
|
|
|
|||
|
|
@app_commands.command(
|
|||
|
|
name="panel", description="Ouvre le panneau de commandes du bot"
|
|||
|
|
)
|
|||
|
|
async def panel(self, interaction: discord.Interaction):
|
|||
|
|
view = MainPanelView(interaction.user, self.bot)
|
|||
|
|
await interaction.response.send_message(view=view, ephemeral=False)
|
|||
|
|
view.message = await interaction.original_response()
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def setup(bot):
|
|||
|
|
await bot.add_cog(Panel(bot))
|