Initial commit: bot Discord Vicy V1.8
This commit is contained in:
commit
56958c5832
70 changed files with 8469 additions and 0 deletions
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Secrets
|
||||||
|
.env
|
||||||
|
config.json
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
|
||||||
|
# Virtual environment
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# Data & logs
|
||||||
|
data/
|
||||||
|
log.txt
|
||||||
|
|
||||||
|
# OS
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
133
__main__.py
Normal file
133
__main__.py
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
import discord
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
from bot import bot
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands, Intents
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
from discord import Intents, Permissions
|
||||||
|
from utils.stats_manager import enregistrer_utilisation, get_stats
|
||||||
|
|
||||||
|
# Configuration du logger Discord (niveau DEBUG pour afficher tous les événements importants)
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
discord.utils.setup_logging(level=logging.DEBUG, root=False)
|
||||||
|
|
||||||
|
# Configuration des intents
|
||||||
|
intents = Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
intents.guilds = True
|
||||||
|
intents.members = True
|
||||||
|
intents.reactions = True
|
||||||
|
|
||||||
|
# Permissions du bot
|
||||||
|
permissions = Permissions()
|
||||||
|
permissions.update(
|
||||||
|
manage_nicknames=True,
|
||||||
|
send_messages=True,
|
||||||
|
read_messages=True,
|
||||||
|
manage_channels=True,
|
||||||
|
manage_messages=True,
|
||||||
|
add_reactions=True,
|
||||||
|
use_application_commands=True,
|
||||||
|
view_channel=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialisation du bot
|
||||||
|
bot = commands.Bot(command_prefix="!", application_id="1310235313461002241", intents=intents)
|
||||||
|
|
||||||
|
async def load_cogs():
|
||||||
|
"""Charge toutes les commandes."""
|
||||||
|
extensions = [
|
||||||
|
"commandes.message",
|
||||||
|
"commandes.identite",
|
||||||
|
"commandes.voir_carte_identite",
|
||||||
|
"commandes.virement",
|
||||||
|
"commandes.transactions",
|
||||||
|
"commandes.ajouter_argent",
|
||||||
|
"commandes.ticket",
|
||||||
|
"commandes.restranscription_staff",
|
||||||
|
"utils.welcome_message",
|
||||||
|
"commandes.permis",
|
||||||
|
"commandes.ouvrir_compte",
|
||||||
|
"commandes.compte",
|
||||||
|
"commandes.change_nickname",
|
||||||
|
"commandes.rename_all_on_join",
|
||||||
|
"commandes.message_tous",
|
||||||
|
"commandes.retirer_argent",
|
||||||
|
"commandes.ouvrir_comptes_entreprises",
|
||||||
|
"commandes.compte_gouvernement",
|
||||||
|
"commandes.comptes_entreprises",
|
||||||
|
"commandes.compte_urssaf",
|
||||||
|
"commandes.compte_banque_nationale",
|
||||||
|
"commandes.virement_entreprise",
|
||||||
|
"commandes.virement_gouvernement",
|
||||||
|
"commandes.valider_visite_médicale",
|
||||||
|
"commandes.abonnement",
|
||||||
|
"commandes.virement_banquier",
|
||||||
|
"commandes.virement_banquier_entreprise",
|
||||||
|
"commandes.compte_fbm",
|
||||||
|
"commandes.virement_fbm",
|
||||||
|
"commandes.virement_ursaff",
|
||||||
|
"commandes.stats_commandes",
|
||||||
|
"commandes.taches",
|
||||||
|
"commandes.roll",
|
||||||
|
"commandes.annonces_sessions", # Fait : V1.7 correction des annonces de sessions
|
||||||
|
"commandes.retrait_gouv",
|
||||||
|
"commandes.absence_staff", # Fait : V1.7 pouvoir voir plus de 3 absences staff (pagination)
|
||||||
|
"commandes.liste_taches", # Fait : V1.7 Rebuild du système de taches pour le rendre plus moderne
|
||||||
|
"commandes.counting"
|
||||||
|
|
||||||
|
|
||||||
|
# Pas fait : V1.8 Amélioration des stats de commandes ajouts de courbes et de graphiques + Voir le top 10 des personnes qui utilisent le plus les commandes
|
||||||
|
]
|
||||||
|
|
||||||
|
for ext in extensions:
|
||||||
|
try:
|
||||||
|
await bot.load_extension(ext)
|
||||||
|
log_info(f"Extension chargée : {ext}")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"Erreur lors du chargement de {ext} : {e}")
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
# Affiche que le bot est prêt et synchronise les commandes slash
|
||||||
|
log_info(f"Connecté en tant que {bot.user}")
|
||||||
|
await load_cogs()
|
||||||
|
await bot.tree.sync()
|
||||||
|
await bot.change_presence(activity=discord.Game(name="la V1.6")) # Ajout du status
|
||||||
|
log_info("Commandes synchronisées.")
|
||||||
|
|
||||||
|
# Gère les erreurs de commandes classiques
|
||||||
|
@bot.event
|
||||||
|
async def on_command_error(ctx, error):
|
||||||
|
log_error(f"Erreur dans la commande {ctx.command}: {error}")
|
||||||
|
|
||||||
|
# Gère toutes les autres erreurs inattendues
|
||||||
|
@bot.event
|
||||||
|
async def on_error(event_method, *args, **kwargs):
|
||||||
|
log_error(f"Erreur non gérée dans l'événement {event_method}", exc_info=True)
|
||||||
|
|
||||||
|
# 👉 Enregistre chaque commande slash utilisée
|
||||||
|
@bot.event
|
||||||
|
async def on_app_command_completion(interaction: discord.Interaction, command: app_commands.Command):
|
||||||
|
try:
|
||||||
|
user_id = interaction.user.id
|
||||||
|
guild_id = interaction.guild.id if interaction.guild else 0
|
||||||
|
enregistrer_utilisation(command.name, user_id, guild_id)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"Erreur en enregistrant les stats : {e}")
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# Charge les variables d'environnement et démarre le bot
|
||||||
|
load_dotenv()
|
||||||
|
token = os.getenv("TOKEN")
|
||||||
|
try:
|
||||||
|
log_info("Démarrage du bot...")
|
||||||
|
await bot.start(token)
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"Erreur critique: {e}", exc_info=True)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
218
abonnements.json
Normal file
218
abonnements.json
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"nom": "Test",
|
||||||
|
"rib_emetteur": "22144 59424 87742058459 72",
|
||||||
|
"rib_receveur": "66427 49104 57218570654 78",
|
||||||
|
"montant": 1.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "samedi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "36495 80083 39542816185 27",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "26384 93370 75890178377 91",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "22144 59424 87742058459 72",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "85047 60626 80894743346 94",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "28777 24580 29765721710 42",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "24483 98056 61791340797 80",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "10009 40554 56452790470 78",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "76644 32901 90493249064 16",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "15563 69899 51361446295 84",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "22128 86524 35982837421 58",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "55868 11389 89049343014 38",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "93266 82343 74845298309 22",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "10234 24218 10477731114 78",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "50970 51336 33017058086 50",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "87292 81104 84784268868 12",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "51229 80290 86979675797 93",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "28794 77878 41312953164 71",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "78740 15751 70195185799 30",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "92871 52823 19649316403 70",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frais_bancaire_et_de_gestion_1",
|
||||||
|
"rib_emetteur": "73834 54818 11833486819 17",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 5.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Frog",
|
||||||
|
"rib_emetteur": "48003 84424 36961155485 64",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 700.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Di regia",
|
||||||
|
"rib_emetteur": "10009 40554 56452790470 78",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 4000.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Leonardo",
|
||||||
|
"rib_emetteur": "24756 54403 68357307735 95",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 4000.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Correa",
|
||||||
|
"rib_emetteur": "28794 77878 41312953164 71",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 4300.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "jose",
|
||||||
|
"rib_emetteur": "87292 81104 84784268868 12",
|
||||||
|
"rib_receveur": "15156 38436 35920 54357",
|
||||||
|
"montant": 800.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"nom": "Paye_de_Salvatore_Di_Regia",
|
||||||
|
"rib_emetteur": "15156 38436 35920 54357",
|
||||||
|
"rib_receveur": "10009 40554 56452790470 78",
|
||||||
|
"montant": 5000.0,
|
||||||
|
"banque": "NGC Bank",
|
||||||
|
"jour": "dimanche"
|
||||||
|
}
|
||||||
|
]
|
||||||
47
absences.json
Normal file
47
absences.json
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"534003230435442690": {
|
||||||
|
"pseudo": "nixfix06",
|
||||||
|
"debut": "25/06/2025",
|
||||||
|
"fin": "01/09/2025",
|
||||||
|
"motif": "je travaille",
|
||||||
|
"superieur": "Aucun",
|
||||||
|
"message_id": 1386993295766323202,
|
||||||
|
"etat": "en cours"
|
||||||
|
},
|
||||||
|
"828923448453103637": {
|
||||||
|
"pseudo": "blancandwhite",
|
||||||
|
"debut": "04/07/2025",
|
||||||
|
"fin": "28/07/2025",
|
||||||
|
"motif": "vacances",
|
||||||
|
"superieur": "<@1108087282692522105>",
|
||||||
|
"message_id": 1389892250317750322,
|
||||||
|
"etat": "en cours"
|
||||||
|
},
|
||||||
|
"914118793918312480": {
|
||||||
|
"pseudo": "neyzizz",
|
||||||
|
"debut": "20/07/2025",
|
||||||
|
"fin": "27/07/2025",
|
||||||
|
"motif": "vacances en montagne",
|
||||||
|
"superieur": "Aucun",
|
||||||
|
"message_id": 1390747833958662154,
|
||||||
|
"etat": "en cours"
|
||||||
|
},
|
||||||
|
"727188532669448509": {
|
||||||
|
"pseudo": "nuggets.png",
|
||||||
|
"debut": "21/07/2025",
|
||||||
|
"fin": "22/07/2025",
|
||||||
|
"motif": "je fouette mg",
|
||||||
|
"superieur": "<@1069386396764221450>",
|
||||||
|
"message_id": 1396650241679294515,
|
||||||
|
"etat": "en cours"
|
||||||
|
},
|
||||||
|
"1069386396764221450": {
|
||||||
|
"pseudo": "matlo13",
|
||||||
|
"debut": "21/07/2025",
|
||||||
|
"fin": "22/07/2025",
|
||||||
|
"motif": "text",
|
||||||
|
"superieur": "Aucun",
|
||||||
|
"message_id": 1396650262252355584,
|
||||||
|
"etat": "en cours"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
banque_data.json
Normal file
1
banque_data.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
25
bot.py
Normal file
25
bot.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
from discord.ext import commands
|
||||||
|
import discord
|
||||||
|
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
intents.members = True
|
||||||
|
|
||||||
|
bot = commands.Bot(command_prefix='/', intents=intents)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
try:
|
||||||
|
log_info(f"Le bot {bot.user} a démarré avec succès.")
|
||||||
|
await bot.change_presence(activity=discord.Game(name="la version 1.2"))
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"Erreur lors du démarrage du bot: {e}")
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
try:
|
||||||
|
synced = await bot.tree.sync()
|
||||||
|
print(f"Synchronisé {len(synced)} commande(s)")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de la synchronisation des commandes : {e}")
|
||||||
66
commandes/Backup/absence_staff.py
Normal file
66
commandes/Backup/absence_staff.py
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
class AbsenceStaff(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.absences = {}
|
||||||
|
|
||||||
|
@app_commands.command(name="absence_staff", description="Indiquez votre absence en tant que staff.")
|
||||||
|
async def absence_staff(self, interaction: discord.Interaction, duree: str, debut: str, fin: str, raison: str, superieur: discord.Member):
|
||||||
|
"""Indiquez votre absence en tant que staff."""
|
||||||
|
try:
|
||||||
|
# Convertir les dates
|
||||||
|
debut_date = datetime.strptime(debut, "%d/%m/%Y")
|
||||||
|
fin_date = datetime.strptime(fin, "%d/%m/%Y")
|
||||||
|
|
||||||
|
# Calculer la durée en jours
|
||||||
|
if duree.endswith('s'): # Si la durée est en semaines
|
||||||
|
duree_jours = int(duree[:-1]) * 7
|
||||||
|
else:
|
||||||
|
duree_jours = int(duree)
|
||||||
|
|
||||||
|
# Vérifier la cohérence des dates
|
||||||
|
if (fin_date - debut_date).days != duree_jours:
|
||||||
|
await interaction.response.send_message("❌ Erreur : La durée spécifiée ne correspond pas aux dates fournies.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Enregistrer l'absence
|
||||||
|
self.absences[interaction.user.id] = {
|
||||||
|
"debut": debut_date,
|
||||||
|
"fin": fin_date,
|
||||||
|
"raison": raison,
|
||||||
|
"superieur": superieur.id
|
||||||
|
}
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Votre absence a été enregistrée, {interaction.user.mention}.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await interaction.response.send_message(f"❌ Erreur : {str(e)}")
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
# Ignorer les messages envoyés par le bot
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier si un utilisateur absent est mentionné
|
||||||
|
for user_id, absence in self.absences.items():
|
||||||
|
user = self.bot.get_user(user_id)
|
||||||
|
if user and user in message.mentions:
|
||||||
|
# Répondre avec un message indiquant l'absence
|
||||||
|
await message.channel.send(
|
||||||
|
f"{user.display_name} est actuellement absent(e).\n"
|
||||||
|
f"Raison : {absence['raison']}\n"
|
||||||
|
f"Retour prévu le : {absence['fin'].strftime('%d/%m/%Y')}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Supprimer le message avec la mention
|
||||||
|
await message.delete()
|
||||||
|
break
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(AbsenceStaff(bot))
|
||||||
|
print("Commande /absence_staff chargée !")
|
||||||
5
commandes/__init__.py
Normal file
5
commandes/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Pour la V1.2 Ajouter des statistiques d'utlisation du bot
|
||||||
|
# Pour la V1.3 Corriger le système de claim des tickets WL (Les anciens propriétaires de ticket garde les permission même après une reprise par quelqu'un d'autre)
|
||||||
|
# Pour la V1.3 Ajouter la commande /compte_utilisateur @[de_l'utilisateur] : affiche le compte d'un autre utilisateur (Banquier Only)
|
||||||
|
# Pour la V1.3 Pouvoir voir les cartes d'identités des autres quand on la le rôle gouvernement
|
||||||
|
# Pour la V1.3 Pouvoir fermer des comptes bancaires ou/et pouvoir régénérer un rib si on est banquier
|
||||||
148
commandes/abonnement.py
Normal file
148
commandes/abonnement.py
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
import json
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
ABONNEMENTS_FILE = "abonnements.json"
|
||||||
|
|
||||||
|
BANQUES_DISPONIBLES = [
|
||||||
|
"Victoria's Credit Bank",
|
||||||
|
"NGC Bank"
|
||||||
|
]
|
||||||
|
|
||||||
|
JOURS_SEMAINE = [
|
||||||
|
"lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"
|
||||||
|
]
|
||||||
|
|
||||||
|
class Abonnement(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.abonnements = self.load_abonnements()
|
||||||
|
self.executer_abonnements.start()
|
||||||
|
|
||||||
|
def load_abonnements(self):
|
||||||
|
try:
|
||||||
|
with open(ABONNEMENTS_FILE, 'r', encoding='utf-8') as f:
|
||||||
|
return json.load(f)
|
||||||
|
except (FileNotFoundError, json.JSONDecodeError):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def save_abonnements(self):
|
||||||
|
with open(ABONNEMENTS_FILE, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(self.abonnements, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
# 🎯 Auto-complétion pour les banques
|
||||||
|
async def autocomplete_banque(self, interaction: discord.Interaction, current: str):
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=b, value=b)
|
||||||
|
for b in BANQUES_DISPONIBLES if current.lower() in b.lower()
|
||||||
|
]
|
||||||
|
|
||||||
|
# 🎯 Auto-complétion pour les jours
|
||||||
|
async def autocomplete_jour(self, interaction: discord.Interaction, current: str):
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=day.capitalize(), value=day)
|
||||||
|
for day in JOURS_SEMAINE if current.lower() in day
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="abonnement", description="Crée un abonnement bancaire hebdomadaire.")
|
||||||
|
@app_commands.describe(
|
||||||
|
nom="Nom de l'abonnement",
|
||||||
|
rib_emetteur="RIB de l'expéditeur",
|
||||||
|
montant="Montant à envoyer",
|
||||||
|
rib_receveur="RIB du bénéficiaire",
|
||||||
|
banque="Nom de la banque",
|
||||||
|
jour="Jour de la semaine du virement"
|
||||||
|
)
|
||||||
|
@app_commands.autocomplete(banque=autocomplete_banque, jour=autocomplete_jour)
|
||||||
|
async def abonnement(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
nom: str,
|
||||||
|
rib_emetteur: str,
|
||||||
|
montant: float,
|
||||||
|
rib_receveur: str,
|
||||||
|
banque: str,
|
||||||
|
jour: str
|
||||||
|
):
|
||||||
|
if jour.lower() not in JOURS_SEMAINE:
|
||||||
|
await interaction.response.send_message("❌ Jour invalide. Choisissez un jour valide de la semaine.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
abonnement = {
|
||||||
|
"nom": nom,
|
||||||
|
"rib_emetteur": rib_emetteur,
|
||||||
|
"rib_receveur": rib_receveur,
|
||||||
|
"montant": montant,
|
||||||
|
"banque": banque,
|
||||||
|
"jour": jour.lower()
|
||||||
|
}
|
||||||
|
|
||||||
|
self.abonnements.append(abonnement)
|
||||||
|
self.save_abonnements()
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Abonnement **{nom}** enregistré. Virement automatique tous les **{jour}**.", ephemeral=True)
|
||||||
|
|
||||||
|
@tasks.loop(minutes=60)
|
||||||
|
async def executer_abonnements(self):
|
||||||
|
today = datetime.datetime.now().strftime("%A").lower()
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except:
|
||||||
|
comptes = {}
|
||||||
|
|
||||||
|
updated = False
|
||||||
|
for abonnement in self.abonnements:
|
||||||
|
if abonnement["jour"] != today:
|
||||||
|
continue
|
||||||
|
|
||||||
|
banque = abonnement["banque"]
|
||||||
|
rib_emetteur = abonnement["rib_emetteur"]
|
||||||
|
rib_receveur = abonnement["rib_receveur"]
|
||||||
|
montant = abonnement["montant"]
|
||||||
|
|
||||||
|
destinataire_id = None
|
||||||
|
emetteur_id = None
|
||||||
|
|
||||||
|
for user_id, data in comptes.get(banque, {}).items():
|
||||||
|
if data.get("rib") == rib_emetteur:
|
||||||
|
emetteur_id = user_id
|
||||||
|
if data.get("rib") == rib_receveur:
|
||||||
|
destinataire_id = user_id
|
||||||
|
|
||||||
|
if not emetteur_id or not destinataire_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if comptes[banque][emetteur_id]["solde"] < montant:
|
||||||
|
continue
|
||||||
|
|
||||||
|
comptes[banque][emetteur_id]["solde"] -= montant
|
||||||
|
comptes[banque][emetteur_id]["transactions"].append({
|
||||||
|
"date": datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement automatique (abonnement)",
|
||||||
|
"source": f"Vers RIB {rib_receveur}",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
comptes[banque][destinataire_id]["solde"] += montant
|
||||||
|
comptes[banque][destinataire_id]["transactions"].append({
|
||||||
|
"date": datetime.datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement reçu (abonnement)",
|
||||||
|
"source": f"{rib_emetteur}",
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
updated = True
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
with open("comptes_bancaires.json", 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(comptes, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
@executer_abonnements.before_loop
|
||||||
|
async def before_abonnement_loop(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Abonnement(bot))
|
||||||
224
commandes/absence_staff.py
Normal file
224
commandes/absence_staff.py
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from discord import app_commands, ui
|
||||||
|
import discord
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
ABSENCE_CHANNEL_ID = 1369669999677145099
|
||||||
|
ABSENCE_FILE = "absences.json"
|
||||||
|
ABSENCE_FILE_TMP = "absences.json.tmp"
|
||||||
|
file_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def load_absences():
|
||||||
|
async with file_lock:
|
||||||
|
try:
|
||||||
|
with open(ABSENCE_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
async def save_absences(data):
|
||||||
|
async with file_lock:
|
||||||
|
with open(ABSENCE_FILE_TMP, "w") as f:
|
||||||
|
json.dump(data, f, indent=4)
|
||||||
|
os.replace(ABSENCE_FILE_TMP, ABSENCE_FILE)
|
||||||
|
|
||||||
|
class Absence(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.check_absences.start()
|
||||||
|
|
||||||
|
@commands.hybrid_command(name="absence", with_app_command=True)
|
||||||
|
async def absence(self, ctx, motif: str, date_debut: str, date_fin: str, superieur: discord.Member = None):
|
||||||
|
try:
|
||||||
|
debut = datetime.strptime(date_debut, "%d/%m/%Y")
|
||||||
|
fin = datetime.strptime(date_fin, "%d/%m/%Y")
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send("❌ Format de date invalide. Utilise JJ/MM/AAAA.", ephemeral=True)
|
||||||
|
|
||||||
|
if debut > fin:
|
||||||
|
return await ctx.send("❌ La date de début doit précéder la date de fin.", ephemeral=True)
|
||||||
|
|
||||||
|
abs_data = await load_absences()
|
||||||
|
if str(ctx.author.id) in abs_data:
|
||||||
|
return await ctx.send("❌ Tu as déjà déclaré une absence. Utilise `/fin_absence` pour la terminer.", ephemeral=True)
|
||||||
|
|
||||||
|
duree = (fin - debut).days + 1
|
||||||
|
etat = "à venir" if debut > datetime.today() else "en cours"
|
||||||
|
|
||||||
|
abs_data[str(ctx.author.id)] = {
|
||||||
|
"pseudo": ctx.author.name,
|
||||||
|
"debut": date_debut,
|
||||||
|
"fin": date_fin,
|
||||||
|
"motif": motif,
|
||||||
|
"superieur": superieur.mention if superieur else "Aucun",
|
||||||
|
"message_id": None,
|
||||||
|
"etat": etat
|
||||||
|
}
|
||||||
|
await save_absences(abs_data)
|
||||||
|
|
||||||
|
channel = self.bot.get_channel(ABSENCE_CHANNEL_ID)
|
||||||
|
if not channel:
|
||||||
|
return await ctx.send("❌ Salon d'absence introuvable. Vérifie l'ID.", ephemeral=True)
|
||||||
|
|
||||||
|
absence_message = await channel.send(
|
||||||
|
f"# ABSENCE STAFF :\n"
|
||||||
|
f"- **Pseudo Discord** : {ctx.author.mention}\n"
|
||||||
|
f"- **Durée** : {duree} jours\n"
|
||||||
|
f"- **Débute le** : {date_debut}\n"
|
||||||
|
f"- **Termine le** : {date_fin}\n"
|
||||||
|
f"- **Motif** : {motif}\n"
|
||||||
|
f"- **Mention du supérieur hiérarchique** : {superieur.mention if superieur else 'Aucun'}"
|
||||||
|
)
|
||||||
|
|
||||||
|
abs_data[str(ctx.author.id)]["message_id"] = absence_message.id
|
||||||
|
await save_absences(abs_data)
|
||||||
|
|
||||||
|
await ctx.send("✅ Absence enregistrée avec succès !", ephemeral=True)
|
||||||
|
|
||||||
|
@commands.hybrid_command(name="fin_absence", with_app_command=True)
|
||||||
|
async def fin_absence(self, ctx):
|
||||||
|
abs_data = await load_absences()
|
||||||
|
user_id = str(ctx.author.id)
|
||||||
|
|
||||||
|
if user_id not in abs_data:
|
||||||
|
return await ctx.send("❌ Tu n'as pas d'absence en cours.", ephemeral=True)
|
||||||
|
|
||||||
|
message_id = abs_data[user_id].get("message_id")
|
||||||
|
channel = self.bot.get_channel(ABSENCE_CHANNEL_ID)
|
||||||
|
if message_id and channel:
|
||||||
|
try:
|
||||||
|
msg = await channel.fetch_message(message_id)
|
||||||
|
await msg.delete()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
del abs_data[user_id]
|
||||||
|
await save_absences(abs_data)
|
||||||
|
await ctx.send("✅ Ton absence a été retirée.", ephemeral=True)
|
||||||
|
|
||||||
|
@commands.hybrid_command(name="liste_absences", with_app_command=True)
|
||||||
|
async def liste_absences(self, ctx):
|
||||||
|
abs_data = await load_absences()
|
||||||
|
absences = [
|
||||||
|
(user_id, info) for user_id, info in abs_data.items()
|
||||||
|
if info.get("etat") == "en cours"
|
||||||
|
]
|
||||||
|
|
||||||
|
if not absences:
|
||||||
|
return await ctx.send("Aucune absence staff en cours.", ephemeral=True)
|
||||||
|
|
||||||
|
per_page = 3
|
||||||
|
pages = [absences[i:i + per_page] for i in range(0, len(absences), per_page)]
|
||||||
|
|
||||||
|
def create_embed(page_index: int) -> discord.Embed:
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"📋 Absences staff en cours (Page {page_index + 1}/{len(pages)})",
|
||||||
|
color=discord.Color.orange()
|
||||||
|
)
|
||||||
|
for _, info in pages[page_index]:
|
||||||
|
embed.add_field(
|
||||||
|
name=info["pseudo"],
|
||||||
|
value=(
|
||||||
|
f"**Début** : {info['debut']}\n"
|
||||||
|
f"**Fin** : {info['fin']}\n"
|
||||||
|
f"**Motif** : {info['motif']}\n"
|
||||||
|
f"**Supérieur** : {info['superieur']}"
|
||||||
|
),
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
embed.set_footer(text="Gestion des absences du staff")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
class PaginatorView(ui.View):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=60)
|
||||||
|
self.page = 0
|
||||||
|
|
||||||
|
@ui.button(label="⬅️ Précédent", style=discord.ButtonStyle.secondary, disabled=True)
|
||||||
|
async def previous(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
self.page -= 1
|
||||||
|
await interaction.response.edit_message(embed=create_embed(self.page), view=self)
|
||||||
|
self.update_buttons()
|
||||||
|
|
||||||
|
@ui.button(label="➡️ Suivant", style=discord.ButtonStyle.secondary, disabled=len(pages) == 1)
|
||||||
|
async def next(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
self.page += 1
|
||||||
|
await interaction.response.edit_message(embed=create_embed(self.page), view=self)
|
||||||
|
self.update_buttons()
|
||||||
|
|
||||||
|
def update_buttons(self):
|
||||||
|
self.children[0].disabled = self.page == 0
|
||||||
|
self.children[1].disabled = self.page >= len(pages) - 1
|
||||||
|
|
||||||
|
view = PaginatorView()
|
||||||
|
await ctx.send(embed=create_embed(0), view=view, ephemeral=True)
|
||||||
|
|
||||||
|
@tasks.loop(minutes=1)
|
||||||
|
async def check_absences(self):
|
||||||
|
abs_data = await load_absences()
|
||||||
|
today = datetime.today()
|
||||||
|
to_remove = []
|
||||||
|
|
||||||
|
for user_id, info in abs_data.items():
|
||||||
|
debut = datetime.strptime(info["debut"], "%d/%m/%Y")
|
||||||
|
fin = datetime.strptime(info["fin"], "%d/%m/%Y")
|
||||||
|
etat = info.get("etat", "en cours")
|
||||||
|
|
||||||
|
if etat == "à venir" and debut <= today:
|
||||||
|
for guild in self.bot.guilds:
|
||||||
|
member = guild.get_member(int(user_id))
|
||||||
|
if member:
|
||||||
|
await self.deactivate_mentions(member)
|
||||||
|
abs_data[user_id]["etat"] = "en cours"
|
||||||
|
|
||||||
|
if etat == "en cours" and fin < today:
|
||||||
|
for guild in self.bot.guilds:
|
||||||
|
member = guild.get_member(int(user_id))
|
||||||
|
if member:
|
||||||
|
await self.activate_mentions(member)
|
||||||
|
to_remove.append(user_id)
|
||||||
|
|
||||||
|
for user_id in to_remove:
|
||||||
|
abs_data.pop(user_id, None)
|
||||||
|
|
||||||
|
await save_absences(abs_data)
|
||||||
|
|
||||||
|
async def deactivate_mentions(self, member):
|
||||||
|
role = discord.utils.get(member.guild.roles, name="Absence")
|
||||||
|
if not role:
|
||||||
|
role = await member.guild.create_role(name="Absence", reason="Gestion des absences staff")
|
||||||
|
await member.add_roles(role, reason="Début d'absence staff")
|
||||||
|
|
||||||
|
async def activate_mentions(self, member):
|
||||||
|
role = discord.utils.get(member.guild.roles, name="Absence")
|
||||||
|
if role:
|
||||||
|
await member.remove_roles(role, reason="Fin d'absence staff")
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
abs_data = await load_absences()
|
||||||
|
absent_ids = {k for k, v in abs_data.items() if v.get("etat") == "en cours"}
|
||||||
|
|
||||||
|
if str(message.author.id) in absent_ids:
|
||||||
|
await message.channel.send(
|
||||||
|
f"{message.author.mention}, tu es actuellement déclaré absent. Merci de prévenir si tu es de retour !",
|
||||||
|
delete_after=30
|
||||||
|
)
|
||||||
|
|
||||||
|
for user_id in absent_ids:
|
||||||
|
if f"<@{user_id}>" in message.content or f"<@!{user_id}>" in message.content:
|
||||||
|
msg_id = abs_data[user_id].get("message_id")
|
||||||
|
absence_url = f"https://discord.com/channels/{message.guild.id}/{ABSENCE_CHANNEL_ID}/{msg_id}" if msg_id else ""
|
||||||
|
await message.reply(
|
||||||
|
f"{message.author.mention}, cet utilisateur est absent. Plus d'infos : {absence_url}",
|
||||||
|
delete_after=60
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Absence(bot))
|
||||||
146
commandes/ajouter_argent.py
Normal file
146
commandes/ajouter_argent.py
Normal file
|
|
@ -0,0 +1,146 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier # ID du rôle banquier
|
||||||
|
|
||||||
|
class AjouterArgent(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
# Choix de banques automatiques
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="ajouter_argent",
|
||||||
|
description="Ajoute de l'argent à un compte (réservé aux banquiers)."
|
||||||
|
)
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(
|
||||||
|
rib="Le RIB du compte",
|
||||||
|
montant="Montant à ajouter",
|
||||||
|
banque="Banque cible (facultatif)"
|
||||||
|
)
|
||||||
|
async def ajouter_argent(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
rib: str,
|
||||||
|
montant: float,
|
||||||
|
banque: app_commands.Choice[str] = None
|
||||||
|
):
|
||||||
|
# Vérification du rôle
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Vous n'avez pas la permission d'utiliser cette commande.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Le montant doit être supérieur à zéro.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_nom = banque.value if banque else None
|
||||||
|
|
||||||
|
# Chargement des fichiers
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
|
||||||
|
cible_data = None
|
||||||
|
user_id = None
|
||||||
|
is_entreprise = False
|
||||||
|
|
||||||
|
# Recherche dans la banque spécifiée (si précisée)
|
||||||
|
if banque_nom and banque_nom in comptes:
|
||||||
|
for uid, info in comptes[banque_nom].items():
|
||||||
|
if info.get("rib") == rib:
|
||||||
|
cible_data = comptes
|
||||||
|
user_id = uid
|
||||||
|
break
|
||||||
|
|
||||||
|
if not user_id and banque_nom and banque_nom in entreprises:
|
||||||
|
for nom_entreprise, info in entreprises[banque_nom].items():
|
||||||
|
if info.get("rib") == rib:
|
||||||
|
cible_data = entreprises
|
||||||
|
user_id = nom_entreprise
|
||||||
|
is_entreprise = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# Si banque non précisée ou compte non trouvé, recherche dans toutes les banques
|
||||||
|
if not user_id and not banque_nom:
|
||||||
|
# Recherche dans toutes les banques utilisateurs
|
||||||
|
for banque_courante, comptes_banque in comptes.items():
|
||||||
|
for uid, info in comptes_banque.items():
|
||||||
|
if info.get("rib") == rib:
|
||||||
|
cible_data = comptes
|
||||||
|
user_id = uid
|
||||||
|
banque_nom = banque_courante
|
||||||
|
break
|
||||||
|
if user_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not user_id and not is_entreprise:
|
||||||
|
# Recherche dans toutes les banques entreprises
|
||||||
|
for banque_courante, entreprises_banque in entreprises.items():
|
||||||
|
for nom_entreprise, info in entreprises_banque.items():
|
||||||
|
if info.get("rib") == rib:
|
||||||
|
cible_data = entreprises
|
||||||
|
user_id = nom_entreprise
|
||||||
|
banque_nom = banque_courante
|
||||||
|
is_entreprise = True
|
||||||
|
break
|
||||||
|
if user_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not user_id:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Aucun compte trouvé avec ce RIB.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ajout du montant
|
||||||
|
cible_data[banque_nom][user_id]["solde"] += montant
|
||||||
|
transaction = {
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": montant,
|
||||||
|
"emetteur": interaction.user.id,
|
||||||
|
"destinataire": user_id
|
||||||
|
}
|
||||||
|
cible_data[banque_nom][user_id]["transactions"].append(transaction)
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
if is_entreprise:
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(entreprises, f, ensure_ascii=False, indent=4)
|
||||||
|
else:
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes, f, ensure_ascii=False, indent=4)
|
||||||
|
# Envoyer un MP à l'utilisateur (sauf entreprise)
|
||||||
|
try:
|
||||||
|
user = await self.bot.fetch_user(int(user_id))
|
||||||
|
await user.send(
|
||||||
|
f"💰 Un dépôt de **{montant:.2f}€** a été effectué sur votre compte dans **{banque_nom}**."
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass # Si l'utilisateur a désactivé les MP
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ **{montant:.2f}€** ajoutés avec succès au compte `{rib}` dans la banque **{banque_nom}**.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(AjouterArgent(bot))
|
||||||
220
commandes/annonces_sessions.py
Normal file
220
commandes/annonces_sessions.py
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
import dateparser
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
ROLE_PING_ID = 1278319901651632138 # ID du rôle citoyen # Rôle pour l'annonce principale
|
||||||
|
REMINDER_ROLE_ID = 1303750986900439151 # ID du rôle rappels sessions # Rôle pour les rappels (à adapter !)
|
||||||
|
|
||||||
|
presence_data = {}
|
||||||
|
|
||||||
|
class PresenceView(discord.ui.View):
|
||||||
|
def __init__(self, message_id):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.message_id = message_id
|
||||||
|
|
||||||
|
async def update_message(self, interaction, state):
|
||||||
|
user_id = interaction.user.id
|
||||||
|
if self.message_id not in presence_data:
|
||||||
|
presence_data[self.message_id] = {
|
||||||
|
"present": set(), "absent": set(), "retard": set(),
|
||||||
|
"date": None, "sent_dm": False,
|
||||||
|
"reminder1": None, "reminder2": None,
|
||||||
|
"reminder1_sent": False, "reminder2_sent": False,
|
||||||
|
"channel_id": None, "guild_id": None
|
||||||
|
}
|
||||||
|
for key in ["present", "absent", "retard"]:
|
||||||
|
presence_data[self.message_id][key].discard(user_id)
|
||||||
|
presence_data[self.message_id][state].add(user_id)
|
||||||
|
n_present = len(presence_data[self.message_id]["present"])
|
||||||
|
n_absent = len(presence_data[self.message_id]["absent"])
|
||||||
|
n_retard = len(presence_data[self.message_id]["retard"])
|
||||||
|
msg = await interaction.channel.fetch_message(self.message_id)
|
||||||
|
lines = msg.content.split('\n')
|
||||||
|
# On modifie uniquement les lignes de présence
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith("> - Je serai présent"):
|
||||||
|
lines[i] = f"> - Je serai présent : <:check:1297296859206778911> **({n_present})**"
|
||||||
|
elif line.startswith("> - Je serai absent"):
|
||||||
|
lines[i] = f"> - Je serai absent : <:uncheck:1297296882778902598> **({n_absent})**"
|
||||||
|
elif line.startswith("> - Je serai en retard"):
|
||||||
|
lines[i] = f"> - Je serai en retard : ⏰ **({n_retard})**"
|
||||||
|
new_content = '\n'.join(lines)
|
||||||
|
await msg.edit(content=new_content, view=self)
|
||||||
|
|
||||||
|
@discord.ui.button(label="Présent", style=discord.ButtonStyle.success, emoji="✅", custom_id="presence_present")
|
||||||
|
async def present(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
await self.update_message(interaction, "present")
|
||||||
|
await interaction.response.send_message("Merci, tu as été noté comme **présent** à la session RP !", ephemeral=True)
|
||||||
|
|
||||||
|
@discord.ui.button(label="Absent", style=discord.ButtonStyle.danger, emoji="❌", custom_id="presence_absent")
|
||||||
|
async def absent(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
await self.update_message(interaction, "absent")
|
||||||
|
await interaction.response.send_message("Merci, tu as été noté comme **absent** à la session RP.", ephemeral=True)
|
||||||
|
|
||||||
|
@discord.ui.button(label="En retard", style=discord.ButtonStyle.primary, emoji="⏰", custom_id="presence_retard")
|
||||||
|
async def retard(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
await self.update_message(interaction, "retard")
|
||||||
|
await interaction.response.send_message("Merci, tu as été noté comme **en retard** pour la session RP.", ephemeral=True)
|
||||||
|
|
||||||
|
class AnnonceSession(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.check_sessions.start()
|
||||||
|
|
||||||
|
def cog_unload(self):
|
||||||
|
self.check_sessions.cancel()
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="annonce_session",
|
||||||
|
description="Annonce une session RP avec image, rappels et boutons de présence."
|
||||||
|
)
|
||||||
|
@app_commands.describe(
|
||||||
|
date="Date de la session (ex: Vendredi 20 Juin à 20h45)",
|
||||||
|
reminder1="Date/heure du 1er rappel (ex: Jeudi 19 Juin à 19h)",
|
||||||
|
reminder2="Date/heure du 2e rappel (ex: Vendredi 20 Juin à 15h)",
|
||||||
|
image="Image à joindre (obligatoire)"
|
||||||
|
)
|
||||||
|
async def annonce_session(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
date: str,
|
||||||
|
reminder1: str,
|
||||||
|
reminder2: str,
|
||||||
|
image: discord.Attachment
|
||||||
|
):
|
||||||
|
if not image.content_type or not image.content_type.startswith("image/"):
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Le fichier joint doit être une image valide.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# On parse toutes les dates en Europe/Paris
|
||||||
|
session_date = dateparser.parse(
|
||||||
|
date, languages=['fr'],
|
||||||
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
||||||
|
)
|
||||||
|
reminder1_date = dateparser.parse(
|
||||||
|
reminder1, languages=['fr'],
|
||||||
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
||||||
|
)
|
||||||
|
reminder2_date = dateparser.parse(
|
||||||
|
reminder2, languages=['fr'],
|
||||||
|
settings={"TIMEZONE": "Europe/Paris", "RETURN_AS_TIMEZONE_AWARE": True}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not session_date or not reminder1_date or not reminder2_date:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Une des dates n'a pas été comprise. Vérifie le format.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
session_date = session_date.astimezone(timezone.utc)
|
||||||
|
reminder1_date = reminder1_date.astimezone(timezone.utc)
|
||||||
|
reminder2_date = reminder2_date.astimezone(timezone.utc)
|
||||||
|
|
||||||
|
message = (
|
||||||
|
"# <:VV:1339237574593609780> - **SESSION VICTORIA’S VICE**\n"
|
||||||
|
"\n"
|
||||||
|
"```📅 - HORAIRE DE LA SESSION```\n"
|
||||||
|
f"> - Nous vous donnons rendez-vous le **{date}** pour une **session officielle** sur Victoria’s Vice. 🗓️\n"
|
||||||
|
"---\n"
|
||||||
|
"```🤔 - COMMENT REJOINDRE LA SESSION ?```\n"
|
||||||
|
"> - Pour lancer la Map, veuillez entrer le code ci-dessous sur la barre de recherche de Fortnite, par la suite lancer la Map en **public** afin de pouvoir nous rejoindre.\n"
|
||||||
|
"> - **`CODE DE LA MAP`** <:arrow:1297491509201080362> [0986-1836-1625]\n"
|
||||||
|
"> - **`LIEN DIRECT DE LA MAP`** <:arrow:1297491509201080362> <https://play.fn.gg/island/0986-1836-1625>\n"
|
||||||
|
"---\n"
|
||||||
|
"```🖐 - SEREZ-VOUS PRÉSENT(E) EN SESSION ?```\n"
|
||||||
|
"> - Je serai présent : <:check:1297296859206778911> **(0)**\n"
|
||||||
|
"> - Je serai absent : <:uncheck:1297296882778902598> **(0)**\n"
|
||||||
|
"> - Je serai en retard : ⏰ **(0)**\n"
|
||||||
|
"---"
|
||||||
|
f"> - **`PING`** : <@&{ROLE_PING_ID}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
content=message,
|
||||||
|
files=[await image.to_file()]
|
||||||
|
)
|
||||||
|
msg = await interaction.original_response()
|
||||||
|
presence_data[msg.id] = {
|
||||||
|
"present": set(),
|
||||||
|
"absent": set(),
|
||||||
|
"retard": set(),
|
||||||
|
"date": session_date,
|
||||||
|
"sent_dm": False,
|
||||||
|
"reminder1": reminder1_date,
|
||||||
|
"reminder2": reminder2_date,
|
||||||
|
"reminder1_sent": False,
|
||||||
|
"reminder2_sent": False,
|
||||||
|
"channel_id": msg.channel.id,
|
||||||
|
"guild_id": msg.guild.id
|
||||||
|
}
|
||||||
|
await msg.edit(view=PresenceView(msg.id))
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="liste_presence",
|
||||||
|
description="Liste les présences pour une session RP."
|
||||||
|
)
|
||||||
|
@app_commands.describe(
|
||||||
|
message_id="ID du message d'annonce"
|
||||||
|
)
|
||||||
|
async def liste_presence(self, interaction: discord.Interaction, message_id: str):
|
||||||
|
try:
|
||||||
|
mid = int(message_id)
|
||||||
|
except ValueError:
|
||||||
|
await interaction.response.send_message("ID de message 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
|
||||||
|
)
|
||||||
|
|
||||||
|
@tasks.loop(seconds=30)
|
||||||
|
async def check_sessions(self):
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
for msg_id, data in list(presence_data.items()):
|
||||||
|
# Premier rappel
|
||||||
|
if data.get("reminder1") and not data.get("reminder1_sent", False) and now >= data["reminder1"]:
|
||||||
|
await self.send_reminder(data, msg_id, "Premier rappel !")
|
||||||
|
data["reminder1_sent"] = True
|
||||||
|
# Deuxième rappel
|
||||||
|
if data.get("reminder2") and not data.get("reminder2_sent", False) and now >= data["reminder2"]:
|
||||||
|
await self.send_reminder(data, msg_id, "Deuxième rappel !")
|
||||||
|
data["reminder2_sent"] = True
|
||||||
|
# Envoi du MP à l'heure de la session
|
||||||
|
if data["date"] and not data.get("sent_dm", False) and now >= data["date"]:
|
||||||
|
for user_id in data["present"]:
|
||||||
|
try:
|
||||||
|
user = await self.bot.fetch_user(user_id)
|
||||||
|
channel = self.bot.get_channel(data["channel_id"])
|
||||||
|
if channel:
|
||||||
|
msg = await channel.fetch_message(msg_id)
|
||||||
|
await user.send(f"La session RP commence ! Voici le lien de l'annonce : {msg.jump_url}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de l'envoi du DM à {user_id} : {e}")
|
||||||
|
data["sent_dm"] = True
|
||||||
|
|
||||||
|
async def send_reminder(self, data, msg_id, label):
|
||||||
|
channel = self.bot.get_channel(data["channel_id"])
|
||||||
|
if channel:
|
||||||
|
msg = await channel.fetch_message(msg_id)
|
||||||
|
await channel.send(
|
||||||
|
f"<@&{REMINDER_ROLE_ID}> ⏰ **{label}**\nLa session RP approche !\nAnnonce : {msg.jump_url}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@check_sessions.before_loop
|
||||||
|
async def before_check_sessions(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(AnnonceSession(bot))
|
||||||
45
commandes/change_nickname.py
Normal file
45
commandes/change_nickname.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import re
|
||||||
|
|
||||||
|
class FormatAllNicknames(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="formatall", description="Force tous les pseudos au format 'Prénom Nom | Epic'")
|
||||||
|
@app_commands.checks.has_permissions(manage_nicknames=True)
|
||||||
|
async def format_all(self, interaction: discord.Interaction):
|
||||||
|
await interaction.response.defer(thinking=True)
|
||||||
|
guild = interaction.guild
|
||||||
|
modified_count = 0
|
||||||
|
|
||||||
|
# Regex : deux mots avant le "|"
|
||||||
|
pattern_correct = re.compile(r"^[^\|]+\s[^\|]+\s\| .+")
|
||||||
|
|
||||||
|
for member in guild.members:
|
||||||
|
if member.bot:
|
||||||
|
continue
|
||||||
|
|
||||||
|
current_nick = member.nick or member.name
|
||||||
|
|
||||||
|
# S'il respecte déjà le bon format ("Prénom Nom | Quelquechose"), on skip
|
||||||
|
if pattern_correct.match(current_nick):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Sinon, forcer à "Prénom Nom | Epic"
|
||||||
|
new_nick = "Prénom Nom | Epic"
|
||||||
|
|
||||||
|
await member.edit(nick=new_nick)
|
||||||
|
modified_count += 1
|
||||||
|
|
||||||
|
except discord.Forbidden:
|
||||||
|
continue
|
||||||
|
except discord.HTTPException:
|
||||||
|
continue
|
||||||
|
|
||||||
|
await interaction.followup.send(f"✅ Renommage terminé : {modified_count} membres modifiés.")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(FormatAllNicknames(bot))
|
||||||
93
commandes/compte.py
Normal file
93
commandes/compte.py
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.banque_manager import BanqueManager
|
||||||
|
|
||||||
|
banque_manager = BanqueManager()
|
||||||
|
|
||||||
|
class Compte(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="compte",
|
||||||
|
description="Afficher vos comptes bancaires et vos 3 dernières transactions"
|
||||||
|
)
|
||||||
|
@app_commands.describe(
|
||||||
|
membre="Afficher le compte d'un autre membre (réservé au gouvernement)"
|
||||||
|
)
|
||||||
|
async def compte(self, interaction: discord.Interaction, membre: discord.Member = None):
|
||||||
|
"""Affiche les soldes et dernières transactions de l'utilisateur ou d'un autre membre (si gouvernement)"""
|
||||||
|
|
||||||
|
banque_manager.load_data()
|
||||||
|
|
||||||
|
# Par défaut, on cible l'utilisateur qui exécute la commande
|
||||||
|
cible = interaction.user
|
||||||
|
user_id = str(cible.id)
|
||||||
|
|
||||||
|
# Si un autre membre est précisé, on vérifie le rôle
|
||||||
|
if membre and membre != interaction.user:
|
||||||
|
role_gouv = discord.utils.get(interaction.guild.roles, name="🌍│Gouvernement")
|
||||||
|
if role_gouv not in interaction.user.roles:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Vous devez avoir le rôle **gouvernement** pour consulter le compte d'un autre membre.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
cible = membre
|
||||||
|
user_id = str(membre.id)
|
||||||
|
|
||||||
|
comptes = banque_manager.comptes
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"💳 Comptes bancaires de {cible.display_name}",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
|
||||||
|
banques_trouvees = False
|
||||||
|
|
||||||
|
for banque, data in comptes.items():
|
||||||
|
if not isinstance(data, dict) or user_id not in data:
|
||||||
|
continue # Ce n'est pas une banque valide pour cet utilisateur
|
||||||
|
|
||||||
|
compte = data[user_id]
|
||||||
|
rib = compte.get("rib", "Non défini")
|
||||||
|
solde = compte.get("solde", 0)
|
||||||
|
transactions = compte.get("transactions", [])
|
||||||
|
|
||||||
|
# Récupérer les 3 dernières transactions avec date
|
||||||
|
last_transactions = transactions[-3:] if transactions else []
|
||||||
|
|
||||||
|
tx_str = ""
|
||||||
|
for tx in last_transactions:
|
||||||
|
date = tx.get("date", "Date inconnue")
|
||||||
|
tx_type = tx.get("type", "Inconnu")
|
||||||
|
montant = tx.get("montant", 0)
|
||||||
|
source = tx.get("emetteur", tx.get("source", "Inconnu"))
|
||||||
|
dest = tx.get("destinataire", "Inconnu")
|
||||||
|
|
||||||
|
if tx_type.lower() == "virement" or tx_type.lower().startswith("virement"):
|
||||||
|
tx_str += f"- 🕒 {date} : **{tx_type}** de **{montant}€** à <@{dest}>\n"
|
||||||
|
elif tx_type.lower() == "virement reçu":
|
||||||
|
tx_str += f"- 🕒 {date} : **{tx_type}** de **{montant}€** de <@{source}>\n"
|
||||||
|
else:
|
||||||
|
tx_str += f"- 🕒 {date} : **{tx_type}** de **{montant}€**\n"
|
||||||
|
|
||||||
|
if not tx_str:
|
||||||
|
tx_str = "*Aucune transaction.*"
|
||||||
|
|
||||||
|
embed.add_field(
|
||||||
|
name=f"🏦 {banque}",
|
||||||
|
value=f"💳 **RIB** : `{rib}`\n💰 **Solde** : `{solde}€`\n📜 **Transactions récentes :**\n{tx_str}",
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
|
||||||
|
banques_trouvees = True
|
||||||
|
|
||||||
|
if not banques_trouvees:
|
||||||
|
embed.description = "❌ Aucun compte bancaire trouvé dans les banques enregistrées pour cet utilisateur."
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Compte(bot))
|
||||||
102
commandes/compte_banque_nationale.py
Normal file
102
commandes/compte_banque_nationale.py
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
|
||||||
|
BANQUE_NATIONALE_ROLE_ID = 1362031086959329470 # Remplace par l’ID réel du rôle banque_nationale
|
||||||
|
|
||||||
|
class CompteBanqueNationale(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def get_banque_nationale_data(self):
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r+", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
# Crée la section si elle n'existe pas
|
||||||
|
if "banque_nationale" not in data:
|
||||||
|
data["banque_nationale"] = {
|
||||||
|
"BANQUE": {
|
||||||
|
"rib": "11111 22222 33333333333 44",
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": [{
|
||||||
|
"date": "Création automatique",
|
||||||
|
"type": "Création de compte",
|
||||||
|
"source": "Système",
|
||||||
|
"montant": 0.0
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.seek(0)
|
||||||
|
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||||
|
f.truncate()
|
||||||
|
|
||||||
|
banque_data = data["banque_nationale"].get("BANQUE", {})
|
||||||
|
return banque_data.get("solde", 0.0), banque_data.get("transactions", [])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lecture ou création banque_nationale : {e}")
|
||||||
|
return 0.0, []
|
||||||
|
|
||||||
|
@app_commands.command(name="voir_banque_nationale", description="Voir solde et transactions du compte banque nationale")
|
||||||
|
async def voir_banque_nationale(self, interaction: discord.Interaction):
|
||||||
|
if not any(role.id == BANQUE_NATIONALE_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'accéder à ce compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
solde, transactions = self.get_banque_nationale_data()
|
||||||
|
|
||||||
|
if not transactions:
|
||||||
|
await interaction.response.send_message("📄 Aucune transaction trouvée sur le compte banque nationale.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
pages = []
|
||||||
|
per_page = 5
|
||||||
|
total_pages = math.ceil(len(transactions) / per_page)
|
||||||
|
|
||||||
|
for i in range(total_pages):
|
||||||
|
start = i * per_page
|
||||||
|
end = start + per_page
|
||||||
|
chunk = transactions[start:end]
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🏦 Banque Nationale - Historique",
|
||||||
|
description=f"Page {i+1}/{total_pages}",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
||||||
|
|
||||||
|
for tx in chunk:
|
||||||
|
description = (
|
||||||
|
f"**Date**: {tx.get('date', 'N/A')}\n"
|
||||||
|
f"**Type**: {tx.get('type', 'N/A')}\n"
|
||||||
|
f"**Montant**: {tx.get('montant', 0)}€\n"
|
||||||
|
f"**Source**: {tx.get('source', 'N/A')}"
|
||||||
|
)
|
||||||
|
embed.add_field(name="📄 Transaction", value=description, inline=False)
|
||||||
|
|
||||||
|
pages.append(embed)
|
||||||
|
|
||||||
|
class Pagination(discord.ui.View):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.current = 0
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️", style=discord.ButtonStyle.grey)
|
||||||
|
async def previous(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current > 0:
|
||||||
|
self.current -= 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
@discord.ui.button(label="➡️", style=discord.ButtonStyle.grey)
|
||||||
|
async def next(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current < len(pages) - 1:
|
||||||
|
self.current += 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=pages[0], view=Pagination(), ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CompteBanqueNationale(bot))
|
||||||
92
commandes/compte_fbm.py
Normal file
92
commandes/compte_fbm.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
|
||||||
|
FBM_ROLE_ID = 1353610672818360330 # ID du rôle autorisé à accéder au compte FBM
|
||||||
|
|
||||||
|
class CompteFBM(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def get_all_transactions(self):
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
fbm_data = data.setdefault("fbm", {}).setdefault("FBM", {
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
})
|
||||||
|
return fbm_data["solde"], fbm_data["transactions"]
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lecture comptes_entreprises.json : {e}")
|
||||||
|
return 0.0, []
|
||||||
|
|
||||||
|
@app_commands.command(name="compte_fbm", description="Affiche le solde et l'historique du compte FBM (réservé au personnel FBM).")
|
||||||
|
async def compte_fbm(self, interaction: discord.Interaction):
|
||||||
|
if not any(role.id == FBM_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'accéder à ce compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
solde, transactions = self.get_all_transactions()
|
||||||
|
|
||||||
|
if not transactions:
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📄 Compte FBM",
|
||||||
|
description="Aucune transaction enregistrée.",
|
||||||
|
color=discord.Color.orange()
|
||||||
|
)
|
||||||
|
embed.add_field(name="💰 Solde actuel", value=f"{solde:.2f}€", inline=False)
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Pagination
|
||||||
|
pages = []
|
||||||
|
per_page = 5
|
||||||
|
total_pages = math.ceil(len(transactions) / per_page)
|
||||||
|
|
||||||
|
for i in range(total_pages):
|
||||||
|
start = i * per_page
|
||||||
|
end = start + per_page
|
||||||
|
chunk = transactions[start:end]
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📄 Historique FBM",
|
||||||
|
description=f"Page {i+1}/{total_pages}",
|
||||||
|
color=discord.Color.orange()
|
||||||
|
)
|
||||||
|
embed.add_field(name="💰 Solde actuel", value=f"{solde:.2f}€", inline=False)
|
||||||
|
|
||||||
|
for tx in chunk:
|
||||||
|
desc = (
|
||||||
|
f"**Date**: {tx.get('date', 'N/A')}\n"
|
||||||
|
f"**Type**: {tx.get('type', 'N/A')}\n"
|
||||||
|
f"**Montant**: {tx.get('montant', 0)}€\n"
|
||||||
|
f"**Source**: {tx.get('source', 'N/A')}"
|
||||||
|
)
|
||||||
|
embed.add_field(name="🔸 Transaction", value=desc, inline=False)
|
||||||
|
|
||||||
|
pages.append(embed)
|
||||||
|
|
||||||
|
class Pagination(discord.ui.View):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.current = 0
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️", style=discord.ButtonStyle.grey)
|
||||||
|
async def previous(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current > 0:
|
||||||
|
self.current -= 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
@discord.ui.button(label="➡️", style=discord.ButtonStyle.grey)
|
||||||
|
async def next(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current < len(pages) - 1:
|
||||||
|
self.current += 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=pages[0], view=Pagination(), ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CompteFBM(bot))
|
||||||
84
commandes/compte_gouvernement.py
Normal file
84
commandes/compte_gouvernement.py
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
|
||||||
|
GOUVERNEMENT_ROLE_ID = 1278305482926194701 # Remplace avec l’ID de ton rôle Gouvernement # Remplace avec l’ID de ton rôle Gouvernement
|
||||||
|
|
||||||
|
class CompteGouvernement(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def get_gouv_data(self):
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
gouv_data = data.get("Gouvernement", {}).get("GOUV", {})
|
||||||
|
return gouv_data.get("solde", 0.0), gouv_data.get("transactions", [])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lecture comptes_entreprises.json : {e}")
|
||||||
|
return 0.0, []
|
||||||
|
|
||||||
|
@app_commands.command(name="compte_gouvernement", description="Affiche le solde et les transactions du compte Gouvernement.")
|
||||||
|
async def compte_gouvernement(self, interaction: discord.Interaction):
|
||||||
|
if not any(role.id == GOUVERNEMENT_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'accéder à ce compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
solde, transactions = self.get_gouv_data()
|
||||||
|
|
||||||
|
if not transactions:
|
||||||
|
await interaction.response.send_message("📄 Aucune transaction trouvée pour le gouvernement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Pagination setup
|
||||||
|
pages = []
|
||||||
|
per_page = 5
|
||||||
|
total_pages = math.ceil(len(transactions) / per_page)
|
||||||
|
|
||||||
|
for i in range(total_pages):
|
||||||
|
start = i * per_page
|
||||||
|
end = start + per_page
|
||||||
|
chunk = transactions[start:end]
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🏛️ Compte Gouvernement",
|
||||||
|
description=f"Page {i+1}/{total_pages}",
|
||||||
|
color=discord.Color.dark_gold()
|
||||||
|
)
|
||||||
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
||||||
|
|
||||||
|
for tx in chunk:
|
||||||
|
desc = (
|
||||||
|
f"**Date**: {tx.get('date', 'N/A')}\n"
|
||||||
|
f"**Type**: {tx.get('type', 'N/A')}\n"
|
||||||
|
f"**Montant**: {tx.get('montant', 0)}€\n"
|
||||||
|
f"**Source**: {tx.get('source', 'N/A')}"
|
||||||
|
)
|
||||||
|
embed.add_field(name="📄 Transaction", value=desc, inline=False)
|
||||||
|
|
||||||
|
pages.append(embed)
|
||||||
|
|
||||||
|
# Vue de pagination
|
||||||
|
class Pagination(discord.ui.View):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.current = 0
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️", style=discord.ButtonStyle.grey)
|
||||||
|
async def previous(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current > 0:
|
||||||
|
self.current -= 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
@discord.ui.button(label="➡️", style=discord.ButtonStyle.grey)
|
||||||
|
async def next(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current < len(pages) - 1:
|
||||||
|
self.current += 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=pages[0], view=Pagination(), ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CompteGouvernement(bot))
|
||||||
96
commandes/compte_urssaf.py
Normal file
96
commandes/compte_urssaf.py
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
|
||||||
|
URSAFF_ROLE_ID = 1362056014584615213 # Remplace par l’ID réel du rôle URSAFF # Remplace par l’ID réel du rôle URSAFF
|
||||||
|
|
||||||
|
class CompteUrssaf(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def get_all_transactions(self):
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lecture comptes_entreprises.json : {e}")
|
||||||
|
return 0.0, []
|
||||||
|
|
||||||
|
# Si URSAFF n'existe pas, on le crée
|
||||||
|
if "ursaff" not in data:
|
||||||
|
data["ursaff"] = {
|
||||||
|
"URSSAFF": {
|
||||||
|
"rib": "00000 00000 00000000000 01",
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
ursaff_data = data.get("ursaff", {}).get("URSAFF", {})
|
||||||
|
return ursaff_data.get("solde", 0.0), ursaff_data.get("transactions", [])
|
||||||
|
|
||||||
|
@app_commands.command(name="compte_ursaff", description="Affiche le solde et l'historique complet du compte URSAFF (réservé aux membres URSAFF).")
|
||||||
|
async def compte_ursaff(self, interaction: discord.Interaction):
|
||||||
|
# Vérifie que l'utilisateur a le rôle URSAFF
|
||||||
|
if not any(role.id == URSAFF_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'accéder à ce compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
solde, transactions = self.get_all_transactions()
|
||||||
|
|
||||||
|
# Pagination setup
|
||||||
|
pages = []
|
||||||
|
per_page = 5
|
||||||
|
total_pages = max(1, math.ceil(len(transactions) / per_page))
|
||||||
|
|
||||||
|
for i in range(total_pages):
|
||||||
|
start = i * per_page
|
||||||
|
end = start + per_page
|
||||||
|
chunk = transactions[start:end]
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📄 Historique URSSAF",
|
||||||
|
description=f"Page {i+1}/{total_pages}",
|
||||||
|
color=discord.Color.dark_purple()
|
||||||
|
)
|
||||||
|
embed.add_field(name="💼 Solde actuel", value=f"{solde:.2f}€", inline=False)
|
||||||
|
|
||||||
|
if chunk:
|
||||||
|
for tx in chunk:
|
||||||
|
description = (
|
||||||
|
f"**Date**: {tx.get('date', 'N/A')}\n"
|
||||||
|
f"**Type**: {tx.get('type', 'N/A')}\n"
|
||||||
|
f"**Montant**: {tx.get('montant', 0)}€\n"
|
||||||
|
f"**Source**: {tx.get('source', 'N/A')}"
|
||||||
|
)
|
||||||
|
embed.add_field(name="🔹 Transaction", value=description, inline=False)
|
||||||
|
else:
|
||||||
|
embed.add_field(name="📄 Transactions", value="Aucune transaction récente.", inline=False)
|
||||||
|
|
||||||
|
pages.append(embed)
|
||||||
|
|
||||||
|
class Pagination(discord.ui.View):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.current = 0
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️", style=discord.ButtonStyle.grey)
|
||||||
|
async def previous(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current > 0:
|
||||||
|
self.current -= 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
@discord.ui.button(label="➡️", style=discord.ButtonStyle.grey)
|
||||||
|
async def next(self, interaction_btn: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if self.current < len(pages) - 1:
|
||||||
|
self.current += 1
|
||||||
|
await interaction_btn.response.edit_message(embed=pages[self.current], view=self)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=pages[0], view=Pagination(), ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CompteUrssaf(bot))
|
||||||
73
commandes/comptes_entreprises.py
Normal file
73
commandes/comptes_entreprises.py
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
|
||||||
|
class CompteEntreprise(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="compte_entreprise", description="Consulte le solde et les transactions d'une entreprise.")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
async def compte_entreprise(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
banque: app_commands.Choice[str],
|
||||||
|
nom_entreprise: str,
|
||||||
|
mot_de_passe: str
|
||||||
|
):
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur de lecture des données bancaires.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if banque_nom not in comptes or nom_entreprise not in comptes[banque_nom]:
|
||||||
|
await interaction.response.send_message("❌ Ce compte entreprise n'existe pas.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte = comptes[banque_nom][nom_entreprise]
|
||||||
|
|
||||||
|
# 🔐 Vérification du mot de passe avec la bonne clé
|
||||||
|
mdp_stocke = compte.get("mdp", "").strip()
|
||||||
|
mdp_fournit = mot_de_passe.strip()
|
||||||
|
|
||||||
|
if mdp_stocke != mdp_fournit:
|
||||||
|
await interaction.response.send_message("❌ Mot de passe incorrect.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
solde = compte.get("solde", 0)
|
||||||
|
transactions = compte.get("transactions", [])
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"🏢 Compte Entreprise : {nom_entreprise}",
|
||||||
|
color=discord.Color.teal()
|
||||||
|
)
|
||||||
|
embed.add_field(name="🏦 Banque", value=banque_nom, inline=True)
|
||||||
|
embed.add_field(name="💰 Solde", value=f"{solde:.2f}€", inline=False)
|
||||||
|
|
||||||
|
if transactions:
|
||||||
|
last_transactions = transactions[-3:]
|
||||||
|
for tx in reversed(last_transactions):
|
||||||
|
desc = (
|
||||||
|
f"**Date**: {tx.get('date', 'N/A')}\n"
|
||||||
|
f"**Type**: {tx.get('type', 'N/A')}\n"
|
||||||
|
f"**Montant**: {tx.get('montant', 0)}€\n"
|
||||||
|
f"**Source**: {tx.get('source', 'N/A')}"
|
||||||
|
)
|
||||||
|
embed.add_field(name="📄 Transaction", value=desc, inline=False)
|
||||||
|
else:
|
||||||
|
embed.add_field(name="📄 Transactions", value="Aucune transaction récente.", inline=False)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CompteEntreprise(bot))
|
||||||
68
commandes/counting.py
Normal file
68
commandes/counting.py
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
COUNTING_FILE = "counting_data.json"
|
||||||
|
counting_channels = {}
|
||||||
|
|
||||||
|
def load_counting_channels():
|
||||||
|
global counting_channels
|
||||||
|
if os.path.isfile(COUNTING_FILE):
|
||||||
|
with open(COUNTING_FILE, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
counting_channels = {int(k): v for k, v in data.items()}
|
||||||
|
else:
|
||||||
|
counting_channels = {}
|
||||||
|
|
||||||
|
def save_counting_channels():
|
||||||
|
with open(COUNTING_FILE, "w", encoding="utf-8") as f:
|
||||||
|
json.dump({str(k): v for k, v in counting_channels.items()}, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
class Counting(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
load_counting_channels()
|
||||||
|
|
||||||
|
async def cog_load(self):
|
||||||
|
# Synchronise les slash commands à l'ajout du cog
|
||||||
|
await self.bot.tree.sync()
|
||||||
|
print("Slash commands synchronisées pour Counting.")
|
||||||
|
|
||||||
|
@app_commands.command(name="start_counting", description="Démarre un channel de counting.")
|
||||||
|
async def start_counting(self, interaction: discord.Interaction):
|
||||||
|
counting_channels[interaction.channel.id] = {"current": 0, "last_user": None}
|
||||||
|
save_counting_channels()
|
||||||
|
await interaction.response.send_message("Le counting commence ! Envoyez 1 pour débuter.")
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
channel_id = message.channel.id
|
||||||
|
if channel_id not in counting_channels:
|
||||||
|
return
|
||||||
|
|
||||||
|
state = counting_channels[channel_id]
|
||||||
|
try:
|
||||||
|
number = int(message.content.strip())
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
|
||||||
|
if number == state["current"] + 1 and message.author.id != state["last_user"]:
|
||||||
|
state["current"] = number
|
||||||
|
state["last_user"] = message.author.id
|
||||||
|
save_counting_channels()
|
||||||
|
await message.add_reaction("✅")
|
||||||
|
else:
|
||||||
|
await message.add_reaction("❌")
|
||||||
|
await message.channel.send(
|
||||||
|
f"Erreur ! <@{message.author.id}> a cassé la chaîne à {number}. On repart à 1 !"
|
||||||
|
)
|
||||||
|
counting_channels[channel_id] = {"current": 0, "last_user": None}
|
||||||
|
save_counting_channels()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Counting(bot))
|
||||||
72
commandes/identite.py
Normal file
72
commandes/identite.py
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.data_manager import DataManager
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
ADMIN_ROLE_ID = 1278305482926194701 # ID du rôle gouvernement # ID du rôle gouvernement
|
||||||
|
|
||||||
|
data_manager = DataManager()
|
||||||
|
|
||||||
|
class CreerIdentite(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="creer_carte_identite", description="Créer une carte d'identité (Réservé aux admins)")
|
||||||
|
@app_commands.choices(sexe=[
|
||||||
|
app_commands.Choice(name="Homme", value="Homme"),
|
||||||
|
app_commands.Choice(name="Femme", value="Femme"),
|
||||||
|
app_commands.Choice(name="Autre", value="Autre")
|
||||||
|
])
|
||||||
|
async def creer_carte_identite(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
utilisateur: discord.Member,
|
||||||
|
nom: str,
|
||||||
|
prenom: str,
|
||||||
|
date_naissance: str,
|
||||||
|
lieu_naissance: str,
|
||||||
|
sexe: app_commands.Choice[str]
|
||||||
|
):
|
||||||
|
"""Commande réservée aux admins pour créer une carte d'identité"""
|
||||||
|
|
||||||
|
if not any(role.id == ADMIN_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Vous n'avez pas la permission de créer des cartes d'identité.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = str(utilisateur.id)
|
||||||
|
|
||||||
|
# ➡️ Plus de refus : on écrase directement l'ancienne carte
|
||||||
|
ancienne_carte = user_id in data_manager.identities
|
||||||
|
|
||||||
|
# 📅 Dates de création et d'expiration
|
||||||
|
date_creation = datetime.now()
|
||||||
|
date_expiration = (date_creation + timedelta(days=730)).strftime("%d/%m/%Y")
|
||||||
|
|
||||||
|
# 📦 Données à enregistrer
|
||||||
|
identity_data = {
|
||||||
|
"nom": nom.upper(),
|
||||||
|
"prenom": prenom.capitalize(),
|
||||||
|
"date_naissance": date_naissance,
|
||||||
|
"lieu_naissance": lieu_naissance,
|
||||||
|
"sexe": sexe.value,
|
||||||
|
"date_expiration": date_expiration
|
||||||
|
}
|
||||||
|
|
||||||
|
# 💾 Enregistrement
|
||||||
|
data_manager.identities[user_id] = identity_data
|
||||||
|
data_manager.save_data()
|
||||||
|
|
||||||
|
# 📢 Message différent selon si c'était une ancienne carte ou non
|
||||||
|
if ancienne_carte:
|
||||||
|
message = f"✅ Carte d'identité de {utilisateur.mention} **mise à jour** avec succès !"
|
||||||
|
else:
|
||||||
|
message = f"✅ Carte d'identité créée pour {utilisateur.mention} avec succès !"
|
||||||
|
|
||||||
|
await interaction.response.send_message(message, ephemeral=False)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(CreerIdentite(bot))
|
||||||
60
commandes/liste_taches.py
Normal file
60
commandes/liste_taches.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
class Taches(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="lister_taches", description="Liste toutes les tâches assignées à tous les utilisateurs.")
|
||||||
|
async def lister_taches(self, interaction: discord.Interaction):
|
||||||
|
try:
|
||||||
|
with open("taches.json", "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Impossible de lire le fichier des tâches.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
taches = data.get("taches", {})
|
||||||
|
if not taches:
|
||||||
|
await interaction.response.send_message("Aucune tâche trouvée.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Regrouper les tâches par utilisateur assigné
|
||||||
|
taches_par_utilisateur = defaultdict(list)
|
||||||
|
for tache_id, tache_info in taches.items():
|
||||||
|
assigne_id = tache_info.get("assigné")
|
||||||
|
if assigne_id:
|
||||||
|
taches_par_utilisateur[assigne_id].append(tache_info)
|
||||||
|
else:
|
||||||
|
taches_par_utilisateur[None].append(tache_info) # Pour tâches non assignées
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📋 Liste des tâches assignées",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
|
||||||
|
for user_id, user_taches in taches_par_utilisateur.items():
|
||||||
|
if user_id is None:
|
||||||
|
nom_utilisateur = "Non assigné"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
user = await self.bot.fetch_user(int(user_id))
|
||||||
|
nom_utilisateur = user.display_name
|
||||||
|
except Exception:
|
||||||
|
nom_utilisateur = f"Utilisateur inconnu ({user_id})"
|
||||||
|
|
||||||
|
taches_text = ""
|
||||||
|
for tache in user_taches:
|
||||||
|
titre = tache.get("titre", "Sans titre")
|
||||||
|
statut = tache.get("statut", "inconnu")
|
||||||
|
taches_text += f"- **{titre}** *(état: {statut})*\n"
|
||||||
|
|
||||||
|
embed.add_field(name=f"{nom_utilisateur}", value=taches_text, inline=False)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=False)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Taches(bot))
|
||||||
22
commandes/message.py
Normal file
22
commandes/message.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
|
||||||
|
class Message(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="message", description="Envoyer un message privé")
|
||||||
|
@app_commands.checks.has_permissions(administrator=True)
|
||||||
|
async def message_utilisateur(self, interaction: discord.Interaction, membre: discord.Member, message: str):
|
||||||
|
try:
|
||||||
|
await membre.send(message)
|
||||||
|
await interaction.response.send_message(f"Message envoyé à {membre.mention}.", ephemeral=True)
|
||||||
|
log_info(f"Message envoyé à {membre.name}")
|
||||||
|
except discord.Forbidden:
|
||||||
|
await interaction.response.send_message("Impossible d'envoyer un MP.", ephemeral=True)
|
||||||
|
log_error(f"Échec d'envoi à {membre.name}")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Message(bot))
|
||||||
38
commandes/message_tous.py
Normal file
38
commandes/message_tous.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
class MessageTous(commands.Cog):
|
||||||
|
def __init__(self, bot: commands.Bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="messagetous",
|
||||||
|
description="Envoyer un message privé à tous les membres du serveur."
|
||||||
|
)
|
||||||
|
@app_commands.checks.has_permissions(administrator=True)
|
||||||
|
async def message_tous(self, interaction: discord.Interaction, message: str):
|
||||||
|
await interaction.response.defer(ephemeral=True)
|
||||||
|
|
||||||
|
succes = 0
|
||||||
|
erreurs = 0
|
||||||
|
|
||||||
|
await interaction.followup.send("Envoi du message en cours...", ephemeral=False)
|
||||||
|
|
||||||
|
for member in interaction.guild.members:
|
||||||
|
if not member.bot and member != interaction.user:
|
||||||
|
try:
|
||||||
|
await member.send(message)
|
||||||
|
succes += 1
|
||||||
|
except discord.Forbidden:
|
||||||
|
erreurs += 1
|
||||||
|
except Exception as e:
|
||||||
|
erreurs += 1
|
||||||
|
|
||||||
|
await interaction.followup.send(
|
||||||
|
f"✅ Message envoyé à {succes} membres.\n❌ {erreurs} erreurs.",
|
||||||
|
ephemeral=False
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot: commands.Bot):
|
||||||
|
await bot.add_cog(MessageTous(bot))
|
||||||
76
commandes/ouvrir_compte.py
Normal file
76
commandes/ouvrir_compte.py
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.banque_manager import BanqueManager
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Rôle nécessaire pour créer un compte
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier
|
||||||
|
|
||||||
|
# Liste des banques disponibles (id interne : nom affiché)
|
||||||
|
BANQUES = {
|
||||||
|
"Victoria's Credit Bank": "Victoria's Credit Bank",
|
||||||
|
"NGC Bank": "Nexus Global Corporation Bank"
|
||||||
|
}
|
||||||
|
|
||||||
|
banque_manager = BanqueManager()
|
||||||
|
|
||||||
|
class OuvrirCompte(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="ouvrir_compte", description="Ouvre un compte bancaire pour un utilisateur (banquier uniquement).")
|
||||||
|
@app_commands.choices(
|
||||||
|
banque=[app_commands.Choice(name=nom, value=id_banque) for id_banque, nom in BANQUES.items()]
|
||||||
|
)
|
||||||
|
async def ouvrir_compte(self, interaction: discord.Interaction, utilisateur: discord.Member, banque: app_commands.Choice[str]):
|
||||||
|
banque_id = banque.value
|
||||||
|
banque_nom = BANQUES[banque_id]
|
||||||
|
|
||||||
|
# Vérification du rôle de banquier
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'ouvrir un compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = str(utilisateur.id)
|
||||||
|
banque_manager.load_data()
|
||||||
|
|
||||||
|
# Conversion automatique si l'ancien format est utilisé
|
||||||
|
if all(isinstance(v, dict) and 'rib' in v for v in banque_manager.comptes.values()):
|
||||||
|
banque_manager.comptes = {"vicynationale": banque_manager.comptes}
|
||||||
|
|
||||||
|
# Vérification si la banque existe dans les données
|
||||||
|
if banque_id not in banque_manager.comptes:
|
||||||
|
banque_manager.comptes[banque_id] = {}
|
||||||
|
|
||||||
|
# Vérification si l'utilisateur a déjà un compte dans cette banque
|
||||||
|
if user_id in banque_manager.comptes[banque_id]:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"❌ {utilisateur.mention} possède déjà un compte à la {banque_nom} !",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Génération du RIB aléatoire
|
||||||
|
rib = f"{random.randint(10000, 99999)} {random.randint(10000, 99999)} {random.randint(10000000000, 99999999999)} {random.randint(10, 99)}"
|
||||||
|
|
||||||
|
# Création du compte
|
||||||
|
banque_manager.comptes[banque_id][user_id] = {
|
||||||
|
"rib": rib,
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
|
||||||
|
banque_manager.save_data()
|
||||||
|
|
||||||
|
# Envoi du RIB en MP à l'utilisateur cible
|
||||||
|
try:
|
||||||
|
await utilisateur.send(f"🏦 Un compte a été créé pour vous à la **{banque_nom}**.\nVoici votre RIB : `{rib}`")
|
||||||
|
except discord.Forbidden:
|
||||||
|
await interaction.response.send_message("❌ Impossible d'envoyer le RIB en message privé (l'utilisateur a les MP fermés).", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Compte créé avec succès pour {utilisateur.mention} à la **{banque_nom}**.", ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(OuvrirCompte(bot))
|
||||||
92
commandes/ouvrir_comptes_entreprises.py
Normal file
92
commandes/ouvrir_comptes_entreprises.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
COMPTES_ENTREPRISES_PATH = "comptes_entreprises.json"
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier
|
||||||
|
|
||||||
|
def generer_rib():
|
||||||
|
return " ".join(["".join(random.choices(string.digits, k=5)) for _ in range(4)])
|
||||||
|
|
||||||
|
def generer_mdp():
|
||||||
|
return "".join(random.choices(string.ascii_letters + string.digits, k=8))
|
||||||
|
|
||||||
|
class OuvrirCompteEntreprise(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choix = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
tva_choix = [
|
||||||
|
app_commands.Choice(name="2%", value=2),
|
||||||
|
app_commands.Choice(name="5%", value=5),
|
||||||
|
app_commands.Choice(name="10%", value=10),
|
||||||
|
app_commands.Choice(name="20%", value=20),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="ouvrir_compte_entreprise", description="Ouvre un compte bancaire pour une entreprise")
|
||||||
|
@app_commands.choices(banque=banque_choix, tva=tva_choix)
|
||||||
|
async def ouvrir_compte_entreprise(self, interaction: discord.Interaction, entreprise: str, banque: app_commands.Choice[str], tva: app_commands.Choice[int]):
|
||||||
|
# ✅ Vérifie que l'utilisateur est banquier
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'exécuter cette commande.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_name = banque.value
|
||||||
|
entreprise = entreprise.strip()
|
||||||
|
|
||||||
|
# ✅ Chargement sécurisé du fichier
|
||||||
|
if os.path.exists(COMPTES_ENTREPRISES_PATH):
|
||||||
|
try:
|
||||||
|
with open(COMPTES_ENTREPRISES_PATH, "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
comptes = {}
|
||||||
|
else:
|
||||||
|
comptes = {}
|
||||||
|
|
||||||
|
if banque_name not in comptes:
|
||||||
|
comptes[banque_name] = {}
|
||||||
|
|
||||||
|
if entreprise in comptes[banque_name]:
|
||||||
|
await interaction.response.send_message(f"❌ Un compte existe déjà pour l'entreprise **{entreprise}** dans la banque **{banque_name}**.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
rib = generer_rib()
|
||||||
|
mdp = generer_mdp()
|
||||||
|
|
||||||
|
comptes[banque_name][entreprise] = {
|
||||||
|
"rib": rib,
|
||||||
|
"solde": 0,
|
||||||
|
"mdp": mdp,
|
||||||
|
"tva": tva.value,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(COMPTES_ENTREPRISES_PATH, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
# ✅ MP à l'utilisateur avec le RIB et le mot de passe
|
||||||
|
try:
|
||||||
|
await interaction.user.send(
|
||||||
|
f"🏦 Compte de l'entreprise **{entreprise}** ouvert avec succès dans la banque **{banque_name}** !\n"
|
||||||
|
f"💳 RIB : `{rib}`\n"
|
||||||
|
f"🔐 Mot de passe : `{mdp}`\n"
|
||||||
|
f"💼 Taux de TVA : `{tva.value}%`\n\n"
|
||||||
|
f"Conservez bien ces informations."
|
||||||
|
)
|
||||||
|
except discord.Forbidden:
|
||||||
|
await interaction.response.send_message("⚠️ Impossible de vous envoyer un message privé avec les informations du compte.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Le compte de l'entreprise **{entreprise}** a été créé avec succès.", ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(OuvrirCompteEntreprise(bot))
|
||||||
32
commandes/permis.py
Normal file
32
commandes/permis.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
|
# IDs des rôles
|
||||||
|
PERMIS_ROLE_ID = 1357027980056199258
|
||||||
|
AUTO_ECOLE_ROLE_ID = 1338844772118298634
|
||||||
|
|
||||||
|
class PermisCommand(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="ajouter_permis", description="Ajoute le rôle 'permis' à un membre.")
|
||||||
|
async def ajouter_permis(self, interaction: discord.Interaction, membre: discord.Member):
|
||||||
|
"""Ajoute le rôle 'permis' à un membre sélectionné."""
|
||||||
|
# Vérifier si l'utilisateur a le rôle "auto-école"
|
||||||
|
if AUTO_ECOLE_ROLE_ID not in [role.id for role in interaction.user.roles]:
|
||||||
|
await interaction.response.send_message("❌ Erreur : Vous n'avez pas la permission d'utiliser cette commande.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier si le rôle "permis" existe
|
||||||
|
permis_role = interaction.guild.get_role(PERMIS_ROLE_ID)
|
||||||
|
if not permis_role:
|
||||||
|
await interaction.response.send_message("❌ Erreur : Le rôle 'permis' n'existe pas.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ajouter le rôle "permis" au membre
|
||||||
|
await membre.add_roles(permis_role)
|
||||||
|
await interaction.response.send_message(f"✅ Le rôle 'permis' a été ajouté à {membre.mention}.")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(PermisCommand(bot))
|
||||||
38
commandes/presence_session.py
Normal file
38
commandes/presence_session.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
# Import ou partage de presence_data selon l'architecture
|
||||||
|
from commandes.annonces_sessions import presence_data # adapte le chemin si besoin
|
||||||
|
|
||||||
|
class ListePresence(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="liste_presence",
|
||||||
|
description="Liste les présences pour une session RP."
|
||||||
|
)
|
||||||
|
@app_commands.describe(
|
||||||
|
message_id="ID du message d'annonce"
|
||||||
|
)
|
||||||
|
async def liste_presence(self, interaction: discord.Interaction, message_id: str):
|
||||||
|
try:
|
||||||
|
mid = int(message_id)
|
||||||
|
except ValueError:
|
||||||
|
await interaction.response.send_message("ID de message 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
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(ListePresence(bot))
|
||||||
75
commandes/pret.py
Normal file
75
commandes/pret.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.banque_manager import BanqueManager
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier
|
||||||
|
|
||||||
|
banque_manager = BanqueManager()
|
||||||
|
|
||||||
|
class Pret(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="calculer_pret", description="Accorde un prêt bancaire à un utilisateur (Réservé aux banquiers).")
|
||||||
|
async def calculer_pret(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
utilisateur: discord.Member,
|
||||||
|
banque: str,
|
||||||
|
montant: float,
|
||||||
|
duree_annees: int
|
||||||
|
):
|
||||||
|
"""Les banquiers peuvent accorder un prêt à un utilisateur si son solde le permet."""
|
||||||
|
|
||||||
|
# Vérification de si le joueur executant la commande est un banquier
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Vous n'avez pas la permission d'accorder un prêt.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = str(utilisateur.id)
|
||||||
|
success, result = banque_manager.ajouter_pret(user_id, banque, montant, duree_annees)
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
await interaction.response.send_message(result, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
total_a_rembourser = result
|
||||||
|
taux_interet = banque_manager.comptes[user_id]['prets'][-1]['taux_interet'] * 100
|
||||||
|
|
||||||
|
# Vérifier si l'utilisateur a assez d'argent pour rembourser
|
||||||
|
solde_utilisateur = banque_manager.comptes[user_id].get("solde", 0)
|
||||||
|
if solde_utilisateur < total_a_rembourser:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"❌ {utilisateur.mention} n'a pas assez d'argent pour rembourser ce prêt.\n"
|
||||||
|
f"💰 **Solde actuel** : {solde_utilisateur}€\n"
|
||||||
|
f"💳 **Montant à rembourser** : {total_a_rembourser}€",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Débiter le solde de l'utilisateur
|
||||||
|
banque_manager.comptes[user_id]["solde"] -= total_a_rembourser
|
||||||
|
banque_manager.save_data()
|
||||||
|
|
||||||
|
# Création de l'embed
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🏦 Prêt bancaire accordé",
|
||||||
|
description=f"Le prêt a été accordé par {interaction.user.mention} pour {utilisateur.mention}.",
|
||||||
|
color=discord.Color.green()
|
||||||
|
)
|
||||||
|
embed.set_thumbnail(url="https://cdn-icons-png.flaticon.com/512/2910/2910827.png") # Icône banque
|
||||||
|
embed.add_field(name="💰 Montant emprunté", value=f"{montant}€", inline=True)
|
||||||
|
embed.add_field(name="📅 Durée", value=f"{duree_annees} ans", inline=True)
|
||||||
|
embed.add_field(name="📈 Taux d'intérêt", value=f"{taux_interet}%", inline=True)
|
||||||
|
embed.add_field(name="💳 Montant total à rembourser", value=f"{total_a_rembourser}€", inline=False)
|
||||||
|
embed.add_field(name="💰 Solde après prêt", value=f"{banque_manager.comptes[user_id]['solde']}€", inline=True)
|
||||||
|
embed.set_footer(text="Prêt enregistré dans le compte bancaire ✅")
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Pret(bot))
|
||||||
24
commandes/rename_all_on_join.py
Normal file
24
commandes/rename_all_on_join.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
|
||||||
|
class RenameMember(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
try:
|
||||||
|
# Vérifie si le bot a la permission de changer les pseudos
|
||||||
|
if member.guild.me.guild_permissions.manage_nicknames:
|
||||||
|
# Renommer le membre avec le format "Prénom Nom | Epic"
|
||||||
|
await member.edit(nick="Prénom Nom | Epic")
|
||||||
|
log_info(f"[✅] Pseudo modifié pour {member.display_name}")
|
||||||
|
else:
|
||||||
|
log_error(f"[❌] Pas la permission de modifier {member.display_name}")
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"[⚠️] Erreur pour {member.display_name} : {e}")
|
||||||
|
|
||||||
|
# Fonction pour ajouter le cog à ton bot
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(RenameMember(bot))
|
||||||
49
commandes/restranscription_staff.py
Normal file
49
commandes/restranscription_staff.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
|
class RestranscriptionStaff(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
# Ignorer les messages du bot lui-même
|
||||||
|
if message.author == self.bot.user:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Ignorer les messages d'autres bots
|
||||||
|
if message.author.bot:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Réceptionner les MPs
|
||||||
|
if isinstance(message.channel, discord.DMChannel):
|
||||||
|
channel_reception = self.bot.get_channel(1277951933105049601) # Remplacez par votre ID de salon
|
||||||
|
|
||||||
|
embed = discord.Embed(description=message.content,
|
||||||
|
color=discord.Color.blue())
|
||||||
|
embed.set_author(name=message.author.name,
|
||||||
|
icon_url=message.author.avatar.url
|
||||||
|
if message.author.avatar else None)
|
||||||
|
|
||||||
|
await channel_reception.send(embed=embed)
|
||||||
|
|
||||||
|
# Traiter les autres commandes si nécessaire
|
||||||
|
await self.bot.process_commands(message)
|
||||||
|
|
||||||
|
# Exemple de commande slash avec gestion des erreurs
|
||||||
|
@app_commands.command()
|
||||||
|
async def message_tous(self, interaction: discord.Interaction):
|
||||||
|
await interaction.response.send_message("Commande test!")
|
||||||
|
|
||||||
|
@message_tous.error
|
||||||
|
async def message_tous_error(self, interaction: discord.Interaction,
|
||||||
|
error: app_commands.AppCommandError):
|
||||||
|
if isinstance(error, app_commands.MissingPermissions):
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"Vous n'avez pas la permission d'utiliser cette commande.",
|
||||||
|
ephemeral=True)
|
||||||
|
|
||||||
|
# Fonction de configuration pour ajouter le cog au bot
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(RestranscriptionStaff(bot))
|
||||||
147
commandes/retirer_argent.py
Normal file
147
commandes/retirer_argent.py
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier # ID du rôle banquier
|
||||||
|
|
||||||
|
class RetirerArgent(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="retirer_argent",
|
||||||
|
description="Retire de l'argent d'un compte via son RIB (utilisateur ou entreprise)."
|
||||||
|
)
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(
|
||||||
|
rib="Le RIB du compte",
|
||||||
|
montant="Montant à retirer",
|
||||||
|
banque="Banque cible (facultatif)"
|
||||||
|
)
|
||||||
|
async def retirer_argent(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
rib: str,
|
||||||
|
montant: float,
|
||||||
|
banque: app_commands.Choice[str] = None
|
||||||
|
):
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission de faire cela.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message("❌ Le montant doit être supérieur à zéro.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_nom = banque.value if banque else None
|
||||||
|
|
||||||
|
# Charger les fichiers
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_bancaires = json.load(f)
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_entreprises = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la lecture des fichiers JSON.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte = None
|
||||||
|
source = None # "utilisateur" ou "entreprise"
|
||||||
|
user_id = None
|
||||||
|
|
||||||
|
# Recherche dans la banque spécifiée (si précisée)
|
||||||
|
if banque_nom and banque_nom in comptes_bancaires:
|
||||||
|
for uid, data in comptes_bancaires[banque_nom].items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
compte = data
|
||||||
|
source = "utilisateur"
|
||||||
|
user_id = uid
|
||||||
|
break
|
||||||
|
|
||||||
|
if not compte and banque_nom and banque_nom in comptes_entreprises:
|
||||||
|
for entreprise, data in comptes_entreprises[banque_nom].items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
compte = data
|
||||||
|
source = "entreprise"
|
||||||
|
user_id = entreprise
|
||||||
|
break
|
||||||
|
|
||||||
|
# Si banque non précisée ou compte non trouvé, recherche dans toutes les banques
|
||||||
|
if not compte and not banque_nom:
|
||||||
|
# Recherche dans toutes les banques utilisateurs
|
||||||
|
for banque_courante, comptes_banque in comptes_bancaires.items():
|
||||||
|
for uid, data in comptes_banque.items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
compte = data
|
||||||
|
source = "utilisateur"
|
||||||
|
user_id = uid
|
||||||
|
banque_nom = banque_courante
|
||||||
|
break
|
||||||
|
if compte:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not compte:
|
||||||
|
# Recherche dans toutes les banques entreprises
|
||||||
|
for banque_courante, entreprises_banque in comptes_entreprises.items():
|
||||||
|
for entreprise, data in entreprises_banque.items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
compte = data
|
||||||
|
source = "entreprise"
|
||||||
|
user_id = entreprise
|
||||||
|
banque_nom = banque_courante
|
||||||
|
break
|
||||||
|
if compte:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not compte:
|
||||||
|
await interaction.response.send_message("❌ Aucun compte trouvé avec ce RIB.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if compte["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant pour retirer cette somme.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Appliquer le retrait
|
||||||
|
compte["solde"] -= montant
|
||||||
|
transaction = {
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Retrait",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": -montant,
|
||||||
|
"emetteur": interaction.user.id,
|
||||||
|
"destinataire": user_id
|
||||||
|
}
|
||||||
|
compte.setdefault("transactions", []).append(transaction)
|
||||||
|
|
||||||
|
# Sauvegarde dans le bon fichier
|
||||||
|
if source == "utilisateur":
|
||||||
|
comptes_bancaires[banque_nom][user_id] = compte
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_bancaires, f, indent=4, ensure_ascii=False)
|
||||||
|
else:
|
||||||
|
comptes_entreprises[banque_nom][user_id] = compte
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
# Message de confirmation
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="💸 Retrait effectué",
|
||||||
|
description=f"💼 Banque : **{banque_nom}**\n📌 Type : **{source.capitalize()}**",
|
||||||
|
color=discord.Color.red()
|
||||||
|
)
|
||||||
|
embed.add_field(name="RIB", value=rib, inline=False)
|
||||||
|
embed.add_field(name="Montant retiré", value=f"{montant:.2f}€", inline=True)
|
||||||
|
embed.add_field(name="Effectué par", value=interaction.user.mention, inline=True)
|
||||||
|
embed.set_footer(text="Transaction enregistrée ✅")
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=False)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(RetirerArgent(bot))
|
||||||
184
commandes/retrait_gouv.py
Normal file
184
commandes/retrait_gouv.py
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
GOUVERNEMENT_ROLE_ID = 1278305482926194701 # Remplace avec l’ID de ton rôle Gouvernement # Remplace par l'ID du rôle Gouvernement
|
||||||
|
GOUV_BANQUE = "Gouvernement"
|
||||||
|
GOUV_COMPTE = "GOUV"
|
||||||
|
GOUV_RIB = "00000 00000 00000000000 00"
|
||||||
|
|
||||||
|
class GouvVirement(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
# Liste des banques à jour (ajoute ici toutes les banques possibles de ton système)
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="gouv_virer",
|
||||||
|
description="Le Gouvernement vire de l'argent de son compte vers un autre RIB (entreprise ou particulier)."
|
||||||
|
)
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(
|
||||||
|
rib="Le RIB destinataire",
|
||||||
|
montant="Montant à virer",
|
||||||
|
banque="Banque cible (facultatif)"
|
||||||
|
)
|
||||||
|
async def gouv_virer(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
rib: str,
|
||||||
|
montant: float,
|
||||||
|
banque: app_commands.Choice[str] = None
|
||||||
|
):
|
||||||
|
# Vérification du rôle Gouvernement
|
||||||
|
if not any(role.id == GOUVERNEMENT_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Seul le Gouvernement peut utiliser cette commande.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message("❌ Le montant doit être supérieur à zéro.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_nom = banque.value if banque else None
|
||||||
|
|
||||||
|
# Charger les fichiers
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_bancaires = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
comptes_bancaires = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_entreprises = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la lecture des fichiers JSON.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Récupérer le compte du Gouvernement
|
||||||
|
try:
|
||||||
|
gouv_compte = comptes_entreprises[GOUV_BANQUE][GOUV_COMPTE]
|
||||||
|
except KeyError:
|
||||||
|
await interaction.response.send_message("❌ Compte Gouvernement introuvable.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if gouv_compte["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Le Gouvernement n'a pas assez de fonds.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Chercher le destinataire
|
||||||
|
destinataire_compte = None
|
||||||
|
destinataire_banque = None
|
||||||
|
destinataire_nom = None
|
||||||
|
destinataire_type = None
|
||||||
|
|
||||||
|
# Si banque précisée, chercher d'abord dans cette banque (entreprises puis particuliers)
|
||||||
|
if banque_nom:
|
||||||
|
# Entreprises
|
||||||
|
if banque_nom in comptes_entreprises:
|
||||||
|
for nom, data in comptes_entreprises[banque_nom].items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
destinataire_compte = data
|
||||||
|
destinataire_banque = banque_nom
|
||||||
|
destinataire_nom = nom
|
||||||
|
destinataire_type = "entreprise"
|
||||||
|
break
|
||||||
|
# Particuliers
|
||||||
|
if not destinataire_compte and banque_nom in comptes_bancaires:
|
||||||
|
for uid, data in comptes_bancaires[banque_nom].items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
destinataire_compte = data
|
||||||
|
destinataire_banque = banque_nom
|
||||||
|
destinataire_nom = uid
|
||||||
|
destinataire_type = "particulier"
|
||||||
|
break
|
||||||
|
# Si banque non précisée, chercher dans toutes les banques
|
||||||
|
else:
|
||||||
|
# Entreprises
|
||||||
|
for banque_courante, entreprises in comptes_entreprises.items():
|
||||||
|
for nom, data in entreprises.items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
destinataire_compte = data
|
||||||
|
destinataire_banque = banque_courante
|
||||||
|
destinataire_nom = nom
|
||||||
|
destinataire_type = "entreprise"
|
||||||
|
break
|
||||||
|
if destinataire_compte:
|
||||||
|
break
|
||||||
|
# Particuliers
|
||||||
|
if not destinataire_compte:
|
||||||
|
for banque_courante, comptes in comptes_bancaires.items():
|
||||||
|
for uid, data in comptes.items():
|
||||||
|
if data.get("rib") == rib:
|
||||||
|
destinataire_compte = data
|
||||||
|
destinataire_banque = banque_courante
|
||||||
|
destinataire_nom = uid
|
||||||
|
destinataire_type = "particulier"
|
||||||
|
break
|
||||||
|
if destinataire_compte:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not destinataire_compte:
|
||||||
|
await interaction.response.send_message("❌ Aucun compte trouvé avec ce RIB dans la banque spécifiée." if banque_nom else "❌ Aucun compte trouvé avec ce RIB.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Effectuer le virement
|
||||||
|
gouv_compte["solde"] -= montant
|
||||||
|
destinataire_compte["solde"] += montant
|
||||||
|
|
||||||
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
|
||||||
|
# Transaction côté Gouvernement (sortant)
|
||||||
|
gouv_compte.setdefault("transactions", []).append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": "Gouvernement",
|
||||||
|
"montant": -montant,
|
||||||
|
"emetteur": "Gouvernement",
|
||||||
|
"destinataire": destinataire_nom
|
||||||
|
})
|
||||||
|
|
||||||
|
# Transaction côté destinataire (entrant)
|
||||||
|
destinataire_compte.setdefault("transactions", []).append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": "Gouvernement",
|
||||||
|
"montant": montant,
|
||||||
|
"emetteur": "Gouvernement",
|
||||||
|
"destinataire": destinataire_nom
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
comptes_entreprises[GOUV_BANQUE][GOUV_COMPTE] = gouv_compte
|
||||||
|
if destinataire_type == "entreprise":
|
||||||
|
comptes_entreprises[destinataire_banque][destinataire_nom] = destinataire_compte
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
else:
|
||||||
|
comptes_bancaires[destinataire_banque][destinataire_nom] = destinataire_compte
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_bancaires, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
# Message de confirmation
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="🏛️ Virement Gouvernemental effectué",
|
||||||
|
description=f"💼 Banque destinataire : **{destinataire_banque}**\n📌 Type : **{destinataire_type.capitalize()}**",
|
||||||
|
color=discord.Color.gold()
|
||||||
|
)
|
||||||
|
embed.add_field(name="RIB destinataire", value=rib, inline=False)
|
||||||
|
embed.add_field(name="Montant viré", value=f"{montant:.2f}€", inline=True)
|
||||||
|
embed.add_field(name="Effectué par", value=interaction.user.mention, inline=True)
|
||||||
|
embed.set_footer(text="Transaction enregistrée ✅")
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=False)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(GouvVirement(bot))
|
||||||
30
commandes/roll.py
Normal file
30
commandes/roll.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import random
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
|
# Supposons que tu as accès à l'objet bot ou client principal
|
||||||
|
# Utilise bot.tree ou client.tree directement
|
||||||
|
|
||||||
|
@app_commands.command(
|
||||||
|
name="roll",
|
||||||
|
description="Lancer un dé entre deux valeurs avec une raison."
|
||||||
|
)
|
||||||
|
@app_commands.describe(
|
||||||
|
minimum="Valeur minimale",
|
||||||
|
maximum="Valeur maximale",
|
||||||
|
action="Raison du lancer de dé"
|
||||||
|
)
|
||||||
|
async def roll(interaction, minimum: int, maximum: int, action: str):
|
||||||
|
if minimum > maximum:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ La valeur minimale doit être inférieure ou égale à la valeur maximale.", ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
result = random.randint(minimum, maximum)
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"🎲 **{interaction.user.display_name}** a lancé un dé pour l'action *{action}*\n"
|
||||||
|
f"Résultat : **{result}** (entre {minimum} et {maximum})"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pour enregistrer la commande dans le bot :
|
||||||
|
async def setup(bot):
|
||||||
|
bot.tree.add_command(roll)
|
||||||
144
commandes/stats_commandes.py
Normal file
144
commandes/stats_commandes.py
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import io
|
||||||
|
import datetime
|
||||||
|
from utils.stats_manager import get_stats_detailed # fonction fictive améliorée
|
||||||
|
|
||||||
|
class StatsCommandes(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
def plot_barh(self, labels, values, title, xlabel, color='cornflowerblue'):
|
||||||
|
plt.figure(figsize=(8,4))
|
||||||
|
plt.barh(labels[::-1], values[::-1], color=color)
|
||||||
|
plt.title(title)
|
||||||
|
plt.xlabel(xlabel)
|
||||||
|
plt.tight_layout()
|
||||||
|
buf = io.BytesIO()
|
||||||
|
plt.savefig(buf, format='png')
|
||||||
|
plt.close()
|
||||||
|
buf.seek(0)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def plot_line(self, dates, values, title, xlabel, ylabel, color='tab:blue'):
|
||||||
|
plt.figure(figsize=(10,5))
|
||||||
|
plt.plot(dates, values, marker='o', color=color)
|
||||||
|
plt.title(title)
|
||||||
|
plt.xlabel(xlabel)
|
||||||
|
plt.ylabel(ylabel)
|
||||||
|
plt.grid(True, linestyle='--', alpha=0.7)
|
||||||
|
plt.tight_layout()
|
||||||
|
buf = io.BytesIO()
|
||||||
|
plt.savefig(buf, format='png')
|
||||||
|
plt.close()
|
||||||
|
buf.seek(0)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def plot_pie(self, labels, values, title):
|
||||||
|
plt.figure(figsize=(6,6))
|
||||||
|
plt.pie(values, labels=labels, autopct='%1.1f%%', startangle=140, colors=plt.cm.Paired.colors)
|
||||||
|
plt.title(title)
|
||||||
|
plt.tight_layout()
|
||||||
|
buf = io.BytesIO()
|
||||||
|
plt.savefig(buf, format='png')
|
||||||
|
plt.close()
|
||||||
|
buf.seek(0)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
@app_commands.command(name="stats_bot", description="Affiche toutes les statistiques d'utilisation du bot.")
|
||||||
|
async def stats_bot(self, interaction: discord.Interaction):
|
||||||
|
# get_stats_detailed() doit retourner un dict avec les clés suivantes (exemple) :
|
||||||
|
# {
|
||||||
|
# "total_commandes": int,
|
||||||
|
# "top_commandes": [(nom, nb), ...],
|
||||||
|
# "top_utilisateurs": [(user_id, nb), ...],
|
||||||
|
# "evolution_commandes": [(date, nb), ...], # list de tuples date (datetime), nb commandes
|
||||||
|
# "repartition_statuts": {statut: nb, ...},
|
||||||
|
# "commandes_par_jour": {jour_semaine: nb, ...} # ex: "Lundi": 123
|
||||||
|
# }
|
||||||
|
|
||||||
|
stats = get_stats_detailed()
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📊 Statistiques Complètes du Bot",
|
||||||
|
description=f"Total commandes utilisées : **{stats['total_commandes']}**",
|
||||||
|
color=discord.Color.blue()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Top commandes en texte
|
||||||
|
if stats["top_commandes"]:
|
||||||
|
top_cmds_text = "\n".join([f"• `{nom}` : **{nb}** fois" for nom, nb in stats["top_commandes"][:5]])
|
||||||
|
else:
|
||||||
|
top_cmds_text = "Aucune commande utilisée."
|
||||||
|
embed.add_field(name="🏆 Top 5 des commandes", value=top_cmds_text, inline=False)
|
||||||
|
|
||||||
|
# Top utilisateurs en texte
|
||||||
|
if stats["top_utilisateurs"]:
|
||||||
|
top_users_text = "\n".join(
|
||||||
|
[f"• <@{uid}> : **{nb}** commandes" for uid, nb in stats["top_utilisateurs"][:5]]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
top_users_text = "Aucun utilisateur enregistré."
|
||||||
|
embed.add_field(name="👤 Top 5 utilisateurs", value=top_users_text, inline=False)
|
||||||
|
|
||||||
|
# Génération des graphiques
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
# Graphique 1 : Top commandes (barh)
|
||||||
|
if stats["top_commandes"]:
|
||||||
|
noms_cmds = [x[0] for x in stats["top_commandes"][:5]]
|
||||||
|
vals_cmds = [x[1] for x in stats["top_commandes"][:5]]
|
||||||
|
buf1 = self.plot_barh(noms_cmds, vals_cmds, "Top 5 Commandes les plus utilisées", "Nombre d'utilisations")
|
||||||
|
files.append(discord.File(fp=buf1, filename="top_commandes.png"))
|
||||||
|
embed.set_image(url="attachment://top_commandes.png")
|
||||||
|
|
||||||
|
# Graphique 2 : Top utilisateurs (barh)
|
||||||
|
if stats["top_utilisateurs"]:
|
||||||
|
noms_users = [f"User {uid}" for uid, _ in stats["top_utilisateurs"][:5]] # On peut remplacer par mention si on fetch
|
||||||
|
vals_users = [nb for _, nb in stats["top_utilisateurs"][:5]]
|
||||||
|
buf2 = self.plot_barh(noms_users, vals_users, "Top 5 Utilisateurs actifs", "Nombre de commandes", color='mediumseagreen')
|
||||||
|
files.append(discord.File(fp=buf2, filename="top_utilisateurs.png"))
|
||||||
|
|
||||||
|
# Graphique 3 : Évolution commandes dans le temps (line)
|
||||||
|
if stats.get("evolution_commandes"):
|
||||||
|
dates = [d for d, _ in stats["evolution_commandes"]]
|
||||||
|
vals = [v for _, v in stats["evolution_commandes"]]
|
||||||
|
# Convertir dates datetime en string format court
|
||||||
|
dates_str = [d.strftime("%d/%m") for d in dates]
|
||||||
|
buf3 = self.plot_line(dates_str, vals, "Évolution des commandes dans le temps", "Date", "Nombre de commandes")
|
||||||
|
files.append(discord.File(fp=buf3, filename="evolution_commandes.png"))
|
||||||
|
|
||||||
|
# Graphique 4 : Répartition statuts (pie)
|
||||||
|
if stats.get("repartition_statuts"):
|
||||||
|
labels = list(stats["repartition_statuts"].keys())
|
||||||
|
values = list(stats["repartition_statuts"].values())
|
||||||
|
buf4 = self.plot_pie(labels, values, "Répartition des statuts des tâches")
|
||||||
|
files.append(discord.File(fp=buf4, filename="repartition_statuts.png"))
|
||||||
|
|
||||||
|
# Graphique 5 : Commandes par jour de la semaine (bar)
|
||||||
|
if stats.get("commandes_par_jour"):
|
||||||
|
jours = list(stats["commandes_par_jour"].keys())
|
||||||
|
valeurs = list(stats["commandes_par_jour"].values())
|
||||||
|
plt.figure(figsize=(8,4))
|
||||||
|
plt.bar(jours, valeurs, color='salmon')
|
||||||
|
plt.title("Commandes par jour de la semaine")
|
||||||
|
plt.xlabel("Jour")
|
||||||
|
plt.ylabel("Nombre de commandes")
|
||||||
|
plt.tight_layout()
|
||||||
|
buf5 = io.BytesIO()
|
||||||
|
plt.savefig(buf5, format='png')
|
||||||
|
plt.close()
|
||||||
|
buf5.seek(0)
|
||||||
|
files.append(discord.File(fp=buf5, filename="commandes_par_jour.png"))
|
||||||
|
|
||||||
|
# Envoi embed + fichiers graphiques
|
||||||
|
if files:
|
||||||
|
await interaction.response.send_message(embed=embed, files=files)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(embed=embed)
|
||||||
|
|
||||||
|
async def setup(bot: commands.Bot):
|
||||||
|
await bot.add_cog(StatsCommandes(bot))
|
||||||
259
commandes/taches.py
Normal file
259
commandes/taches.py
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
from datetime import datetime
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
from utils.gestion_taches import (
|
||||||
|
ajouter_tache, lister_taches_utilisateur, taches_proches,
|
||||||
|
update_tache_status, charger_taches, supprimer_tache, sauvegarder_taches
|
||||||
|
)
|
||||||
|
|
||||||
|
PRIORITES = ["Haute", "Moyenne", "Basse", "Critique", "Faible"]
|
||||||
|
|
||||||
|
class RappelTacheView(discord.ui.View):
|
||||||
|
def __init__(self, tid: str):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.tid = tid
|
||||||
|
|
||||||
|
@discord.ui.button(label="✅ Marquer comme faite", style=discord.ButtonStyle.success, custom_id="btn_mark_done")
|
||||||
|
async def mark_done(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
success = await update_tache_status(self.tid, "Terminée")
|
||||||
|
if success:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ La tâche #{self.tid} a été marquée comme terminée !", ephemeral=True)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Impossible de mettre à jour la tâche. Peut-être déjà terminée ?", ephemeral=True)
|
||||||
|
self.disable_all_items()
|
||||||
|
await interaction.message.edit(view=self)
|
||||||
|
|
||||||
|
class MesTachesPaginator(discord.ui.View):
|
||||||
|
def __init__(self, interaction: discord.Interaction, taches_list: list[tuple], per_page=5):
|
||||||
|
super().__init__(timeout=120)
|
||||||
|
self.interaction = interaction
|
||||||
|
self.taches = taches_list
|
||||||
|
self.per_page = per_page
|
||||||
|
self.page = 0
|
||||||
|
self.max_page = (len(taches_list) - 1) // per_page
|
||||||
|
|
||||||
|
def get_embed(self):
|
||||||
|
embed = discord.Embed(title="📝 Vos Tâches Assignées", color=discord.Color.green())
|
||||||
|
start = self.page * self.per_page
|
||||||
|
end = start + self.per_page
|
||||||
|
for tid, t in self.taches[start:end]:
|
||||||
|
embed.add_field(
|
||||||
|
name=f"#{tid} - {t['titre']}",
|
||||||
|
value=f"📅 Échéance : {t['échéance']}\n⚠️ Priorité : {t['priorité']}\n📌 Statut : {t['statut']}",
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
embed.set_footer(text=f"Page {self.page + 1} / {self.max_page + 1}")
|
||||||
|
return embed
|
||||||
|
|
||||||
|
@discord.ui.button(label="⬅️", style=discord.ButtonStyle.secondary)
|
||||||
|
async def previous_page(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if interaction.user.id != self.interaction.user.id:
|
||||||
|
await interaction.response.send_message("❌ Ce n'est pas votre pagination.", ephemeral=True)
|
||||||
|
return
|
||||||
|
if self.page > 0:
|
||||||
|
self.page -= 1
|
||||||
|
await interaction.response.edit_message(embed=self.get_embed(), view=self)
|
||||||
|
else:
|
||||||
|
await interaction.response.defer()
|
||||||
|
|
||||||
|
@discord.ui.button(label="➡️", style=discord.ButtonStyle.secondary)
|
||||||
|
async def next_page(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
if interaction.user.id != self.interaction.user.id:
|
||||||
|
await interaction.response.send_message("❌ Ce n'est pas votre pagination.", ephemeral=True)
|
||||||
|
return
|
||||||
|
if self.page < self.max_page:
|
||||||
|
self.page += 1
|
||||||
|
await interaction.response.edit_message(embed=self.get_embed(), view=self)
|
||||||
|
else:
|
||||||
|
await interaction.response.defer()
|
||||||
|
|
||||||
|
class JiraDiscord(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.rappels.start()
|
||||||
|
|
||||||
|
def cog_unload(self):
|
||||||
|
self.rappels.cancel()
|
||||||
|
|
||||||
|
async def autocomplete_priorite(self, interaction: discord.Interaction, current: str):
|
||||||
|
return [
|
||||||
|
app_commands.Choice(name=prio, value=prio)
|
||||||
|
for prio in PRIORITES if current.lower() in prio.lower()
|
||||||
|
][:5]
|
||||||
|
|
||||||
|
@app_commands.command(name="nouvelle_tache", description="Créer une nouvelle tâche")
|
||||||
|
@app_commands.describe(
|
||||||
|
titre="Titre de la tâche",
|
||||||
|
description="Description de la tâche",
|
||||||
|
assigne="Utilisateur assigné",
|
||||||
|
priorite="Niveau de priorité (ex: Haute, Moyenne, Basse)",
|
||||||
|
echeance="Date d'échéance au format JJ/MM/AAAA"
|
||||||
|
)
|
||||||
|
async def nouvelle_tache(
|
||||||
|
self, interaction: discord.Interaction, titre: str, description: str,
|
||||||
|
assigne: discord.User, priorite: str, echeance: str
|
||||||
|
):
|
||||||
|
data = await charger_taches()
|
||||||
|
for tid, tache in data.get("taches", {}).items():
|
||||||
|
if tache["assigné"] == assigne.id and tache["titre"].lower() == titre.lower():
|
||||||
|
return await interaction.response.send_message(
|
||||||
|
f"❌ {assigne.mention} a déjà une tâche avec ce titre.", ephemeral=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
date_obj = datetime.strptime(echeance, "%d/%m/%Y")
|
||||||
|
date_str = date_obj.strftime("%Y-%m-%d")
|
||||||
|
except ValueError:
|
||||||
|
return await interaction.response.send_message(
|
||||||
|
"❌ Format de date invalide (JJ/MM/AAAA).", ephemeral=True)
|
||||||
|
|
||||||
|
id_tache = await ajouter_tache(titre, description, assigne.id, priorite, date_str, interaction.user.id)
|
||||||
|
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"📌 Nouvelle Tâche #{id_tache}",
|
||||||
|
description=description,
|
||||||
|
color=discord.Color.blurple()
|
||||||
|
)
|
||||||
|
embed.set_author(name=f"Assignée à {assigne.display_name}", icon_url=assigne.display_avatar.url)
|
||||||
|
embed.add_field(name="🗂 Titre", value=titre, inline=False)
|
||||||
|
embed.add_field(name="⚠️ Priorité", value=priorite, inline=True)
|
||||||
|
embed.add_field(name="📅 Échéance", value=echeance, inline=True)
|
||||||
|
embed.set_footer(text=f"Créée par {interaction.user.display_name}", icon_url=interaction.user.display_avatar.url)
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await assigne.send(
|
||||||
|
f"👋 Bonjour {assigne.display_name},\n\nUne nouvelle tâche t'a été assignée par {interaction.user.mention} :",
|
||||||
|
embed=embed
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@nouvelle_tache.autocomplete("priorite")
|
||||||
|
async def autocomplete_priorite_handler(self, interaction: discord.Interaction, current: str):
|
||||||
|
return await self.autocomplete_priorite(interaction, current)
|
||||||
|
|
||||||
|
@app_commands.command(name="mes_taches", description="Lister mes tâches assignées")
|
||||||
|
async def mes_taches(self, interaction: discord.Interaction):
|
||||||
|
taches = await lister_taches_utilisateur(interaction.user.id)
|
||||||
|
if not taches:
|
||||||
|
await interaction.response.send_message("🚫 Aucune tâche ne vous est assignée.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
taches_list = list(taches.items())
|
||||||
|
if len(taches_list) <= 5:
|
||||||
|
embed = discord.Embed(title="📝 Vos Tâches Assignées", color=discord.Color.green())
|
||||||
|
for tid, t in taches_list:
|
||||||
|
embed.add_field(
|
||||||
|
name=f"#{tid} - {t['titre']}",
|
||||||
|
value=f"📅 Échéance : {t['échéance']}\n⚠️ Priorité : {t['priorité']}\n📌 Statut : {t['statut']}",
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
else:
|
||||||
|
view = MesTachesPaginator(interaction, taches_list)
|
||||||
|
await interaction.response.send_message(embed=view.get_embed(), view=view, ephemeral=True)
|
||||||
|
|
||||||
|
@app_commands.command(name="update_tache", description="Mettre à jour le statut et la priorité d'une tâche")
|
||||||
|
@app_commands.describe(
|
||||||
|
id_tache="ID de la tâche à mettre à jour",
|
||||||
|
statut="Nouveau statut de la tâche",
|
||||||
|
priorite="Nouvelle priorité (optionnel)"
|
||||||
|
)
|
||||||
|
async def update_tache(
|
||||||
|
self, interaction: discord.Interaction, id_tache: str, statut: str, priorite: str = None
|
||||||
|
):
|
||||||
|
data = await charger_taches()
|
||||||
|
if id_tache not in data.get("taches", {}):
|
||||||
|
return await interaction.response.send_message("❌ Tâche non trouvée.", ephemeral=True)
|
||||||
|
|
||||||
|
tache = data["taches"][id_tache]
|
||||||
|
if tache["assigné"] != interaction.user.id:
|
||||||
|
return await interaction.response.send_message("❌ Vous ne pouvez pas mettre à jour le statut de cette tâche.", ephemeral=True)
|
||||||
|
|
||||||
|
statut_update = await update_tache_status(id_tache, statut)
|
||||||
|
priorite_update = True
|
||||||
|
if priorite:
|
||||||
|
tache["priorité"] = priorite
|
||||||
|
await sauvegarder_taches(data)
|
||||||
|
|
||||||
|
if statut_update and priorite_update:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Le statut de la tâche #{id_tache} a été mis à jour à **{statut}**." +
|
||||||
|
(f"\nLa priorité est maintenant **{priorite}**." if priorite else ""),
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
if tache["créé_par"] != interaction.user.id:
|
||||||
|
try:
|
||||||
|
creator = await self.bot.fetch_user(tache["créé_par"])
|
||||||
|
await creator.send(
|
||||||
|
f"🔔 La tâche #{id_tache} que vous avez créée a été mise à jour par {interaction.user.mention} :\n"
|
||||||
|
f"**Nouveau statut** : {statut}" +
|
||||||
|
(f"\n**Nouvelle priorité** : {priorite}" if priorite else "")
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la mise à jour de la tâche.", ephemeral=True)
|
||||||
|
|
||||||
|
@update_tache.autocomplete("priorite")
|
||||||
|
async def autocomplete_priorite_update(self, interaction: discord.Interaction, current: str):
|
||||||
|
return await self.autocomplete_priorite(interaction, current)
|
||||||
|
|
||||||
|
@app_commands.command(name="supprimer_tache", description="Supprimer une tâche")
|
||||||
|
@app_commands.describe(
|
||||||
|
id_tache="ID de la tâche à supprimer"
|
||||||
|
)
|
||||||
|
async def supprimer_tache_cmd(self, interaction: discord.Interaction, id_tache: str):
|
||||||
|
data = await charger_taches()
|
||||||
|
if id_tache not in data.get("taches", {}):
|
||||||
|
return await interaction.response.send_message("❌ Tâche non trouvée.", ephemeral=True)
|
||||||
|
|
||||||
|
tache = data["taches"][id_tache]
|
||||||
|
perms = interaction.user.guild_permissions
|
||||||
|
can_delete = (
|
||||||
|
tache["créé_par"] == interaction.user.id or
|
||||||
|
tache["assigné"] == interaction.user.id or
|
||||||
|
perms.administrator
|
||||||
|
)
|
||||||
|
if not can_delete:
|
||||||
|
return await interaction.response.send_message("❌ Vous ne pouvez pas supprimer cette tâche.", ephemeral=True)
|
||||||
|
|
||||||
|
success = await supprimer_tache(id_tache)
|
||||||
|
if success:
|
||||||
|
await interaction.response.send_message(f"🗑️ La tâche #{id_tache} a été supprimée.", ephemeral=True)
|
||||||
|
else:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la suppression de la tâche.", ephemeral=True)
|
||||||
|
|
||||||
|
@tasks.loop(seconds=30)
|
||||||
|
async def rappels(self):
|
||||||
|
now = datetime.now(ZoneInfo("Europe/Paris"))
|
||||||
|
if now.hour == 9 and now.minute == 0:
|
||||||
|
taches = await taches_proches()
|
||||||
|
for tid, t in taches.items():
|
||||||
|
try:
|
||||||
|
user = await self.bot.fetch_user(t["assigné"])
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"🔔 Rappel Tâche #{tid}",
|
||||||
|
description=t["description"],
|
||||||
|
color=discord.Color.orange()
|
||||||
|
)
|
||||||
|
embed.add_field(name="🗂 Titre", value=t["titre"], inline=False)
|
||||||
|
embed.add_field(name="⚠️ Priorité", value=t["priorité"], inline=True)
|
||||||
|
embed.add_field(name="📅 Échéance", value=t["échéance"], inline=True)
|
||||||
|
embed.set_footer(text="Clique sur le bouton si tu as fini !")
|
||||||
|
view = RappelTacheView(tid)
|
||||||
|
await user.send(embed=embed, view=view)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
@rappels.before_loop
|
||||||
|
async def avant_rappel(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(JiraDiscord(bot))
|
||||||
329
commandes/ticket.py
Normal file
329
commandes/ticket.py
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from discord import app_commands
|
||||||
|
|
||||||
|
TICKET_CATEGORY_ID = 1301142883876737085 # ID de la catégorie des tickets # ID de la catégorie des tickets
|
||||||
|
STAFF_ROLE_ID = 1277638784095092816 # ID du rôle staff # ID du rôle staff
|
||||||
|
TEAM_STAFF_ROLE_ID = 1277638784095092816 # ID du rôle équipe staff # ID du rôle équipe staff
|
||||||
|
ATTENTE_ORAL_ROLE_ID = 1278343007996870699 # ID du rôle "attente oral" # ID du rôle "attente oral"
|
||||||
|
CANDIDATURE_A_FAIRE_ROLE_ID = 1278343541936099412 # ID du rôle "candidature à faire" # ID du rôle "candidature à faire"
|
||||||
|
CITOYEN_ROLE_ID = 1278319901651632138 # ID du rôle "citoyen" # ID du rôle "citoyen"
|
||||||
|
|
||||||
|
class ContinueFormView(discord.ui.View):
|
||||||
|
"""Vue avec un bouton pour continuer à l'étape suivante"""
|
||||||
|
|
||||||
|
def __init__(self, current_step, step1_data=None, step2_part1_data=None, step2_part2_data=None):
|
||||||
|
super().__init__(timeout=180.0) # Définir un timeout pour la vue
|
||||||
|
self.current_step = current_step
|
||||||
|
self.step1_data = step1_data
|
||||||
|
self.step2_part1_data = step2_part1_data
|
||||||
|
self.step2_part2_data = step2_part2_data
|
||||||
|
|
||||||
|
@discord.ui.button(label="📋 Continuer le formulaire", style=discord.ButtonStyle.green, custom_id="continue_form")
|
||||||
|
async def continue_form(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Passe à l'étape suivante du formulaire"""
|
||||||
|
if self.current_step == 1:
|
||||||
|
await interaction.response.send_modal(TicketStep2Part1(self.step1_data))
|
||||||
|
elif self.current_step == 2:
|
||||||
|
await interaction.response.send_modal(TicketStep2Part2(self.step1_data, self.step2_part1_data))
|
||||||
|
elif self.current_step == 3:
|
||||||
|
await interaction.response.send_modal(TicketStep3(self.step1_data, self.step2_part1_data, self.step2_part2_data))
|
||||||
|
|
||||||
|
# Vérifier si le message existe toujours avant de le modifier
|
||||||
|
try:
|
||||||
|
await interaction.message.edit(view=self)
|
||||||
|
except discord.errors.NotFound:
|
||||||
|
# Si le message n'existe plus, nous ne faisons rien
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TicketStep1(discord.ui.Modal, title="📋 Informations Personnelles"):
|
||||||
|
"""Étape 1 du formulaire - Infos personnelles"""
|
||||||
|
|
||||||
|
pseudo = discord.ui.TextInput(label="Pseudo Epic (Fortnite)", required=True, max_length=16)
|
||||||
|
age = discord.ui.TextInput(label="Âge", required=True, max_length=2)
|
||||||
|
experience = discord.ui.TextInput(label="Expérience RP ?", style=discord.TextStyle.paragraph, required=True, max_length=50)
|
||||||
|
decouverte = discord.ui.TextInput(label="Comment as-tu découvert le serveur ?", required=True, max_length=20)
|
||||||
|
micro = discord.ui.TextInput(label="As-tu un micro de qualité ?", required=True, max_length=3)
|
||||||
|
|
||||||
|
async def on_submit(self, interaction: discord.Interaction):
|
||||||
|
"""Envoie un bouton pour passer à l'étape 2"""
|
||||||
|
view = ContinueFormView(current_step=1, step1_data=self)
|
||||||
|
await interaction.response.send_message("✅ Première étape terminée ! Cliquez ci-dessous pour continuer.", view=view, ephemeral=True)
|
||||||
|
|
||||||
|
class TicketStep2Part1(discord.ui.Modal, title="👤 Infos sur ton personnage (Partie 1)"):
|
||||||
|
"""Étape 2 du formulaire - Infos RP (Partie 1)"""
|
||||||
|
|
||||||
|
def __init__(self, step1_data):
|
||||||
|
super().__init__()
|
||||||
|
self.step1_data = step1_data
|
||||||
|
|
||||||
|
prenom = discord.ui.TextInput(label="Prénom", required=True)
|
||||||
|
nom = discord.ui.TextInput(label="Nom", required=True)
|
||||||
|
age_perso = discord.ui.TextInput(label="Âge du personnage", required=True)
|
||||||
|
genre = discord.ui.TextInput(label="Genre", required=True, max_length=5)
|
||||||
|
naissance = discord.ui.TextInput(label="Date et lieu de naissance", required=True)
|
||||||
|
|
||||||
|
async def on_submit(self, interaction: discord.Interaction):
|
||||||
|
"""Envoie un bouton pour passer à l'étape suivante"""
|
||||||
|
view = ContinueFormView(current_step=2, step1_data=self.step1_data, step2_part1_data=self)
|
||||||
|
await interaction.response.send_message("✅ Deuxième partie terminée ! Cliquez ci-dessous pour continuer.", view=view, ephemeral=True)
|
||||||
|
|
||||||
|
class TicketStep2Part2(discord.ui.Modal, title="👤 Infos sur ton personnage (Partie 2)"):
|
||||||
|
"""Étape 2 du formulaire - Infos RP (Partie 2)"""
|
||||||
|
|
||||||
|
def __init__(self, step1_data, step2_part1_data):
|
||||||
|
super().__init__()
|
||||||
|
self.step1_data = step1_data
|
||||||
|
self.step2_part1_data = step2_part1_data
|
||||||
|
|
||||||
|
traits = discord.ui.TextInput(label="Traits de caractère", required=True)
|
||||||
|
nationalite = discord.ui.TextInput(label="Nationalité", required=True)
|
||||||
|
skin_rp = discord.ui.TextInput(label="Skin RP", required=True)
|
||||||
|
metier_souhaite = discord.ui.TextInput(label="Métier souhaité", required=True)
|
||||||
|
|
||||||
|
async def on_submit(self, interaction: discord.Interaction):
|
||||||
|
"""Envoie un bouton pour passer à l'étape 3"""
|
||||||
|
view = ContinueFormView(current_step=3, step1_data=self.step1_data, step2_part1_data=self.step2_part1_data, step2_part2_data=self)
|
||||||
|
await interaction.response.send_message("✅ Deuxième étape terminée ! Cliquez ci-dessous pour continuer.", view=view, ephemeral=True)
|
||||||
|
|
||||||
|
class TicketStep3(discord.ui.Modal, title="📋 Développement du Personnage"):
|
||||||
|
"""Étape 3 du formulaire - Histoire du personnage"""
|
||||||
|
|
||||||
|
def __init__(self, step1_data, step2_part1_data, step2_part2_data):
|
||||||
|
super().__init__()
|
||||||
|
self.step1_data = step1_data
|
||||||
|
self.step2_part1_data = step2_part1_data
|
||||||
|
self.step2_part2_data = step2_part2_data
|
||||||
|
|
||||||
|
histoire = discord.ui.TextInput(
|
||||||
|
label="Histoire du personnage",
|
||||||
|
style=discord.TextStyle.paragraph,
|
||||||
|
required=True,
|
||||||
|
min_length=425,
|
||||||
|
max_length=500 # Limite de caractères maximum
|
||||||
|
)
|
||||||
|
objectifs = discord.ui.TextInput(label="Objectifs RP (court et long terme)", style=discord.TextStyle.paragraph, required=True, max_length=100)
|
||||||
|
|
||||||
|
async def on_submit(self, interaction: discord.Interaction):
|
||||||
|
"""Création du ticket après validation"""
|
||||||
|
guild = interaction.guild
|
||||||
|
user = interaction.user
|
||||||
|
category = discord.utils.get(guild.categories, id=TICKET_CATEGORY_ID)
|
||||||
|
|
||||||
|
# Vérifier si la catégorie existe
|
||||||
|
if category is None:
|
||||||
|
await interaction.response.send_message("❌ Erreur : La catégorie des tickets n'existe pas !", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier si le rôle staff existe
|
||||||
|
staff_role = discord.utils.get(guild.roles, id=STAFF_ROLE_ID)
|
||||||
|
if staff_role is None:
|
||||||
|
await interaction.response.send_message("❌ Erreur : Le rôle staff n'existe pas !", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier si l'utilisateur a déjà un ticket ouvert
|
||||||
|
for channel in category.text_channels:
|
||||||
|
if channel.topic == f"Ticket de {user.id}":
|
||||||
|
await interaction.response.send_message(f"❌ Vous avez déjà un ticket ouvert : {channel.mention}", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Définir les permissions du salon du ticket
|
||||||
|
overwrites = {
|
||||||
|
guild.default_role: discord.PermissionOverwrite(read_messages=False),
|
||||||
|
user: discord.PermissionOverwrite(read_messages=True, send_messages=True),
|
||||||
|
staff_role: discord.PermissionOverwrite(read_messages=True, send_messages=True),
|
||||||
|
discord.utils.get(guild.roles, id=TEAM_STAFF_ROLE_ID): discord.PermissionOverwrite(read_messages=True, send_messages=False)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Créer un salon de ticket avec le nom [pseudo_du_membre]-écrit
|
||||||
|
ticket_channel = await category.create_text_channel(
|
||||||
|
name=f"{user.name}-écrit",
|
||||||
|
topic=f"Ticket de {user.id}",
|
||||||
|
overwrites=overwrites
|
||||||
|
)
|
||||||
|
|
||||||
|
# Récupérer le rôle "équipe staff"
|
||||||
|
team_staff_role = discord.utils.get(guild.roles, id=TEAM_STAFF_ROLE_ID)
|
||||||
|
|
||||||
|
# Création de l'embed avec les infos du formulaire
|
||||||
|
embed = discord.Embed(title="📩 Ticket Whitelist", color=0x00ff00)
|
||||||
|
embed.add_field(name="📋 - Informations Personnelles", value=(
|
||||||
|
f"> - Pseudo Epic : {self.step1_data.pseudo.value}\n"
|
||||||
|
f"> - Âge : {self.step1_data.age.value}\n"
|
||||||
|
f"> - Expérience RP : {self.step1_data.experience.value}\n"
|
||||||
|
f"> - Découverte du serveur : {self.step1_data.decouverte.value}\n"
|
||||||
|
f"> - Micro de qualité : {self.step1_data.micro.value}"
|
||||||
|
), inline=False)
|
||||||
|
embed.add_field(name="👤 - Informations RP", value=(
|
||||||
|
f"> - Prénom : {self.step2_part1_data.prenom.value}\n"
|
||||||
|
f"> - Nom : {self.step2_part1_data.nom.value}\n"
|
||||||
|
f"> - Âge du personnage : {self.step2_part1_data.age_perso.value}\n"
|
||||||
|
f"> - Genre : {self.step2_part1_data.genre.value}\n"
|
||||||
|
f"> - Naissance : {self.step2_part1_data.naissance.value}\n"
|
||||||
|
f"> - Traits de caractère : {self.step2_part2_data.traits.value}\n"
|
||||||
|
f"> - Nationalité : {self.step2_part2_data.nationalite.value}\n"
|
||||||
|
f"> - Skin RP : {self.step2_part2_data.skin_rp.value}\n"
|
||||||
|
f"> - Métier souhaité : {self.step2_part2_data.metier_souhaite.value}"
|
||||||
|
), inline=False)
|
||||||
|
embed.add_field(name="📋 - Développement du Personnage", value=(
|
||||||
|
f"> - Histoire : {self.histoire.value}\n"
|
||||||
|
f"> - Objectifs : {self.objectifs.value}"
|
||||||
|
), inline=False)
|
||||||
|
|
||||||
|
# Envoyer l'embed avec les boutons d'actions pour les staff
|
||||||
|
await ticket_channel.send(embed=embed, view=TicketManagementView(user))
|
||||||
|
|
||||||
|
# Envoyer un message pour mentionner l'équipe staff
|
||||||
|
await ticket_channel.send(f"{team_staff_role.mention} - Nouveau ticket créé !")
|
||||||
|
|
||||||
|
# Mettre à jour le pseudo du joueur si le bot a les permissions nécessaires
|
||||||
|
if guild.me.guild_permissions.manage_nicknames:
|
||||||
|
new_nickname = f"{self.step2_part1_data.prenom.value} {self.step2_part1_data.nom.value} | {self.step1_data.pseudo.value}"
|
||||||
|
if len(new_nickname) > 32:
|
||||||
|
new_nickname = new_nickname[:32]
|
||||||
|
await user.edit(nick=new_nickname)
|
||||||
|
else:
|
||||||
|
await interaction.followup.send("❌ Le bot n'a pas les permissions nécessaires pour modifier le pseudo.", ephemeral=True)
|
||||||
|
|
||||||
|
# Envoyer un message de confirmation
|
||||||
|
try:
|
||||||
|
await interaction.response.send_message(f"✅ Ticket ouvert : {ticket_channel.mention}", ephemeral=True)
|
||||||
|
except discord.errors.NotFound:
|
||||||
|
await interaction.followup.send(f"✅ Ticket ouvert : {ticket_channel.mention}", ephemeral=True)
|
||||||
|
|
||||||
|
class TicketManagementView(discord.ui.View):
|
||||||
|
"""Vue pour gérer le ticket avec les boutons Fermer, Réouvrir, Claim et Supprimer"""
|
||||||
|
|
||||||
|
def __init__(self, ticket_owner):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.ticket_owner = ticket_owner
|
||||||
|
self.claimed_by = None # Stocke le staff qui claim le ticket
|
||||||
|
|
||||||
|
@discord.ui.button(label="🔒 Fermer le Ticket", style=discord.ButtonStyle.red, custom_id="close_ticket")
|
||||||
|
async def close_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Ferme le ticket en désactivant l'envoi de messages pour le membre"""
|
||||||
|
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
|
||||||
|
await interaction.response.send_message("❌ Seuls les staffs peuvent fermer un ticket.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await interaction.channel.set_permissions(self.ticket_owner, read_messages=False, send_messages=False)
|
||||||
|
await interaction.channel.edit(name="ticket-fermé")
|
||||||
|
await interaction.response.send_message("🔒 Le ticket a été fermé. Vous ne pouvez plus le voir.", ephemeral=True)
|
||||||
|
|
||||||
|
# Mettre à jour la vue pour afficher uniquement les boutons Réouvrir et Supprimer
|
||||||
|
new_view = ClosedTicketView(self.ticket_owner)
|
||||||
|
await interaction.channel.send("Le ticket a été fermé.", view=new_view)
|
||||||
|
|
||||||
|
@discord.ui.button(label="👤 Prendre en charge le Ticket", style=discord.ButtonStyle.blurple, custom_id="claim_ticket")
|
||||||
|
async def claim_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Un staff prend en charge le ticket"""
|
||||||
|
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
|
||||||
|
await interaction.response.send_message("❌ Seuls les staffs peuvent claim un ticket.", ephemeral=True)
|
||||||
|
return
|
||||||
|
self.claimed_by = interaction.user
|
||||||
|
await interaction.channel.set_permissions(discord.utils.get(interaction.guild.roles, id=STAFF_ROLE_ID), send_messages=False, read_messages=True)
|
||||||
|
await interaction.channel.set_permissions(self.claimed_by, read_messages=True, send_messages=True)
|
||||||
|
await interaction.response.send_message(f"👤 {self.claimed_by.mention} a claim ce ticket.", ephemeral=False)
|
||||||
|
|
||||||
|
class ClosedTicketView(discord.ui.View):
|
||||||
|
"""Vue pour les tickets fermés avec les boutons Réouvrir et Supprimer"""
|
||||||
|
|
||||||
|
def __init__(self, ticket_owner):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
self.ticket_owner = ticket_owner
|
||||||
|
|
||||||
|
@discord.ui.button(label="♻ Réouvrir le Ticket", style=discord.ButtonStyle.green, custom_id="reopen_ticket")
|
||||||
|
async def reopen_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Réouvre le ticket pour le membre"""
|
||||||
|
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
|
||||||
|
await interaction.response.send_message("❌ Seuls les staffs peuvent réouvrir un ticket.", ephemeral=True)
|
||||||
|
return
|
||||||
|
await interaction.channel.set_permissions(self.ticket_owner, read_messages=True, send_messages=True)
|
||||||
|
await interaction.response.send_message("✅ Le ticket a été réouvert.", ephemeral=True)
|
||||||
|
|
||||||
|
# Mettre à jour la vue pour afficher tous les boutons
|
||||||
|
new_view = TicketManagementView(self.ticket_owner)
|
||||||
|
await interaction.channel.send("Le ticket a été réouvert.", view=new_view)
|
||||||
|
|
||||||
|
@discord.ui.button(label="❌ Supprimer le Ticket", style=discord.ButtonStyle.danger, custom_id="delete_ticket")
|
||||||
|
async def delete_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Supprime le salon du ticket"""
|
||||||
|
if not discord.utils.get(interaction.user.roles, id=STAFF_ROLE_ID):
|
||||||
|
await interaction.response.send_message("❌ Seuls les staffs peuvent supprimer un ticket.", ephemeral=True)
|
||||||
|
return
|
||||||
|
await interaction.response.send_message("❌ Suppression du ticket...", ephemeral=True)
|
||||||
|
await interaction.channel.delete()
|
||||||
|
|
||||||
|
class TicketView(discord.ui.View):
|
||||||
|
"""Vue avec le bouton pour ouvrir le ticket"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(timeout=None)
|
||||||
|
|
||||||
|
@discord.ui.button(label="📑 Ouvrir un Ticket Whitelist", style=discord.ButtonStyle.red, custom_id="open_ticket")
|
||||||
|
async def open_ticket(self, interaction: discord.Interaction, button: discord.ui.Button):
|
||||||
|
"""Affiche le premier formulaire"""
|
||||||
|
await interaction.response.send_modal(TicketStep1())
|
||||||
|
|
||||||
|
class Ticket(commands.Cog):
|
||||||
|
"""Commande pour envoyer l'embed de ticket"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="ticket", description="Envoie l'embed pour ouvrir un ticket.")
|
||||||
|
async def ticket(self, interaction: discord.Interaction):
|
||||||
|
"""Envoie l'embed avec le bouton d'ouverture de ticket"""
|
||||||
|
embed = discord.Embed(
|
||||||
|
title="📩 Ticket Whitelist",
|
||||||
|
description="Pour réaliser votre whitelist, ouvrez un ticket et remplissez le formulaire.",
|
||||||
|
color=0x00ff00
|
||||||
|
)
|
||||||
|
view = TicketView()
|
||||||
|
await interaction.channel.send(embed=embed, view=view)
|
||||||
|
await interaction.response.send_message("✅ Embed des tickets envoyé.", ephemeral=True)
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_message(self, message):
|
||||||
|
"""Surveille les messages des staffs dans les tickets"""
|
||||||
|
if message.guild is None or message.author.bot:
|
||||||
|
return
|
||||||
|
if not message.channel.topic or not message.channel.topic.startswith("Ticket de"):
|
||||||
|
return
|
||||||
|
|
||||||
|
staff_role = discord.utils.get(message.guild.roles, id=STAFF_ROLE_ID)
|
||||||
|
if staff_role in message.author.roles and "validé" in message.content.lower():
|
||||||
|
try:
|
||||||
|
user_id = message.channel.topic.split("Ticket de ")[1]
|
||||||
|
user = await message.guild.fetch_member(user_id)
|
||||||
|
|
||||||
|
# Vérifier si le rôle "attente oral" est déjà attribué
|
||||||
|
attente_oral_role = discord.utils.get(message.guild.roles, id=ATTENTE_ORAL_ROLE_ID)
|
||||||
|
candidature_a_faire_role = discord.utils.get(message.guild.roles, id=CANDIDATURE_A_FAIRE_ROLE_ID)
|
||||||
|
citoyen_role = discord.utils.get(message.guild.roles, id=CITOYEN_ROLE_ID)
|
||||||
|
|
||||||
|
if attente_oral_role in user.roles:
|
||||||
|
# Deuxième "validé" détecté
|
||||||
|
await user.remove_roles(attente_oral_role)
|
||||||
|
await user.add_roles(citoyen_role)
|
||||||
|
await message.channel.edit(name=f"{user.name}-citoyen")
|
||||||
|
else:
|
||||||
|
# Premier "validé" détecté
|
||||||
|
await user.remove_roles(candidature_a_faire_role)
|
||||||
|
await user.add_roles(attente_oral_role)
|
||||||
|
await message.channel.edit(name=f"{user.name}-oral")
|
||||||
|
|
||||||
|
# Mettre à jour le pseudo du joueur si le bot a les permissions nécessaires
|
||||||
|
if message.guild.me.guild_permissions.manage_nicknames:
|
||||||
|
new_nickname = f"{self.step2_part1_data.prenom.value} {self.step2_part1_data.nom.value} | {self.step1_data.pseudo.value}"
|
||||||
|
if len(new_nickname) > 32:
|
||||||
|
new_nickname = new_nickname[:32]
|
||||||
|
await user.edit(nick=new_nickname)
|
||||||
|
else:
|
||||||
|
await message.channel.send("❌ Le bot n'a pas les permissions nécessaires pour modifier le pseudo.", delete_after=10)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors du renommage du ticket: {e}")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Ticket(bot))
|
||||||
67
commandes/transactions.py
Normal file
67
commandes/transactions.py
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.banque_manager import BanqueManager
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier # ID du rôle des banquiers
|
||||||
|
|
||||||
|
banque_manager = BanqueManager()
|
||||||
|
|
||||||
|
class Transactions(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="transactions", description="Affiche les transactions d'un utilisateur (réservé aux banquiers).")
|
||||||
|
async def transactions(self, interaction: discord.Interaction, utilisateur: discord.Member):
|
||||||
|
"""Affiche l'historique des transactions d'un utilisateur (banquiers uniquement)."""
|
||||||
|
|
||||||
|
# ✅ Récupération du vrai membre pour avoir les rôles
|
||||||
|
member = interaction.guild.get_member(interaction.user.id)
|
||||||
|
if not member:
|
||||||
|
await interaction.response.send_message("❌ Impossible de vérifier vos permissions.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# ✅ Vérification du rôle banquier
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in member.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission de voir les transactions.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_manager.load_data()
|
||||||
|
|
||||||
|
user_id = str(utilisateur.id)
|
||||||
|
|
||||||
|
# ✅ Vérification si l'utilisateur a des transactions
|
||||||
|
if user_id not in banque_manager.comptes or "transactions" not in banque_manager.comptes[user_id]:
|
||||||
|
await interaction.response.send_message(f"❌ {utilisateur.mention} n'a pas d'historique de transactions.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
transactions = banque_manager.comptes[user_id].get("transactions", [])
|
||||||
|
|
||||||
|
if not transactions:
|
||||||
|
await interaction.response.send_message(f"📜 {utilisateur.mention} n'a encore effectué aucune transaction.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# ✅ Création de l'embed
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"📜 Historique des transactions de {utilisateur.name}",
|
||||||
|
color=discord.Color.gold()
|
||||||
|
)
|
||||||
|
|
||||||
|
for t in transactions[-10:]:
|
||||||
|
embed.add_field(
|
||||||
|
name=f"📅 {t['date']}",
|
||||||
|
value=(
|
||||||
|
f"**Type**: {t['type']}\n"
|
||||||
|
f"💰 **Montant**: {t['montant']}€\n"
|
||||||
|
f"📤 **Émetteur**: <@{t['emetteur']}>\n"
|
||||||
|
f"📥 **Destinataire**: <@{t['destinataire']}>"
|
||||||
|
),
|
||||||
|
inline=False
|
||||||
|
)
|
||||||
|
|
||||||
|
embed.set_footer(text="Seules les 10 dernières transactions sont affichées.")
|
||||||
|
|
||||||
|
await interaction.response.send_message(embed=embed)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Transactions(bot))
|
||||||
77
commandes/valider_visite_médicale.py
Normal file
77
commandes/valider_visite_médicale.py
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands, tasks
|
||||||
|
import json
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import os
|
||||||
|
|
||||||
|
EMS_ROLE_ID = 1278317212675084328 # Remplace par l’ID du rôle EMS # Remplace par l’ID du rôle EMS
|
||||||
|
ROLE_A_ATTRIBUER_ID = 1367198876548993045 # Remplace par l’ID du rôle visite médicale # Remplace par l’ID du rôle à attribuer
|
||||||
|
FICHIER_ROLES = "visite_médicale.json"
|
||||||
|
|
||||||
|
class AttribuerRole(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.roles_temporaire = self.charger_roles()
|
||||||
|
self.verification_roles.start()
|
||||||
|
|
||||||
|
def charger_roles(self):
|
||||||
|
if os.path.exists(FICHIER_ROLES):
|
||||||
|
with open(FICHIER_ROLES, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def sauvegarder_roles(self):
|
||||||
|
with open(FICHIER_ROLES, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(self.roles_temporaire, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
@app_commands.command(name="valider_visite_médicale", description="Attribue un rôle temporaire suite à une visite médicale (EMS uniquement).")
|
||||||
|
async def valider_visite(self, interaction: discord.Interaction, membre: discord.Member):
|
||||||
|
if not any(role.id == EMS_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Seuls les EMS peuvent utiliser cette commande.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
role = interaction.guild.get_role(ROLE_A_ATTRIBUER_ID)
|
||||||
|
if not role:
|
||||||
|
await interaction.response.send_message("❌ Rôle à attribuer introuvable.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await membre.add_roles(role)
|
||||||
|
expiration = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
self.roles_temporaire[str(membre.id)] = {
|
||||||
|
"role_id": role.id,
|
||||||
|
"expiration": expiration
|
||||||
|
}
|
||||||
|
self.sauvegarder_roles()
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Rôle temporaire attribué à {membre.mention} jusqu'au {expiration}.", ephemeral=True)
|
||||||
|
|
||||||
|
@tasks.loop(hours=1)
|
||||||
|
async def verification_roles(self):
|
||||||
|
now = datetime.now()
|
||||||
|
to_remove = []
|
||||||
|
|
||||||
|
for user_id, data in self.roles_temporaire.items():
|
||||||
|
expiration = datetime.strptime(data["expiration"], "%Y-%m-%d %H:%M:%S")
|
||||||
|
if now >= expiration:
|
||||||
|
to_remove.append(user_id)
|
||||||
|
|
||||||
|
for user_id in to_remove:
|
||||||
|
member = self.bot.get_user(int(user_id)) or await self.bot.fetch_user(int(user_id))
|
||||||
|
guild = discord.utils.get(self.bot.guilds)
|
||||||
|
member = guild.get_member(int(user_id))
|
||||||
|
role = guild.get_role(ROLE_A_ATTRIBUER_ID)
|
||||||
|
|
||||||
|
if member and role:
|
||||||
|
await member.remove_roles(role)
|
||||||
|
del self.roles_temporaire[user_id]
|
||||||
|
|
||||||
|
if to_remove:
|
||||||
|
self.sauvegarder_roles()
|
||||||
|
|
||||||
|
@verification_roles.before_loop
|
||||||
|
async def before_verification(self):
|
||||||
|
await self.bot.wait_until_ready()
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(AttribuerRole(bot))
|
||||||
138
commandes/virement.py
Normal file
138
commandes/virement.py
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
import json
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class Virement(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement", description="Fait un virement bancaire à un autre membre via son RIB")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(rib="Le RIB du destinataire", montant="Le montant à envoyer", banque="Banque d'où retirer l'argent")
|
||||||
|
async def virement(self, interaction: discord.Interaction, rib: str, montant: float, banque: app_commands.Choice[str]):
|
||||||
|
auteur_id = str(interaction.user.id)
|
||||||
|
banque_source = banque.value
|
||||||
|
|
||||||
|
# Charger les comptes utilisateurs
|
||||||
|
with open('comptes_bancaires.json', 'r', encoding='utf-8') as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
|
||||||
|
# Charger les comptes entreprises
|
||||||
|
with open('comptes_entreprises.json', 'r', encoding='utf-8') as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
|
||||||
|
# Vérifier que l'utilisateur a un compte dans cette banque
|
||||||
|
if banque_source not in comptes or auteur_id not in comptes[banque_source]:
|
||||||
|
await interaction.response.send_message(f"❌ Tu n'as pas de compte dans la banque **{banque_source}**.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte_emetteur = comptes[banque_source][auteur_id]
|
||||||
|
if compte_emetteur["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Ton solde est insuffisant pour effectuer ce virement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Rechercher le destinataire (utilisateur ou entreprise)
|
||||||
|
destinataire_id = None
|
||||||
|
banque_destinataire = None
|
||||||
|
is_entreprise = False
|
||||||
|
|
||||||
|
# Recherche dans comptes utilisateurs
|
||||||
|
for bq_name, bq_data in comptes.items():
|
||||||
|
if isinstance(bq_data, dict):
|
||||||
|
for user_id, info in bq_data.items():
|
||||||
|
if isinstance(info, dict) and info.get("rib") == rib:
|
||||||
|
destinataire_id = user_id
|
||||||
|
banque_destinataire = bq_name
|
||||||
|
break
|
||||||
|
if destinataire_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Sinon, recherche dans les entreprises
|
||||||
|
if not destinataire_id:
|
||||||
|
for bq_name, bq_data in entreprises.items():
|
||||||
|
if isinstance(bq_data, dict):
|
||||||
|
for ent_id, info in bq_data.items():
|
||||||
|
if isinstance(info, dict) and info.get("rib") == rib:
|
||||||
|
destinataire_id = ent_id
|
||||||
|
banque_destinataire = bq_name
|
||||||
|
is_entreprise = True
|
||||||
|
break
|
||||||
|
if destinataire_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not destinataire_id:
|
||||||
|
await interaction.response.send_message("❌ Aucun compte trouvé avec ce RIB.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Appliquer la TVA si entreprise
|
||||||
|
montant_net = montant
|
||||||
|
tva_envoyee = 0
|
||||||
|
if is_entreprise:
|
||||||
|
taux = entreprises[banque_destinataire][destinataire_id].get("tva", 0)
|
||||||
|
tva_envoyee = round(montant * taux / 100, 2)
|
||||||
|
montant_net = montant - tva_envoyee
|
||||||
|
|
||||||
|
# Ajouter la TVA au Gouvernement
|
||||||
|
if "Gouvernement" not in entreprises:
|
||||||
|
entreprises["Gouvernement"] = {}
|
||||||
|
if "GOUV" not in entreprises["Gouvernement"]:
|
||||||
|
entreprises["Gouvernement"]["GOUV"] = {
|
||||||
|
"rib": "00000 00000 00000000000 00",
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
entreprises["Gouvernement"]["GOUV"]["solde"] += tva_envoyee
|
||||||
|
entreprises["Gouvernement"]["GOUV"]["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": auteur_id,
|
||||||
|
"montant": tva_envoyee
|
||||||
|
})
|
||||||
|
|
||||||
|
# Déduire du compte émetteur
|
||||||
|
comptes[banque_source][auteur_id]["solde"] -= montant
|
||||||
|
comptes[banque_source][auteur_id]["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement",
|
||||||
|
"source": f"Vers RIB {rib}",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ajouter au compte destinataire
|
||||||
|
cible_data = entreprises if is_entreprise else comptes
|
||||||
|
cible_data[banque_destinataire][destinataire_id]["solde"] += montant_net
|
||||||
|
cible_data[banque_destinataire][destinataire_id]["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": interaction.user.name,
|
||||||
|
"montant": montant_net
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
with open('comptes_bancaires.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(comptes, f, ensure_ascii=False, indent=4)
|
||||||
|
with open('comptes_entreprises.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(entreprises, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
# Envoi MP au destinataire si c'est un utilisateur
|
||||||
|
if not is_entreprise:
|
||||||
|
try:
|
||||||
|
user_dest = await self.bot.fetch_user(int(destinataire_id))
|
||||||
|
await user_dest.send(f"📥 Vous avez reçu un virement de **{montant:.2f}€** de la part de **{interaction.user.display_name}**.")
|
||||||
|
except:
|
||||||
|
pass # Si l'utilisateur a les MP désactivés
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Virement de **{montant:.2f}€** effectué.{' TVA de ' + str(tva_envoyee) + '€ envoyée au Gouvernement.' if is_entreprise else ''}",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(Virement(bot))
|
||||||
86
commandes/virement_banquier.py
Normal file
86
commandes/virement_banquier.py
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import json
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier # À remplacer par l’ID réel du rôle banquier
|
||||||
|
|
||||||
|
class VirementBanquier(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_banquier", description="Effectue un virement au nom d'un client (réservé aux banquiers).")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
async def virement_banquier(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
rib_emetteur: str,
|
||||||
|
montant: float,
|
||||||
|
rib_destinataire: str,
|
||||||
|
banque: app_commands.Choice[str]
|
||||||
|
):
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission d'utiliser cette commande.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except:
|
||||||
|
await interaction.response.send_message("❌ Erreur de lecture des comptes bancaires.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Trouver les ID à partir des RIB
|
||||||
|
emetteur_id = None
|
||||||
|
destinataire_id = None
|
||||||
|
|
||||||
|
for user_id, data in comptes.get(banque_nom, {}).items():
|
||||||
|
if data.get("rib") == rib_emetteur:
|
||||||
|
emetteur_id = user_id
|
||||||
|
if data.get("rib") == rib_destinataire:
|
||||||
|
destinataire_id = user_id
|
||||||
|
|
||||||
|
if not emetteur_id:
|
||||||
|
await interaction.response.send_message("❌ Le RIB émetteur est introuvable dans cette banque.", ephemeral=True)
|
||||||
|
return
|
||||||
|
if not destinataire_id:
|
||||||
|
await interaction.response.send_message("❌ Le RIB destinataire est introuvable dans cette banque.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier le solde
|
||||||
|
if comptes[banque_nom][emetteur_id]["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Le solde du compte émetteur est insuffisant.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Exécuter le virement
|
||||||
|
comptes[banque_nom][emetteur_id]["solde"] -= montant
|
||||||
|
comptes[banque_nom][emetteur_id]["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement manuel (par banquier)",
|
||||||
|
"source": f"Vers RIB {rib_destinataire}",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
comptes[banque_nom][destinataire_id]["solde"] += montant
|
||||||
|
comptes[banque_nom][destinataire_id]["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement reçu (par banquier)",
|
||||||
|
"source": f"RIB {rib_emetteur}",
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Virement de **{montant:.2f}€** effectué de **{rib_emetteur}** vers **{rib_destinataire}** dans **{banque_nom}**.", ephemeral=True)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementBanquier(bot))
|
||||||
122
commandes/virement_banquier_entreprise.py
Normal file
122
commandes/virement_banquier_entreprise.py
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
BANQUIER_ROLE_ID = 1360314740567576616 # ID du rôle des banquiers # ID du rôle banquier # ID du rôle des banquiers
|
||||||
|
|
||||||
|
class VirementBanquierEntreprise(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banques = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank")
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_banquier_entreprise", description="Fait un virement depuis une entreprise avec mot de passe (réservé aux banquiers).")
|
||||||
|
@app_commands.choices(banque=banques)
|
||||||
|
async def virement_banquier_entreprise(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
banque: app_commands.Choice[str],
|
||||||
|
nom_entreprise: str,
|
||||||
|
mot_de_passe: str,
|
||||||
|
rib_destinataire: str,
|
||||||
|
montant: float
|
||||||
|
):
|
||||||
|
if not any(role.id == BANQUIER_ROLE_ID for role in interaction.user.roles):
|
||||||
|
await interaction.response.send_message("❌ Vous n'avez pas la permission de faire cette commande.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
# Chargement des fichiers
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
particuliers = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur de lecture des fichiers JSON.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérification de l'entreprise
|
||||||
|
if banque_nom not in entreprises or nom_entreprise not in entreprises[banque_nom]:
|
||||||
|
await interaction.response.send_message("❌ Compte entreprise introuvable.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte_entreprise = entreprises[banque_nom][nom_entreprise]
|
||||||
|
|
||||||
|
if compte_entreprise.get("mdp") != mot_de_passe:
|
||||||
|
await interaction.response.send_message("❌ Mot de passe incorrect.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if compte_entreprise["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant pour ce virement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Recherche du compte destinataire (entreprise ou particulier)
|
||||||
|
destinataire_id = None
|
||||||
|
banque_destinataire = None
|
||||||
|
is_entreprise = False
|
||||||
|
|
||||||
|
# Recherche dans entreprises
|
||||||
|
for bq, entreprises_data in entreprises.items():
|
||||||
|
for nom, infos in entreprises_data.items():
|
||||||
|
if infos.get("rib") == rib_destinataire:
|
||||||
|
destinataire_id = nom
|
||||||
|
banque_destinataire = bq
|
||||||
|
is_entreprise = True
|
||||||
|
break
|
||||||
|
if destinataire_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Sinon, recherche dans particuliers
|
||||||
|
if not destinataire_id:
|
||||||
|
for bq, clients in particuliers.items():
|
||||||
|
for user_id, infos in clients.items():
|
||||||
|
if infos.get("rib") == rib_destinataire:
|
||||||
|
destinataire_id = user_id
|
||||||
|
banque_destinataire = bq
|
||||||
|
is_entreprise = False
|
||||||
|
break
|
||||||
|
if destinataire_id:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not destinataire_id:
|
||||||
|
await interaction.response.send_message("❌ RIB destinataire introuvable.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Retrait du montant
|
||||||
|
compte_entreprise["solde"] -= montant
|
||||||
|
compte_entreprise["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement",
|
||||||
|
"source": f"Entreprise {nom_entreprise}",
|
||||||
|
"montant": -montant,
|
||||||
|
"destinataire": rib_destinataire
|
||||||
|
})
|
||||||
|
|
||||||
|
# Créditer le destinataire
|
||||||
|
compte_cible = entreprises if is_entreprise else particuliers
|
||||||
|
compte_data = compte_cible[banque_destinataire][destinataire_id]
|
||||||
|
compte_data["solde"] += montant
|
||||||
|
compte_data["transactions"].append({
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": nom_entreprise,
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(entreprises, f, ensure_ascii=False, indent=4)
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(particuliers, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
await interaction.response.send_message(f"✅ Virement de **{montant:.2f}€** effectué depuis **{nom_entreprise}** vers **{rib_destinataire}**.")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementBanquierEntreprise(bot))
|
||||||
149
commandes/virement_entreprise.py
Normal file
149
commandes/virement_entreprise.py
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class VirementEntreprise(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_entreprise", description="Effectuer un virement depuis une entreprise vers un RIB.")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
async def virement_entreprise(
|
||||||
|
self,
|
||||||
|
interaction: discord.Interaction,
|
||||||
|
rib_entreprise: str,
|
||||||
|
montant: float,
|
||||||
|
mot_de_passe: str,
|
||||||
|
rib_destinataire: str,
|
||||||
|
banque: app_commands.Choice[str]
|
||||||
|
):
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
# Chargement des données
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_entreprises = json.load(f)
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes_bancaires = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur de lecture des données bancaires.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 🔐 Vérification de l'émetteur
|
||||||
|
entreprise_id = None
|
||||||
|
for nom_entreprise, infos in comptes_entreprises.get(banque_nom, {}).items():
|
||||||
|
if infos.get("rib") == rib_entreprise:
|
||||||
|
if infos.get("mdp") != mot_de_passe:
|
||||||
|
await interaction.response.send_message("❌ Mot de passe incorrect.", ephemeral=True)
|
||||||
|
return
|
||||||
|
entreprise_id = nom_entreprise
|
||||||
|
break
|
||||||
|
|
||||||
|
if not entreprise_id:
|
||||||
|
await interaction.response.send_message("❌ Aucun compte entreprise trouvé avec ce RIB.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte_emetteur = comptes_entreprises[banque_nom][entreprise_id]
|
||||||
|
|
||||||
|
if compte_emetteur["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 🔎 Recherche du destinataire
|
||||||
|
destinataire_data = None
|
||||||
|
destinataire_type = None
|
||||||
|
destinataire_nom = None
|
||||||
|
banque_dest = None
|
||||||
|
|
||||||
|
for banque_cible, comptes in comptes_entreprises.items():
|
||||||
|
for nom, infos in comptes.items():
|
||||||
|
if infos.get("rib") == rib_destinataire:
|
||||||
|
destinataire_data = infos
|
||||||
|
destinataire_type = "entreprise"
|
||||||
|
destinataire_nom = nom
|
||||||
|
banque_dest = banque_cible
|
||||||
|
break
|
||||||
|
if destinataire_data:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not destinataire_data:
|
||||||
|
for banque_cible, comptes in comptes_bancaires.items():
|
||||||
|
for uid, infos in comptes.items():
|
||||||
|
if infos.get("rib") == rib_destinataire:
|
||||||
|
destinataire_data = infos
|
||||||
|
destinataire_type = "particulier"
|
||||||
|
destinataire_nom = uid
|
||||||
|
banque_dest = banque_cible
|
||||||
|
break
|
||||||
|
if destinataire_data:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not destinataire_data:
|
||||||
|
await interaction.response.send_message("❌ RIB destinataire introuvable.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 📉 Débit du compte entreprise
|
||||||
|
compte_emetteur["solde"] -= montant
|
||||||
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
compte_emetteur.setdefault("transactions", []).append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": f"Vers RIB {rib_destinataire}",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# 📈 Crédit du destinataire (avec TVA si entreprise)
|
||||||
|
montant_net = montant
|
||||||
|
tva_envoyee = 0
|
||||||
|
|
||||||
|
if destinataire_type == "entreprise":
|
||||||
|
tva = destinataire_data.get("tva", 0)
|
||||||
|
tva_envoyee = round(montant * tva / 100, 2)
|
||||||
|
montant_net = montant - tva_envoyee
|
||||||
|
|
||||||
|
# Crédit TVA à l'État
|
||||||
|
if "Gouvernement" not in comptes_entreprises:
|
||||||
|
comptes_entreprises["Gouvernement"] = {}
|
||||||
|
if "GOUV" not in comptes_entreprises["Gouvernement"]:
|
||||||
|
comptes_entreprises["Gouvernement"]["GOUV"] = {
|
||||||
|
"rib": "00000 00000 00000000000 00",
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
|
||||||
|
comptes_entreprises["Gouvernement"]["GOUV"]["solde"] += tva_envoyee
|
||||||
|
comptes_entreprises["Gouvernement"]["GOUV"]["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": entreprise_id,
|
||||||
|
"montant": tva_envoyee
|
||||||
|
})
|
||||||
|
|
||||||
|
destinataire_data["solde"] += montant_net
|
||||||
|
destinataire_data.setdefault("transactions", []).append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": entreprise_id,
|
||||||
|
"montant": montant_net
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegardes
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_entreprises, f, ensure_ascii=False, indent=4)
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes_bancaires, f, ensure_ascii=False, indent=4)
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Virement effectué avec succès.{' TVA de ' + str(tva_envoyee) + '€ envoyée au Gouvernement.' if tva_envoyee else ''}",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementEntreprise(bot))
|
||||||
97
commandes/virement_fbm.py
Normal file
97
commandes/virement_fbm.py
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class VirementFBM(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_fbm", description="Fait un virement au compte indépendant FBM.")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(montant="Montant à transférer", banque="Banque à utiliser")
|
||||||
|
async def virement_fbm(self, interaction: discord.Interaction, montant: float, banque: app_commands.Choice[str]):
|
||||||
|
auteur_id = str(interaction.user.id)
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message("❌ Le montant doit être supérieur à 0.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Charger les fichiers
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la lecture des comptes bancaires.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
except:
|
||||||
|
entreprises = {}
|
||||||
|
|
||||||
|
# Vérification du compte de l'utilisateur
|
||||||
|
if banque_nom not in comptes or auteur_id not in comptes[banque_nom]:
|
||||||
|
await interaction.response.send_message("❌ Tu n'as pas de compte dans cette banque.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte = comptes[banque_nom][auteur_id]
|
||||||
|
if compte["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant pour effectuer le virement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Initialiser FBM si nécessaire
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Mise à jour des soldes
|
||||||
|
compte["solde"] -= montant
|
||||||
|
entreprises["fbm"]["FBM"]["solde"] += montant
|
||||||
|
|
||||||
|
# Historique utilisateur
|
||||||
|
compte["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": f"Vers FBM",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Historique FBM
|
||||||
|
entreprises["fbm"]["FBM"]["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": interaction.user.name,
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
# Confirmation
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Virement de **{montant:.2f}€** envoyé au compte **FBM** depuis **{banque_nom}**.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementFBM(bot))
|
||||||
86
commandes/virement_gouvernement.py
Normal file
86
commandes/virement_gouvernement.py
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class VirementGouvernement(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_gouvernement", description="Effectue un virement au Gouvernement.")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(montant="Le montant à envoyer", banque="Banque à utiliser pour le virement")
|
||||||
|
async def virement_gouvernement(self, interaction: discord.Interaction, montant: float, banque: app_commands.Choice[str]):
|
||||||
|
auteur_id = str(interaction.user.id)
|
||||||
|
banque_source = banque.value
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message("❌ Le montant doit être supérieur à zéro.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Charger les fichiers
|
||||||
|
try:
|
||||||
|
with open('comptes_bancaires.json', 'r', encoding='utf-8') as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
with open('comptes_entreprises.json', 'r', encoding='utf-8') as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
await interaction.response.send_message(f"❌ Erreur de lecture des fichiers : {e}", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
if banque_source not in comptes or auteur_id not in comptes[banque_source]:
|
||||||
|
await interaction.response.send_message(f"❌ Tu n'as pas de compte dans la banque **{banque_source}**.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte_user = comptes[banque_source][auteur_id]
|
||||||
|
if compte_user["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant pour effectuer ce virement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Vérifier ou créer le compte Gouvernement
|
||||||
|
if "Gouvernement" not in entreprises:
|
||||||
|
entreprises["Gouvernement"] = {}
|
||||||
|
if "GOUV" not in entreprises["Gouvernement"]:
|
||||||
|
entreprises["Gouvernement"]["GOUV"] = {
|
||||||
|
"rib": "00000 00000 00000000000 00",
|
||||||
|
"solde": 0.0,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
|
||||||
|
# Effectuer le virement
|
||||||
|
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
|
||||||
|
compte_user["solde"] -= montant
|
||||||
|
entreprises["Gouvernement"]["GOUV"]["solde"] += montant
|
||||||
|
|
||||||
|
compte_user["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": f"Vers Gouvernement",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
entreprises["Gouvernement"]["GOUV"]["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": interaction.user.name,
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
with open('comptes_bancaires.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(comptes, f, indent=4, ensure_ascii=False)
|
||||||
|
with open('comptes_entreprises.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Virement de **{montant:.2f}€** envoyé au Gouvernement avec succès.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementGouvernement(bot))
|
||||||
93
commandes/virement_ursaff.py
Normal file
93
commandes/virement_ursaff.py
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class VirementUrssaf(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
banque_choices = [
|
||||||
|
app_commands.Choice(name="Victoria's Credit Bank", value="Victoria's Credit Bank"),
|
||||||
|
app_commands.Choice(name="NGC Bank", value="NGC Bank"),
|
||||||
|
]
|
||||||
|
|
||||||
|
@app_commands.command(name="virement_ursaff", description="Fait un virement vers le compte indépendant URSAFF.")
|
||||||
|
@app_commands.choices(banque=banque_choices)
|
||||||
|
@app_commands.describe(montant="Montant à transférer", banque="Banque à utiliser")
|
||||||
|
async def virement_ursaff(self, interaction: discord.Interaction, montant: float, banque: app_commands.Choice[str]):
|
||||||
|
auteur_id = str(interaction.user.id)
|
||||||
|
banque_nom = banque.value
|
||||||
|
|
||||||
|
if montant <= 0:
|
||||||
|
await interaction.response.send_message("❌ Le montant doit être supérieur à 0.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_bancaires.json", "r", encoding="utf-8") as f:
|
||||||
|
comptes = json.load(f)
|
||||||
|
except Exception:
|
||||||
|
await interaction.response.send_message("❌ Erreur lors de la lecture des comptes bancaires.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open("comptes_entreprises.json", "r", encoding="utf-8") as f:
|
||||||
|
entreprises = json.load(f)
|
||||||
|
except:
|
||||||
|
entreprises = {}
|
||||||
|
|
||||||
|
if banque_nom not in comptes or auteur_id not in comptes[banque_nom]:
|
||||||
|
await interaction.response.send_message("❌ Tu n'as pas de compte dans cette banque.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
compte = comptes[banque_nom][auteur_id]
|
||||||
|
if compte["solde"] < montant:
|
||||||
|
await interaction.response.send_message("❌ Solde insuffisant pour effectuer le virement.", ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Initialiser URSAFF si nécessaire
|
||||||
|
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")
|
||||||
|
|
||||||
|
# Mise à jour des soldes
|
||||||
|
compte["solde"] -= montant
|
||||||
|
entreprises["ursaff"]["URSAFF"]["solde"] += montant
|
||||||
|
|
||||||
|
# Historique utilisateur
|
||||||
|
compte["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement",
|
||||||
|
"source": "Vers URSAFF",
|
||||||
|
"montant": -montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Historique URSAFF
|
||||||
|
entreprises["ursaff"]["URSAFF"]["transactions"].append({
|
||||||
|
"date": now,
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": interaction.user.name,
|
||||||
|
"montant": montant
|
||||||
|
})
|
||||||
|
|
||||||
|
# Sauvegarde
|
||||||
|
with open("comptes_bancaires.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(comptes, f, indent=4, ensure_ascii=False)
|
||||||
|
with open("comptes_entreprises.json", "w", encoding="utf-8") as f:
|
||||||
|
json.dump(entreprises, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
await interaction.response.send_message(
|
||||||
|
f"✅ Virement de **{montant:.2f}€** envoyé au compte **URSAFF** depuis **{banque_nom}**.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VirementUrssaf(bot))
|
||||||
65
commandes/voir_carte_identite.py
Normal file
65
commandes/voir_carte_identite.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import discord
|
||||||
|
from discord import app_commands
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.data_manager import DataManager
|
||||||
|
from utils.card_generator import CardGenerator
|
||||||
|
|
||||||
|
card_generator = CardGenerator()
|
||||||
|
|
||||||
|
class VoirIdentite(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@app_commands.command(name="voir_carte_identite", description="Afficher votre carte d'identité ou celle d'un autre utilisateur")
|
||||||
|
async def voir_carte_identite(self, interaction: discord.Interaction, utilisateur: discord.Member = None):
|
||||||
|
"""Affiche la carte d'identité d'un utilisateur"""
|
||||||
|
|
||||||
|
# Remplacer par l'ID de ton rôle gouvernement
|
||||||
|
GOUVERNEMENT_ROLE_ID = 1360236421872484403
|
||||||
|
|
||||||
|
target_user = utilisateur or interaction.user
|
||||||
|
|
||||||
|
# 🔒 Vérification si l'utilisateur peut voir la carte d'un autre
|
||||||
|
if utilisateur and utilisateur != interaction.user:
|
||||||
|
gouvernement_role = interaction.guild.get_role(GOUVERNEMENT_ROLE_ID)
|
||||||
|
if gouvernement_role not in interaction.user.roles:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"🚫 Vous n'avez pas l'autorisation de voir la carte d'identité d'un autre utilisateur.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = str(target_user.id)
|
||||||
|
|
||||||
|
# 🧠 Recréer un DataManager à chaque commande
|
||||||
|
data_manager = DataManager()
|
||||||
|
|
||||||
|
# 🔎 Récupération des données
|
||||||
|
identity_data = data_manager.identities.get(user_id)
|
||||||
|
|
||||||
|
if identity_data is None:
|
||||||
|
await interaction.response.send_message(
|
||||||
|
"❌ Cet utilisateur ne possède pas de carte d'identité.",
|
||||||
|
ephemeral=True
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 🛡️ Vérification que l'identité est complète
|
||||||
|
if "date_expiration" not in identity_data:
|
||||||
|
identity_data["date_expiration"] = "Non spécifiée"
|
||||||
|
|
||||||
|
# 🖼️ Génération de l'image de la carte
|
||||||
|
card_buffer = await card_generator.create_identity_card(target_user, identity_data)
|
||||||
|
|
||||||
|
# 📩 Envoi du fichier + embed
|
||||||
|
file = discord.File(card_buffer, filename="carte_identite.png")
|
||||||
|
embed = discord.Embed(
|
||||||
|
title=f"🪪 Carte d'identité de {target_user.display_name}",
|
||||||
|
color=0x2ecc71
|
||||||
|
)
|
||||||
|
embed.set_image(url="attachment://carte_identite.png")
|
||||||
|
|
||||||
|
await interaction.response.send_message(file=file, embed=embed, ephemeral=False)
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(VoirIdentite(bot))
|
||||||
30
commandes/welcome_message.py
Normal file
30
commandes/welcome_message.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
|
||||||
|
class WelcomeMessage(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
try:
|
||||||
|
# ID du salon discussion
|
||||||
|
welcome_channel_id = 1278483527783944242
|
||||||
|
welcome_channel = member.guild.get_channel(welcome_channel_id)
|
||||||
|
|
||||||
|
if welcome_channel:
|
||||||
|
welcome_message = (
|
||||||
|
f"## BIENVENUE <:panda_welcome:1297298999849517056> !\n\n"
|
||||||
|
f"> **L'équipe staff te souhaite la bienvenue sur Victoria's Vice {member.mention} !**\n\n"
|
||||||
|
f"> Pour ta candidature <:arrow_1:1297491509201080362> <#1278477608392196176> / <#1278477152215371806> \n\n"
|
||||||
|
f"> Si tu as des questions <:arrow_1:1297491509201080362> <#1279037583820718120>\n\n"
|
||||||
|
f"*> Bien cordialement, L'équipe staff de Victoria's Vice*"
|
||||||
|
)
|
||||||
|
|
||||||
|
await welcome_channel.send(welcome_message)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de l'envoi du message de bienvenue: {e}")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(WelcomeMessage(bot))
|
||||||
2111
comptes_bancaires.json
Normal file
2111
comptes_bancaires.json
Normal file
File diff suppressed because it is too large
Load diff
492
comptes_entreprises.json
Normal file
492
comptes_entreprises.json
Normal file
|
|
@ -0,0 +1,492 @@
|
||||||
|
{
|
||||||
|
"ngc_bank": {},
|
||||||
|
"Gouvernement": {
|
||||||
|
"GOUV": {
|
||||||
|
"rib": "00000 00000 00000000000 00",
|
||||||
|
"solde": 10085849.01,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "26/04/2025 15:55:13",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "534003230435442690",
|
||||||
|
"montant": 0.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "27/04/2025 14:01:32",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "534003230435442690",
|
||||||
|
"montant": 0.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 08:53:44",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1108087282692522105",
|
||||||
|
"montant": 8.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 10:42:38",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1263573205268828231",
|
||||||
|
"montant": 7.6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 15:37:27",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1244182195300601920",
|
||||||
|
"montant": 8.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "01/05/2025 08:56:08",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "914118793918312480",
|
||||||
|
"montant": 5.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "01/05/2025 13:08:59",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1321863072242995332",
|
||||||
|
"montant": 300.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "04/05/2025 16:51:20",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "971446412690722826",
|
||||||
|
"montant": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:09:39",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "353942721997832195",
|
||||||
|
"montant": 400.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:23:40",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "828239898975666216",
|
||||||
|
"montant": 10.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:24:07",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "534003230435442690",
|
||||||
|
"montant": 100.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/05/2025 10:49:55",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1263573205268828231",
|
||||||
|
"montant": 8.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/05/2025 18:19:03",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1263573205268828231",
|
||||||
|
"montant": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "07/05/2025 19:45:13",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "gameurpro12",
|
||||||
|
"montant": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 17:23:13",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1200313720195264613",
|
||||||
|
"montant": 7.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 18:31:46",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1263573205268828231",
|
||||||
|
"montant": 7.6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 19:10:15",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "534003230435442690",
|
||||||
|
"montant": 100.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 19:15:25",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "534003230435442690",
|
||||||
|
"montant": 100.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 13:06:24",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1321863072242995332",
|
||||||
|
"montant": 330.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 14:49:46",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1072112886509473792",
|
||||||
|
"montant": 14000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 14:50:02",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "501080933282218005",
|
||||||
|
"montant": 2400.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "12/05/2025 18:35:06",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1263573205268828231",
|
||||||
|
"montant": 7.6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:17:43",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1126995714552111215",
|
||||||
|
"montant": 2400.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:34:58",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "376796341071773706",
|
||||||
|
"montant": 2400.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:34:58",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "376796341071773706",
|
||||||
|
"montant": 2400.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "19/05/2025 11:55:01",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1200313720195264613",
|
||||||
|
"montant": 7.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "29/05/2025 13:51:53",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "376796341071773706",
|
||||||
|
"montant": 6000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "29/05/2025 15:16:42",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "353942721997832195",
|
||||||
|
"montant": 27.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/06/2025 20:09:01",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "353942721997832195",
|
||||||
|
"montant": 42.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "20/06/2025 19:06:14",
|
||||||
|
"type": "TVA reçue",
|
||||||
|
"source": "1244372888702816458",
|
||||||
|
"montant": 2000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "29/06/2025 12:31:17",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 15869.0,
|
||||||
|
"emetteur": 353942721997832195,
|
||||||
|
"destinataire": "GOUV"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"NGC Bank": {
|
||||||
|
"Journal en onde": {
|
||||||
|
"rib": "93884 11674 79519 40904",
|
||||||
|
"solde": 6031.0,
|
||||||
|
"mdp": "E96zM0Jj",
|
||||||
|
"tva": 2,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:23:40",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "docteur_w.d_axolotl",
|
||||||
|
"montant": 490.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:24:07",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 4900.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "Journal en onde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/05/2025 10:49:55",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "e.93130",
|
||||||
|
"montant": 392.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/05/2025 18:19:03",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "e.93130",
|
||||||
|
"montant": 49.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Milano Motors": {
|
||||||
|
"rib": "79307 68952 45977 60249",
|
||||||
|
"solde": 126400.0,
|
||||||
|
"mdp": "9YcjNvud",
|
||||||
|
"tva": 20,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 14:49:46",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "lagrenouillebeka",
|
||||||
|
"montant": 56000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 14:50:02",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "justeme",
|
||||||
|
"montant": 9600.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:17:43",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "jl_wesley.f1",
|
||||||
|
"montant": 9600.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:34:58",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "bitehoven",
|
||||||
|
"montant": 9600.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "18/05/2025 15:34:58",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "bitehoven",
|
||||||
|
"montant": 9600.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "29/05/2025 13:51:53",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "bitehoven",
|
||||||
|
"montant": 24000.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "20/06/2025 19:06:14",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "oghacker1337",
|
||||||
|
"montant": 8000.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Sicilia mia": {
|
||||||
|
"rib": "19440 99822 26785 73807",
|
||||||
|
"solde": 108.0,
|
||||||
|
"mdp": "8sqmuoz4",
|
||||||
|
"tva": 20,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "29/05/2025 15:16:42",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "mg_studios_",
|
||||||
|
"montant": 108.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Domaine de vins": {
|
||||||
|
"rib": "96241 34733 44548 77079",
|
||||||
|
"solde": 1768.0,
|
||||||
|
"mdp": "hIJj81ci",
|
||||||
|
"tva": 20,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "05/05/2025 16:09:39",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "mg_studios_",
|
||||||
|
"montant": 1600.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "06/06/2025 20:09:01",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "mg_studios_",
|
||||||
|
"montant": 168.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Umbrella Assurances": {
|
||||||
|
"rib": "54201 75079 71658 35659",
|
||||||
|
"solde": 2969.4,
|
||||||
|
"mdp": "KDRQGd3R",
|
||||||
|
"tva": 2,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 08:53:44",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "tricks212_zz",
|
||||||
|
"montant": 416.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 10:42:38",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "e.93130",
|
||||||
|
"montant": 372.4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "28/04/2025 15:37:27",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "hvk_pompotfraicz",
|
||||||
|
"montant": 416.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "01/05/2025 08:56:08",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "neyzizz",
|
||||||
|
"montant": 254.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 17:23:13",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "agent_chaos_officiel",
|
||||||
|
"montant": 382.2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 18:31:46",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "e.93130",
|
||||||
|
"montant": 372.4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "12/05/2025 18:35:06",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "e.93130",
|
||||||
|
"montant": 372.4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "19/05/2025 11:55:01",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "agent_chaos_officiel",
|
||||||
|
"montant": 382.2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Auto école": {
|
||||||
|
"rib": "11940 73588 95258 04768",
|
||||||
|
"solde": 15971.0,
|
||||||
|
"mdp": "zcEKe45Y",
|
||||||
|
"tva": 20,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "26/04/2025 15:55:13",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "nixfix06",
|
||||||
|
"montant": 0.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "27/04/2025 14:01:32",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "nixfix06",
|
||||||
|
"montant": 0.8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "01/05/2025 13:08:59",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "sz94d",
|
||||||
|
"montant": 1200.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "11/05/2025 13:06:24",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "sz94d",
|
||||||
|
"montant": 1320.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Sicilia Mia": {
|
||||||
|
"rib": "68229 13765 90163 35585",
|
||||||
|
"solde": 1907.09,
|
||||||
|
"mdp": "6uTORm3r",
|
||||||
|
"tva": 10,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "04/05/2025 16:51:20",
|
||||||
|
"type": "Virement reçu",
|
||||||
|
"source": "gameurpro12",
|
||||||
|
"montant": 0.09000000000000001
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"NGC Bank": {
|
||||||
|
"rib": "15156 38436 35920 54357",
|
||||||
|
"solde": 1040900.0,
|
||||||
|
"mdp": "nxDcskg0",
|
||||||
|
"tva": 2,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 19:10:15",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 4900.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "NGC Bank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 19:15:25",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 4900.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "NGC Bank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "09/05/2025 19:15:51",
|
||||||
|
"type": "Retrait",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": -4900.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "NGC Bank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "24/05/2025 13:44:09",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 1000000.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "NGC Bank"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "04/06/2025 16:30:19",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 36000.0,
|
||||||
|
"emetteur": 534003230435442690,
|
||||||
|
"destinataire": "NGC Bank"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Agence immobilière.": {
|
||||||
|
"rib": "54044 32109 51269 69180",
|
||||||
|
"solde": 108000.0,
|
||||||
|
"mdp": "tCH7QK7G",
|
||||||
|
"tva": 20,
|
||||||
|
"transactions": [
|
||||||
|
{
|
||||||
|
"date": "03/07/2025 22:35:20",
|
||||||
|
"type": "Dépôt",
|
||||||
|
"source": "Banque",
|
||||||
|
"montant": 108000.0,
|
||||||
|
"emetteur": 353942721997832195,
|
||||||
|
"destinataire": "Agence immobilière."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"La Concordia": {
|
||||||
|
"rib": "09860 71327 12935 47361",
|
||||||
|
"solde": 0,
|
||||||
|
"mdp": "3vo66Wqu",
|
||||||
|
"tva": 10,
|
||||||
|
"transactions": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
counting_data.json
Normal file
6
counting_data.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"1390076581892063354": {
|
||||||
|
"current": 4,
|
||||||
|
"last_user": 1200313720195264613
|
||||||
|
}
|
||||||
|
}
|
||||||
3
id_compteur.json
Normal file
3
id_compteur.json
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"dernier_id": 152
|
||||||
|
}
|
||||||
BIN
ressources/assets/CIITAL.png
Normal file
BIN
ressources/assets/CIITAL.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
174
ressources/assets/Code_HTML_Vice_TMV2.html
Normal file
174
ressources/assets/Code_HTML_Vice_TMV2.html
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
<div className="w-[1920px] h-[1080px] relative bg-white overflow-hidden">
|
||||||
|
<div className="w-80 h-[1080px] left-0 top-0 absolute bg-gray-700 inline-flex flex-col justify-between items-start">
|
||||||
|
<div className="self-stretch h-28 px-3.5 inline-flex justify-between items-center">
|
||||||
|
<div className="w-40 h-7 flex justify-start items-center">
|
||||||
|
<div className="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div className="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-white" />
|
||||||
|
</div>
|
||||||
|
<div className="w-28 h-7 text-center justify-center text-white text-xl font-normal font-['Inter']">Utilisateur</div>
|
||||||
|
<div className="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div className="w-4 h-2 left-[11.72px] top-[15.86px] absolute outline outline-2 outline-offset-[-1px] outline-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-10 h-10 relative origin-top-left rotate-180 overflow-hidden">
|
||||||
|
<div className="w-6 h-7 left-[9.19px] top-[7.44px] absolute outline outline-2 outline-offset-[-1px] outline-white" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="self-stretch h-[507px] px-4 py-2.5 inline-flex justify-start items-start gap-3.5 flex-wrap content-start">
|
||||||
|
<div className="w-80 justify-center text-white text-xl font-normal font-['Inter']">Employer :</div>
|
||||||
|
<div className="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div className="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div className="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500" />
|
||||||
|
</div>
|
||||||
|
<div className="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div className="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div className="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500" />
|
||||||
|
</div>
|
||||||
|
<div className="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div className="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div className="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500" />
|
||||||
|
</div>
|
||||||
|
<div className="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div className="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div className="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500" />
|
||||||
|
</div>
|
||||||
|
<div className="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="self-stretch h-80 p-2.5 bg-violet-500 rounded-tl-[20px] rounded-tr-[20px] inline-flex justify-center items-start gap-2.5 flex-wrap content-start">
|
||||||
|
<div className="w-80 h-9 inline-flex flex-col justify-between items-start">
|
||||||
|
<div className="justify-center text-white text-xl font-normal font-['Inter']">Suggestion :</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-[1590px] h-28 px-2.5 left-[330px] top-0 absolute bg-slate-500/20 inline-flex justify-between items-center">
|
||||||
|
<div className="flex justify-start items-center gap-3.5">
|
||||||
|
<div className="w-20 h-20 relative overflow-hidden">
|
||||||
|
<div className="w-10 h-9 left-[19.79px] top-[20px] absolute bg-black" />
|
||||||
|
</div>
|
||||||
|
<div className="w-80 h-10 text-center justify-center text-black text-2xl font-normal font-['Inter']">Nom de l’entreprise</div>
|
||||||
|
</div>
|
||||||
|
<div className="px-12 flex justify-start items-center gap-10">
|
||||||
|
<div className="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div className="w-8 h-8 left-[3.32px] top-[3.28px] absolute bg-black" />
|
||||||
|
</div>
|
||||||
|
<div className="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div className="w-8 h-8 left-[3.33px] top-[3.33px] absolute bg-black" />
|
||||||
|
</div>
|
||||||
|
<div className="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div className="w-8 h-6 left-[3.33px] top-[8.33px] absolute bg-black" />
|
||||||
|
</div>
|
||||||
|
<div className="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div className="w-8 h-9 left-[3.33px] top-[2.99px] absolute bg-black" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-[1590px] h-[970px] p-14 left-[330px] top-[110px] absolute inline-flex justify-start items-start gap-20 flex-wrap content-start">
|
||||||
|
<div className="w-[1442px] flex justify-start items-center gap-2.5">
|
||||||
|
<div className="text-center justify-center text-black text-3xl font-normal font-['Inter']">Information :</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
<div className="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
<div className="w-40 h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
<div className="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
<div className="w-36 h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
<div className="w-[535px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]" />
|
||||||
|
</div>
|
||||||
|
<div className="w-5 h-5 left-[290px] top-[756px] absolute bg-white" />
|
||||||
|
<div className="p-2.5 left-[1641px] top-[1016px] absolute inline-flex justify-center items-center gap-2.5">
|
||||||
|
<div className="text-center justify-start text-black/20 text-4xl font-normal font-['Inter']">Victoria’s Vice™</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-[1920px] h-[1080px] relative bg-white overflow-hidden">
|
||||||
|
<div class="w-80 h-[1080px] left-0 top-0 absolute bg-gray-700 inline-flex flex-col justify-between items-start">
|
||||||
|
<div class="self-stretch h-28 px-3.5 inline-flex justify-between items-center">
|
||||||
|
<div class="w-40 h-7 flex justify-start items-center">
|
||||||
|
<div class="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div class="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-white"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-28 h-7 text-center justify-center text-white text-xl font-normal font-['Inter']">Utilisateur</div>
|
||||||
|
<div class="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div class="w-4 h-2 left-[11.72px] top-[15.86px] absolute outline outline-2 outline-offset-[-1px] outline-white"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-10 h-10 relative origin-top-left rotate-180 overflow-hidden">
|
||||||
|
<div class="w-6 h-7 left-[9.19px] top-[7.44px] absolute outline outline-2 outline-offset-[-1px] outline-white"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="self-stretch h-[507px] px-4 py-2.5 inline-flex justify-start items-start gap-3.5 flex-wrap content-start">
|
||||||
|
<div class="w-80 justify-center text-white text-xl font-normal font-['Inter']">Employer :</div>
|
||||||
|
<div class="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div class="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div class="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500"></div>
|
||||||
|
</div>
|
||||||
|
<div class="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div class="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div class="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500"></div>
|
||||||
|
</div>
|
||||||
|
<div class="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-72 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div class="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div class="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500"></div>
|
||||||
|
</div>
|
||||||
|
<div class="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 h-16 px-[5px] bg-slate-800 rounded-[10px] flex justify-start items-center gap-2.5">
|
||||||
|
<div class="w-12 h-12 relative overflow-hidden">
|
||||||
|
<div class="w-11 h-11 left-[3.20px] top-[3.20px] absolute bg-violet-500"></div>
|
||||||
|
</div>
|
||||||
|
<div class="justify-center text-white text-xl font-normal font-['Inter']">Nom du joueur</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="self-stretch h-80 p-2.5 bg-violet-500 rounded-tl-[20px] rounded-tr-[20px] inline-flex justify-center items-start gap-2.5 flex-wrap content-start">
|
||||||
|
<div class="w-80 h-9 inline-flex flex-col justify-between items-start">
|
||||||
|
<div class="justify-center text-white text-xl font-normal font-['Inter']">Suggestion :</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-[1590px] h-28 px-2.5 left-[330px] top-0 absolute bg-slate-500/20 inline-flex justify-between items-center">
|
||||||
|
<div class="flex justify-start items-center gap-3.5">
|
||||||
|
<div class="w-20 h-20 relative overflow-hidden">
|
||||||
|
<div class="w-10 h-9 left-[19.79px] top-[20px] absolute bg-black"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-80 h-10 text-center justify-center text-black text-2xl font-normal font-['Inter']">Nom de l’entreprise</div>
|
||||||
|
</div>
|
||||||
|
<div class="px-12 flex justify-start items-center gap-10">
|
||||||
|
<div class="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div class="w-8 h-8 left-[3.32px] top-[3.28px] absolute bg-black"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div class="w-8 h-8 left-[3.33px] top-[3.33px] absolute bg-black"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div class="w-8 h-6 left-[3.33px] top-[8.33px] absolute bg-black"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-10 h-10 relative overflow-hidden">
|
||||||
|
<div class="w-8 h-9 left-[3.33px] top-[2.99px] absolute bg-black"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-[1590px] h-[970px] p-14 left-[330px] top-[110px] absolute inline-flex justify-start items-start gap-20 flex-wrap content-start">
|
||||||
|
<div class="w-[1442px] flex justify-start items-center gap-2.5">
|
||||||
|
<div class="text-center justify-center text-black text-3xl font-normal font-['Inter']">Information :</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
<div class="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
<div class="w-40 h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
<div class="w-[530px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
<div class="w-36 h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
<div class="w-[535px] h-72 bg-white rounded-[20px] shadow-[0px_4px_43.79999923706055px_0px_rgba(0,0,0,0.25)]"></div>
|
||||||
|
</div>
|
||||||
|
<div class="w-5 h-5 left-[290px] top-[756px] absolute bg-white"></div>
|
||||||
|
<div class="p-2.5 left-[1641px] top-[1016px] absolute inline-flex justify-center items-center gap-2.5">
|
||||||
|
<div class="text-center justify-start text-black/20 text-4xl font-normal font-['Inter']">Victoria’s Vice™</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
BIN
ressources/assets/Victorias_ViceTMV2.png
Normal file
BIN
ressources/assets/Victorias_ViceTMV2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
BIN
ressources/assets/template.png
Normal file
BIN
ressources/assets/template.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 KiB |
1
ressources/banque_data.json
Normal file
1
ressources/banque_data.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
500
ressources/data.json
Normal file
500
ressources/data.json
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
{
|
||||||
|
"identities": {
|
||||||
|
"353942721997832195": {
|
||||||
|
"nom": "RICCI",
|
||||||
|
"prenom": "Aldo",
|
||||||
|
"date_naissance": "22/05/1967",
|
||||||
|
"lieu_naissance": "Victoria's Vice",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "01/12/2026"
|
||||||
|
},
|
||||||
|
"1096453463849828362": {
|
||||||
|
"nom": "DE MONTROSE",
|
||||||
|
"prenom": "Warren",
|
||||||
|
"date_naissance": "04/04/1991",
|
||||||
|
"lieu_naissance": "Londres",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "20/06/2027"
|
||||||
|
},
|
||||||
|
"914118793918312480": {
|
||||||
|
"nom": "CORREA",
|
||||||
|
"prenom": "Mattia",
|
||||||
|
"date_naissance": "28/04/1986",
|
||||||
|
"lieu_naissance": "Milan",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "01/12/2026"
|
||||||
|
},
|
||||||
|
"768915179995004988": {
|
||||||
|
"nom": "KASHMIRI",
|
||||||
|
"prenom": "Khalid",
|
||||||
|
"date_naissance": "19/07/1988",
|
||||||
|
"lieu_naissance": "Algérie",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"828923448453103637": {
|
||||||
|
"nom": "NORLOCK",
|
||||||
|
"prenom": "Bucky",
|
||||||
|
"date_naissance": "04/06/1999",
|
||||||
|
"lieu_naissance": "Venise",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "24/06/2027"
|
||||||
|
},
|
||||||
|
"971446412690722826": {
|
||||||
|
"nom": "PAS GENTIL",
|
||||||
|
"prenom": "Pas gentil",
|
||||||
|
"date_naissance": "04/04/2025",
|
||||||
|
"lieu_naissance": "Pas Gentil",
|
||||||
|
"sexe": "Autre",
|
||||||
|
"date_expiration": "11/04/2027"
|
||||||
|
},
|
||||||
|
"1324439906046574693": {
|
||||||
|
"nom": "DZQDQDZ",
|
||||||
|
"prenom": "Dzqdqzdz",
|
||||||
|
"date_naissance": "01/01/2000",
|
||||||
|
"lieu_naissance": "dzqd",
|
||||||
|
"sexe": "Femme",
|
||||||
|
"date_expiration": "12/03/2027"
|
||||||
|
},
|
||||||
|
"1200313720195264613": {
|
||||||
|
"nom": "HAMILTON",
|
||||||
|
"prenom": "Leonardo",
|
||||||
|
"date_naissance": "09/01/1985",
|
||||||
|
"lieu_naissance": "Canada Québec",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "01/05/2027"
|
||||||
|
},
|
||||||
|
"942073262333112351": {
|
||||||
|
"nom": "MURDOCK",
|
||||||
|
"prenom": "Matthew",
|
||||||
|
"date_naissance": "12/03/1990",
|
||||||
|
"lieu_naissance": "Hells Kitchen",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "11/04/2027"
|
||||||
|
},
|
||||||
|
"828239898975666216": {
|
||||||
|
"nom": "VINDERTECH",
|
||||||
|
"prenom": "Félix",
|
||||||
|
"date_naissance": "11/05/1990",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "11/04/2027"
|
||||||
|
},
|
||||||
|
"836606840254496788": {
|
||||||
|
"nom": "MARECHAL",
|
||||||
|
"prenom": "Charles",
|
||||||
|
"date_naissance": "08/01/1995",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "11/04/2027"
|
||||||
|
},
|
||||||
|
"1126995714552111215": {
|
||||||
|
"nom": "FIGLINI",
|
||||||
|
"prenom": "José",
|
||||||
|
"date_naissance": "28/12/2001",
|
||||||
|
"lieu_naissance": "Victoria's Vice",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "11/04/2027"
|
||||||
|
},
|
||||||
|
"1108087282692522105": {
|
||||||
|
"nom": "JULES",
|
||||||
|
"prenom": "Delcourt",
|
||||||
|
"date_naissance": "18/04/2004",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/06/2027"
|
||||||
|
},
|
||||||
|
"1351957361333370932": {
|
||||||
|
"nom": "DURAND",
|
||||||
|
"prenom": "Mehdi",
|
||||||
|
"date_naissance": "20/11/2002",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"936337534760386580": {
|
||||||
|
"nom": "HAKERMAN",
|
||||||
|
"prenom": "Malo",
|
||||||
|
"date_naissance": "25/11/2000",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"449424004663607307": {
|
||||||
|
"nom": "DOLOS",
|
||||||
|
"prenom": "Arturo",
|
||||||
|
"date_naissance": "01/04/2001",
|
||||||
|
"lieu_naissance": "Salina",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"881841899634323456": {
|
||||||
|
"nom": "LAVIBE",
|
||||||
|
"prenom": "Rachid",
|
||||||
|
"date_naissance": "28/03/2001",
|
||||||
|
"lieu_naissance": "Portugal",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"946068504023556186": {
|
||||||
|
"nom": "MARSTON",
|
||||||
|
"prenom": "John",
|
||||||
|
"date_naissance": "09/10/1974",
|
||||||
|
"lieu_naissance": "Montreal",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"1203485889251115089": {
|
||||||
|
"nom": "CARTER",
|
||||||
|
"prenom": "Ethan",
|
||||||
|
"date_naissance": "16/11/2000",
|
||||||
|
"lieu_naissance": "Midnight city",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"1324527110425018438": {
|
||||||
|
"nom": "DEMARCHI",
|
||||||
|
"prenom": "Stella",
|
||||||
|
"date_naissance": "18/08/2001",
|
||||||
|
"lieu_naissance": "Milan",
|
||||||
|
"sexe": "Femme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"901856948184559676": {
|
||||||
|
"nom": "PILISO",
|
||||||
|
"prenom": "Dario",
|
||||||
|
"date_naissance": "25/02/1980",
|
||||||
|
"lieu_naissance": "Milan",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "13/04/2027"
|
||||||
|
},
|
||||||
|
"906574786308734986": {
|
||||||
|
"nom": "FERRARI",
|
||||||
|
"prenom": "Pedro",
|
||||||
|
"date_naissance": "28/02/2000",
|
||||||
|
"lieu_naissance": "Rome",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "10/05/2027"
|
||||||
|
},
|
||||||
|
"1311384140905709578": {
|
||||||
|
"nom": "LOPEZ",
|
||||||
|
"prenom": "Kayz",
|
||||||
|
"date_naissance": "04/07/2000",
|
||||||
|
"lieu_naissance": "Venise",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "22/06/2027"
|
||||||
|
},
|
||||||
|
"501080933282218005": {
|
||||||
|
"nom": "GIORGINO",
|
||||||
|
"prenom": "Antoine",
|
||||||
|
"date_naissance": "17/06/2004",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "21/04/2027"
|
||||||
|
},
|
||||||
|
"826145675506745395": {
|
||||||
|
"nom": "GALLERY",
|
||||||
|
"prenom": "Valentino",
|
||||||
|
"date_naissance": "19/06/1994",
|
||||||
|
"lieu_naissance": "Nice",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "21/04/2027"
|
||||||
|
},
|
||||||
|
"534003230435442690": {
|
||||||
|
"nom": "DI REGIA",
|
||||||
|
"prenom": "Salvatore",
|
||||||
|
"date_naissance": "09/11/1990",
|
||||||
|
"lieu_naissance": "Rome",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "21/04/2027"
|
||||||
|
},
|
||||||
|
"1304410873015832596": {
|
||||||
|
"nom": "EL MASRI",
|
||||||
|
"prenom": "Rayan",
|
||||||
|
"date_naissance": "21/10/1999",
|
||||||
|
"lieu_naissance": "Algerie",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/04/2027"
|
||||||
|
},
|
||||||
|
"1321933664535183395": {
|
||||||
|
"nom": "MICKALSON",
|
||||||
|
"prenom": "Jackson",
|
||||||
|
"date_naissance": "08/02/1995",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/04/2027"
|
||||||
|
},
|
||||||
|
"1267066015238586452": {
|
||||||
|
"nom": "BLOSSOM",
|
||||||
|
"prenom": "Kira",
|
||||||
|
"date_naissance": "23/02/2003",
|
||||||
|
"lieu_naissance": "Miami",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/04/2027"
|
||||||
|
},
|
||||||
|
"1263573205268828231": {
|
||||||
|
"nom": "FERNANDEZ",
|
||||||
|
"prenom": "Mattéo",
|
||||||
|
"date_naissance": "07/05/1999",
|
||||||
|
"lieu_naissance": "Mexique",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/04/2027"
|
||||||
|
},
|
||||||
|
"730574544821157988": {
|
||||||
|
"nom": "ZENTORNO",
|
||||||
|
"prenom": "Neiz",
|
||||||
|
"date_naissance": "10/06/2000",
|
||||||
|
"lieu_naissance": "Algérie",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/04/2027"
|
||||||
|
},
|
||||||
|
"1244372888702816458": {
|
||||||
|
"nom": "LOPEZ",
|
||||||
|
"prenom": "Oussama",
|
||||||
|
"date_naissance": "11/07/2002",
|
||||||
|
"lieu_naissance": "chatelet les halles",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "27/04/2027"
|
||||||
|
},
|
||||||
|
"1321863072242995332": {
|
||||||
|
"nom": "RAMINEZ",
|
||||||
|
"prenom": "Rios",
|
||||||
|
"date_naissance": "10/02/2004",
|
||||||
|
"lieu_naissance": "Rome",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "09/06/2027"
|
||||||
|
},
|
||||||
|
"1363308330721738842": {
|
||||||
|
"nom": "BELFORD",
|
||||||
|
"prenom": "Jordan",
|
||||||
|
"date_naissance": "13/11/2004",
|
||||||
|
"lieu_naissance": "Manhattan New York",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "16/05/2027"
|
||||||
|
},
|
||||||
|
"599130976806764545": {
|
||||||
|
"nom": "HAMILTON",
|
||||||
|
"prenom": "William",
|
||||||
|
"date_naissance": "23/08/1977",
|
||||||
|
"lieu_naissance": "Québec",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "01/05/2027"
|
||||||
|
},
|
||||||
|
"1268584648611729418": {
|
||||||
|
"nom": "VINCE",
|
||||||
|
"prenom": "Kyle",
|
||||||
|
"date_naissance": "08/07/2000",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "03/05/2027"
|
||||||
|
},
|
||||||
|
"727188532669448509": {
|
||||||
|
"nom": "LEROY",
|
||||||
|
"prenom": "Mady",
|
||||||
|
"date_naissance": "19/03/1997",
|
||||||
|
"lieu_naissance": "montreal",
|
||||||
|
"sexe": "Femme",
|
||||||
|
"date_expiration": "08/05/2027"
|
||||||
|
},
|
||||||
|
"1322531063012134943": {
|
||||||
|
"nom": "REVERSE",
|
||||||
|
"prenom": "Stanle",
|
||||||
|
"date_naissance": "07/10/2002",
|
||||||
|
"lieu_naissance": "Los Angeles",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "03/05/2027"
|
||||||
|
},
|
||||||
|
"1361493382911758528": {
|
||||||
|
"nom": "AMARA",
|
||||||
|
"prenom": "Madja",
|
||||||
|
"date_naissance": "12/06/2000",
|
||||||
|
"lieu_naissance": "Annaba",
|
||||||
|
"sexe": "Femme",
|
||||||
|
"date_expiration": "10/05/2027"
|
||||||
|
},
|
||||||
|
"561485865562406914": {
|
||||||
|
"nom": "ASVALT",
|
||||||
|
"prenom": "Harmonium",
|
||||||
|
"date_naissance": "01/01/2000",
|
||||||
|
"lieu_naissance": "Luxembourg",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "10/05/2027"
|
||||||
|
},
|
||||||
|
"1282306873563021357": {
|
||||||
|
"nom": "GRIMM",
|
||||||
|
"prenom": "Djelys",
|
||||||
|
"date_naissance": "25/09/1999",
|
||||||
|
"lieu_naissance": "Paris",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "10/05/2027"
|
||||||
|
},
|
||||||
|
"1238099342288752661": {
|
||||||
|
"nom": "MAJO GARO",
|
||||||
|
"prenom": "Wireless",
|
||||||
|
"date_naissance": "1984/10/28",
|
||||||
|
"lieu_naissance": "Mexique",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "17/05/2027"
|
||||||
|
},
|
||||||
|
"1058418257142501417": {
|
||||||
|
"nom": "LOUÏE",
|
||||||
|
"prenom": "Jean",
|
||||||
|
"date_naissance": "02/07/2005",
|
||||||
|
"lieu_naissance": "Toulouse",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "29/05/2027"
|
||||||
|
},
|
||||||
|
"1351821260140707862": {
|
||||||
|
"nom": "RICCI",
|
||||||
|
"prenom": "Antonio",
|
||||||
|
"date_naissance": "30/03/2000",
|
||||||
|
"lieu_naissance": "Rome",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "07/06/2027"
|
||||||
|
},
|
||||||
|
"558327236378361857": {
|
||||||
|
"nom": "MUSULIN",
|
||||||
|
"prenom": "Tony",
|
||||||
|
"date_naissance": "15/11/1987",
|
||||||
|
"lieu_naissance": "New York",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "07/06/2027"
|
||||||
|
},
|
||||||
|
"1364012189052178533": {
|
||||||
|
"nom": "LORAS",
|
||||||
|
"prenom": "Philippe",
|
||||||
|
"date_naissance": "06/03/2000",
|
||||||
|
"lieu_naissance": "Kinshasa",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "20/06/2027"
|
||||||
|
},
|
||||||
|
"1350161151539024007": {
|
||||||
|
"nom": "PILISO",
|
||||||
|
"prenom": "Antonio",
|
||||||
|
"date_naissance": "30/11/2006",
|
||||||
|
"lieu_naissance": "Bogotta",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "07/06/2027"
|
||||||
|
},
|
||||||
|
"1312077385780301865": {
|
||||||
|
"nom": "LONDUHAUT",
|
||||||
|
"prenom": "Yanis",
|
||||||
|
"date_naissance": "07/03/2001",
|
||||||
|
"lieu_naissance": "New York",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "09/06/2027"
|
||||||
|
},
|
||||||
|
"1217095995804876950": {
|
||||||
|
"nom": "SMITH",
|
||||||
|
"prenom": "Franklin",
|
||||||
|
"date_naissance": "11/08/2004",
|
||||||
|
"lieu_naissance": "Los Angeles",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "22/06/2027"
|
||||||
|
},
|
||||||
|
"376796341071773706": {
|
||||||
|
"nom": "FRICADELLO",
|
||||||
|
"prenom": "Niccolo",
|
||||||
|
"date_naissance": "24/11/1987",
|
||||||
|
"lieu_naissance": "Chihuahua",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "15/06/2027"
|
||||||
|
},
|
||||||
|
"478564181356838922": {
|
||||||
|
"nom": "ECCLESTON",
|
||||||
|
"prenom": "John",
|
||||||
|
"date_naissance": "21 aout 1990",
|
||||||
|
"lieu_naissance": "Londres",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "15/06/2027"
|
||||||
|
},
|
||||||
|
"897082541033545739": {
|
||||||
|
"nom": "SALVADOR",
|
||||||
|
"prenom": "Diego",
|
||||||
|
"date_naissance": "18/06/2003",
|
||||||
|
"lieu_naissance": "Mexico",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "22/06/2027"
|
||||||
|
},
|
||||||
|
"1048991928496177152": {
|
||||||
|
"nom": "BRABUS",
|
||||||
|
"prenom": "Selim",
|
||||||
|
"date_naissance": "08/01/2002",
|
||||||
|
"lieu_naissance": "Rome",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "15/06/2027"
|
||||||
|
},
|
||||||
|
"1351650470392893512": {
|
||||||
|
"nom": "LOPEZ",
|
||||||
|
"prenom": "Jason",
|
||||||
|
"date_naissance": "19/09/1990",
|
||||||
|
"lieu_naissance": "Milano",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "19/06/2027"
|
||||||
|
},
|
||||||
|
"1218642392043884685": {
|
||||||
|
"nom": "MANCINI",
|
||||||
|
"prenom": "Salvatore",
|
||||||
|
"date_naissance": "22/11/1965",
|
||||||
|
"lieu_naissance": "Venice",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "19/06/2027"
|
||||||
|
},
|
||||||
|
"1246814346139668553": {
|
||||||
|
"nom": "MENDEZ",
|
||||||
|
"prenom": "Arthur",
|
||||||
|
"date_naissance": "20/03/2000",
|
||||||
|
"lieu_naissance": "Guillerval",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "19/06/2027"
|
||||||
|
},
|
||||||
|
"1072112886509473792": {
|
||||||
|
"nom": "FROG",
|
||||||
|
"prenom": "Beka",
|
||||||
|
"date_naissance": "19/10/1994",
|
||||||
|
"lieu_naissance": "Toronto",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "20/06/2027"
|
||||||
|
},
|
||||||
|
"690202239536857174": {
|
||||||
|
"nom": "DO SANTOS",
|
||||||
|
"prenom": "Raphaël",
|
||||||
|
"date_naissance": "19/06/1998",
|
||||||
|
"lieu_naissance": "Sao Paulo",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "22/06/2027"
|
||||||
|
},
|
||||||
|
"1290382773013577802": {
|
||||||
|
"nom": "DO SANTOS",
|
||||||
|
"prenom": "Fernando",
|
||||||
|
"date_naissance": "04/02/2003",
|
||||||
|
"lieu_naissance": "Sao Paulo",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/06/2027"
|
||||||
|
},
|
||||||
|
"930869581931745410": {
|
||||||
|
"nom": "REAPER",
|
||||||
|
"prenom": "Tommy",
|
||||||
|
"date_naissance": "25/01/2003",
|
||||||
|
"lieu_naissance": "New York",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "25/06/2027"
|
||||||
|
},
|
||||||
|
"667478308870422568": {
|
||||||
|
"nom": "SUPER",
|
||||||
|
"prenom": "Giovanni",
|
||||||
|
"date_naissance": "08/10/1993",
|
||||||
|
"lieu_naissance": "Stockholm",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "02/07/2027"
|
||||||
|
},
|
||||||
|
"1341203038609739889": {
|
||||||
|
"nom": "MARAZEL",
|
||||||
|
"prenom": "Tyson",
|
||||||
|
"date_naissance": "26/08/2002",
|
||||||
|
"lieu_naissance": "Marseille",
|
||||||
|
"sexe": "Homme",
|
||||||
|
"date_expiration": "04/07/2027"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
stats_commandes.json
Normal file
1
stats_commandes.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
64
taches.json
Normal file
64
taches.json
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
{
|
||||||
|
"taches": {
|
||||||
|
"7": {
|
||||||
|
"titre": "Contactez White",
|
||||||
|
"description": "Faire des vidéos de la map",
|
||||||
|
"assigné": 534003230435442690,
|
||||||
|
"statut": "À faire",
|
||||||
|
"priorité": "Critique",
|
||||||
|
"échéance": "2025-06-30",
|
||||||
|
"créé_par": 971446412690722826,
|
||||||
|
"commentaires": []
|
||||||
|
},
|
||||||
|
"10": {
|
||||||
|
"titre": "Vocal en rapport avec les sanctions récente",
|
||||||
|
"description": "J'aimerais que tu me programme une voc **URGENTE** avec Nooxi au plus vite et toi pour que je discute avec vous a propos des sanctions à votre encontre",
|
||||||
|
"assigné": 1108087282692522105,
|
||||||
|
"statut": "Terminée",
|
||||||
|
"priorité": "Critique",
|
||||||
|
"échéance": "2025-07-04",
|
||||||
|
"créé_par": 971446412690722826,
|
||||||
|
"commentaires": []
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"titre": "PRÉSENTATION DU SERVEUR",
|
||||||
|
"description": "refaire la présentation du serveur",
|
||||||
|
"assigné": 914118793918312480,
|
||||||
|
"statut": "À faire",
|
||||||
|
"priorité": "Haute",
|
||||||
|
"échéance": "2025-02-07",
|
||||||
|
"créé_par": 914118793918312480,
|
||||||
|
"commentaires": []
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"titre": "Liste Métier counter",
|
||||||
|
"description": "Bot qui ajoute automatiquement +1 ou -1 sur le poste quand un joueur reçoit le rôle",
|
||||||
|
"assigné": 971446412690722826,
|
||||||
|
"statut": "🛠️ V1.7 de Vicy en préparation. 📅 Sortie à définir.",
|
||||||
|
"priorité": "Moyenne",
|
||||||
|
"échéance": "2025-07-04",
|
||||||
|
"créé_par": 667478308870422568,
|
||||||
|
"commentaires": []
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"titre": "Mise en production de Vicy publique",
|
||||||
|
"description": "Création de Vicy publique",
|
||||||
|
"assigné": 971446412690722826,
|
||||||
|
"statut": "À faire",
|
||||||
|
"priorité": "Basse",
|
||||||
|
"échéance": "2025-09-01",
|
||||||
|
"créé_par": 971446412690722826,
|
||||||
|
"commentaires": []
|
||||||
|
},
|
||||||
|
"151": {
|
||||||
|
"titre": "dzqdz",
|
||||||
|
"description": "dzqqdz",
|
||||||
|
"assigné": 971446412690722826,
|
||||||
|
"statut": "Terminée",
|
||||||
|
"priorité": "Critique",
|
||||||
|
"échéance": "2025-07-22",
|
||||||
|
"créé_par": 971446412690722826,
|
||||||
|
"commentaires": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
58
utils/banque_manager.py
Normal file
58
utils/banque_manager.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
from .logger import log_error
|
||||||
|
|
||||||
|
class BanqueManager:
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
self.file_path = "comptes_bancaires.json"
|
||||||
|
self.comptes = {}
|
||||||
|
self.load_data()
|
||||||
|
|
||||||
|
def load_data(self):
|
||||||
|
"""Charge les données bancaires depuis un fichier JSON."""
|
||||||
|
if os.path.exists(self.file_path):
|
||||||
|
try:
|
||||||
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
||||||
|
data = f.read().strip()
|
||||||
|
self.comptes = json.loads(data) if data else {}
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
log_error("Erreur de lecture dans comptes_bancaires.json, réinitialisation...")
|
||||||
|
self.comptes = {}
|
||||||
|
self.save_data()
|
||||||
|
|
||||||
|
def save_data(self):
|
||||||
|
"""Sauvegarde les comptes et transactions dans comptes_bancaires.json."""
|
||||||
|
with open(self.file_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(self.comptes, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
def enregistrer_transaction(self, emetteur_id, destinataire_id, montant, type_transaction):
|
||||||
|
"""
|
||||||
|
Enregistre une transaction dans l'historique et recharge les données en temps réel.
|
||||||
|
"""
|
||||||
|
self.load_data()
|
||||||
|
|
||||||
|
transaction = {
|
||||||
|
"date": datetime.now().strftime("%d/%m/%Y %H:%M:%S"),
|
||||||
|
"type": type_transaction,
|
||||||
|
"montant": montant,
|
||||||
|
"emetteur": emetteur_id,
|
||||||
|
"destinataire": destinataire_id
|
||||||
|
}
|
||||||
|
|
||||||
|
if emetteur_id not in self.comptes:
|
||||||
|
self.comptes[emetteur_id] = {"solde": 0, "prets": [], "transactions": []}
|
||||||
|
elif "transactions" not in self.comptes[emetteur_id]:
|
||||||
|
self.comptes[emetteur_id]["transactions"] = []
|
||||||
|
|
||||||
|
self.comptes[emetteur_id]["transactions"].append(transaction)
|
||||||
|
|
||||||
|
if destinataire_id not in self.comptes:
|
||||||
|
self.comptes[destinataire_id] = {"solde": 0, "prets": [], "transactions": []}
|
||||||
|
elif "transactions" not in self.comptes[destinataire_id]:
|
||||||
|
self.comptes[destinataire_id]["transactions"] = []
|
||||||
|
|
||||||
|
self.comptes[destinataire_id]["transactions"].append(transaction)
|
||||||
|
|
||||||
|
self.save_data()
|
||||||
126
utils/card_generator.py
Normal file
126
utils/card_generator.py
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
import os
|
||||||
|
import aiohttp
|
||||||
|
import discord
|
||||||
|
from io import BytesIO
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
class CardGenerator:
|
||||||
|
def __init__(self):
|
||||||
|
self.session = None
|
||||||
|
self.template = None
|
||||||
|
self.watermark = None
|
||||||
|
self.font_regular = None
|
||||||
|
self.font_bold = None
|
||||||
|
self.font_large = None
|
||||||
|
self.create_template()
|
||||||
|
|
||||||
|
def create_template(self):
|
||||||
|
try:
|
||||||
|
CI_path = "/home/discord/Bot/Vicy/ressources/assets/CIITAL.png"
|
||||||
|
|
||||||
|
if not os.path.exists(CI_path):
|
||||||
|
raise FileNotFoundError(f"Image de fond introuvable : {CI_path}")
|
||||||
|
|
||||||
|
# Chargement de l'image de base
|
||||||
|
self.template = Image.open(CI_path).convert("RGBA")
|
||||||
|
self.template = self.template.resize((800, 500))
|
||||||
|
|
||||||
|
# Vérifier que l'image a bien été chargée
|
||||||
|
if self.template is None:
|
||||||
|
raise ValueError("L'image de fond n'a pas été chargée correctement.")
|
||||||
|
|
||||||
|
# Chargement des polices
|
||||||
|
try:
|
||||||
|
self.font_regular = ImageFont.load_default()
|
||||||
|
self.font_bold = ImageFont.load_default()
|
||||||
|
self.font_large = ImageFont.load_default()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors du chargement des polices: {e}")
|
||||||
|
self.font_regular = None
|
||||||
|
self.font_bold = None
|
||||||
|
self.font_large = None
|
||||||
|
|
||||||
|
# Créer un filigrane transparent
|
||||||
|
self.watermark = Image.new('RGBA', (800, 500), (255, 255, 255, 0))
|
||||||
|
watermark_draw = ImageDraw.Draw(self.watermark)
|
||||||
|
|
||||||
|
for i in range(0, 800, 100):
|
||||||
|
for j in range(0, 500, 100):
|
||||||
|
watermark_draw.text((i, j), "", fill=(200, 200, 200, 100))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de la création du template: {e}")
|
||||||
|
self.template = None
|
||||||
|
self.watermark = None
|
||||||
|
|
||||||
|
async def get_session(self):
|
||||||
|
if self.session is None:
|
||||||
|
self.session = aiohttp.ClientSession()
|
||||||
|
return self.session
|
||||||
|
|
||||||
|
async def download_avatar(self, user):
|
||||||
|
if not user.avatar:
|
||||||
|
return Image.new('RGBA', (200, 200), (128, 128, 128, 255))
|
||||||
|
|
||||||
|
try:
|
||||||
|
session = await self.get_session()
|
||||||
|
async with session.get(str(user.avatar.url)) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
avatar_data = await response.read()
|
||||||
|
return Image.open(BytesIO(avatar_data)).convert('RGBA')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors du téléchargement de l'avatar: {e}")
|
||||||
|
return Image.new('RGBA', (200, 200), (128, 128, 128, 255))
|
||||||
|
|
||||||
|
async def create_identity_card(self, user, identity_data):
|
||||||
|
if not self.template:
|
||||||
|
self.create_template()
|
||||||
|
if not self.template:
|
||||||
|
raise Exception("Impossible de créer le template")
|
||||||
|
|
||||||
|
card = self.template.copy()
|
||||||
|
draw = ImageDraw.Draw(card)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Photo de profil
|
||||||
|
avatar = await self.download_avatar(user)
|
||||||
|
avatar = avatar.resize((200, 200), Image.LANCZOS)
|
||||||
|
mask = Image.new('L', avatar.size, 0)
|
||||||
|
mask_draw = ImageDraw.Draw(mask)
|
||||||
|
mask_draw.ellipse((0, 0, 200, 200), fill=255)
|
||||||
|
card.paste(avatar, (50, 120), mask)
|
||||||
|
|
||||||
|
# Informations personnelles
|
||||||
|
text_positions = {
|
||||||
|
'nom': (328, 169),
|
||||||
|
'prenom': (329, 212),
|
||||||
|
'date_naissance': (329, 254),
|
||||||
|
'lieu_naissance': (489, 169),
|
||||||
|
'sexe': (511, 212),
|
||||||
|
'date_expiration': (26, 408)
|
||||||
|
}
|
||||||
|
|
||||||
|
for field, pos in text_positions.items():
|
||||||
|
value = str(identity_data[field])
|
||||||
|
|
||||||
|
draw.text(pos,
|
||||||
|
value,
|
||||||
|
fill='black',
|
||||||
|
font=self.font_bold if field in ['nom', 'prenom'] else self.font_regular)
|
||||||
|
|
||||||
|
if self.watermark:
|
||||||
|
card.paste(self.watermark, (0, 0), self.watermark)
|
||||||
|
|
||||||
|
buffer = BytesIO()
|
||||||
|
card.save(buffer, format='PNG')
|
||||||
|
buffer.seek(0)
|
||||||
|
return buffer
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de la création de la carte: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
async def cleanup(self):
|
||||||
|
if self.session:
|
||||||
|
await self.session.close()
|
||||||
|
self.session = None
|
||||||
61
utils/data_manager.py
Normal file
61
utils/data_manager.py
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
|
||||||
|
class DataManager:
|
||||||
|
""" Gère la sauvegarde et le chargement des données. """
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.identities = {}
|
||||||
|
self.load_data()
|
||||||
|
|
||||||
|
def save_data(self):
|
||||||
|
""" Sauvegarde les identités dans un fichier JSON. """
|
||||||
|
try:
|
||||||
|
with open('ressources/data.json', 'w', encoding='utf-8') as f:
|
||||||
|
json.dump({'identities': self.identities}, f, ensure_ascii=False, indent=4)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de la sauvegarde des données: {e}")
|
||||||
|
|
||||||
|
def load_data(self):
|
||||||
|
""" Charge les identités depuis un fichier JSON. """
|
||||||
|
try:
|
||||||
|
if os.path.exists('ressources/data.json'):
|
||||||
|
with open('ressources/data.json', 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
self.identities = data.get('identities', {})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors du chargement des données: {e}")
|
||||||
|
self.identities = {}
|
||||||
|
|
||||||
|
class DataManager:
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialise le gestionnaire de données et charge les identités existantes."""
|
||||||
|
self.file_path = os.path.join(os.path.dirname(__file__), "../ressources/data.json")
|
||||||
|
self.identities = self.load_data() # Charge les données existantes
|
||||||
|
|
||||||
|
def load_data(self):
|
||||||
|
"""Charge les identités depuis le fichier JSON."""
|
||||||
|
if not os.path.exists(self.file_path):
|
||||||
|
print(f"⚠️ Fichier {self.file_path} introuvable. Création d'un nouveau fichier...")
|
||||||
|
self.save_data() # Crée un fichier vide
|
||||||
|
return {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.file_path, "r", encoding="utf-8") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
return data.get("identities", {})
|
||||||
|
except (json.JSONDecodeError, IOError) as e:
|
||||||
|
print(f"❌ Erreur lors du chargement des données : {e}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def save_data(self):
|
||||||
|
"""Sauvegarde les identités dans un fichier JSON."""
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(self.file_path), exist_ok=True)
|
||||||
|
with open(self.file_path, "w", encoding="utf-8") as f:
|
||||||
|
json.dump({"identities": self.identities}, f, ensure_ascii=False, indent=4)
|
||||||
|
print(f"✅ Données sauvegardées dans {self.file_path}")
|
||||||
|
except IOError as e:
|
||||||
|
print(f"❌ Erreur lors de la sauvegarde des données : {e}")
|
||||||
89
utils/gestion_taches.py
Normal file
89
utils/gestion_taches.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import asyncio
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
FICHIER_TACHES = "taches.json"
|
||||||
|
FICHIER_TACHES_TMP = "taches.json.tmp"
|
||||||
|
FICHIER_ID = "id_compteur.json"
|
||||||
|
file_lock = asyncio.Lock()
|
||||||
|
|
||||||
|
async def charger_taches():
|
||||||
|
async with file_lock:
|
||||||
|
if not os.path.exists(FICHIER_TACHES):
|
||||||
|
with open(FICHIER_TACHES, "w", encoding='utf-8') as f:
|
||||||
|
json.dump({"taches": {}}, f, indent=4)
|
||||||
|
with open(FICHIER_TACHES, "r", encoding='utf-8') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
async def sauvegarder_taches(donnees):
|
||||||
|
async with file_lock:
|
||||||
|
with open(FICHIER_TACHES_TMP, "w", encoding='utf-8') as f:
|
||||||
|
json.dump(donnees, f, indent=4, ensure_ascii=False)
|
||||||
|
os.replace(FICHIER_TACHES_TMP, FICHIER_TACHES)
|
||||||
|
|
||||||
|
async def generer_id_unique():
|
||||||
|
async with file_lock:
|
||||||
|
if not os.path.exists(FICHIER_ID):
|
||||||
|
with open(FICHIER_ID, "w", encoding='utf-8') as f:
|
||||||
|
json.dump({"dernier_id": 0}, f, indent=4)
|
||||||
|
|
||||||
|
with open(FICHIER_ID, "r+", encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
data["dernier_id"] += 1
|
||||||
|
f.seek(0)
|
||||||
|
json.dump(data, f, indent=4)
|
||||||
|
f.truncate()
|
||||||
|
return str(data["dernier_id"])
|
||||||
|
|
||||||
|
async def ajouter_tache(titre, description, user_id, priorite, date_echeance, auteur_id):
|
||||||
|
data = await charger_taches()
|
||||||
|
taches = data["taches"]
|
||||||
|
id_tache = await generer_id_unique()
|
||||||
|
|
||||||
|
taches[id_tache] = {
|
||||||
|
"titre": titre,
|
||||||
|
"description": description,
|
||||||
|
"assigné": user_id,
|
||||||
|
"statut": "À faire",
|
||||||
|
"priorité": priorite,
|
||||||
|
"échéance": date_echeance,
|
||||||
|
"créé_par": auteur_id,
|
||||||
|
"commentaires": []
|
||||||
|
}
|
||||||
|
|
||||||
|
await sauvegarder_taches(data)
|
||||||
|
return id_tache
|
||||||
|
|
||||||
|
async def update_tache_status(id_tache, statut):
|
||||||
|
data = await charger_taches()
|
||||||
|
if id_tache in data["taches"]:
|
||||||
|
data["taches"][id_tache]["statut"] = statut
|
||||||
|
await sauvegarder_taches(data)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def supprimer_tache(id_tache):
|
||||||
|
data = await charger_taches()
|
||||||
|
if id_tache in data["taches"]:
|
||||||
|
del data["taches"][id_tache]
|
||||||
|
await sauvegarder_taches(data)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def lister_taches_utilisateur(user_id):
|
||||||
|
data = await charger_taches()
|
||||||
|
return {tid: t for tid, t in data["taches"].items() if t["assigné"] == user_id}
|
||||||
|
|
||||||
|
async def taches_proches():
|
||||||
|
data = await charger_taches()
|
||||||
|
proches = {}
|
||||||
|
now = datetime.now()
|
||||||
|
for tid, t in data["taches"].items():
|
||||||
|
try:
|
||||||
|
date_obj = datetime.strptime(t["échéance"], "%Y-%m-%d")
|
||||||
|
if 0 <= (date_obj - now).days <= 2:
|
||||||
|
proches[tid] = t
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
return proches
|
||||||
50
utils/image_generator.py
Normal file
50
utils/image_generator.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import json
|
||||||
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
import os
|
||||||
|
|
||||||
|
def generate_bank_image(user_id, balance, transactions):
|
||||||
|
"""Génère une image avec les informations bancaires de l'utilisateur."""
|
||||||
|
|
||||||
|
image_path = "ressources/assets/template.png"
|
||||||
|
if not os.path.exists(image_path):
|
||||||
|
print(f"❌ Erreur : Fichier {image_path} introuvable.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
image = Image.open(image_path)
|
||||||
|
draw = ImageDraw.Draw(image)
|
||||||
|
|
||||||
|
# Vérifier que la police existe
|
||||||
|
font_path = "ressources/font.ttf"
|
||||||
|
if not os.path.exists(font_path):
|
||||||
|
print("❌ Erreur : Police introuvable, chargement de la police par défaut.")
|
||||||
|
font_large = ImageFont.load_default()
|
||||||
|
font_small = ImageFont.load_default()
|
||||||
|
else:
|
||||||
|
font_large = ImageFont.truetype(font_path, 120)
|
||||||
|
font_small = ImageFont.truetype(font_path, 30)
|
||||||
|
|
||||||
|
# Centrer le solde en dessous de la fenêtre bleue
|
||||||
|
balance_text = f"Solde : {balance} €"
|
||||||
|
balance_x = (image.width - draw.textlength(balance_text, font=font_large)) // 2
|
||||||
|
balance_y = 850 # Ajustez cette valeur pour positionner le texte en dessous de la fenêtre bleue
|
||||||
|
draw.text((balance_x, balance_y), balance_text, fill="white", font=font_large)
|
||||||
|
|
||||||
|
# Affichage des transactions
|
||||||
|
start_x = 50 # Ajustez cette valeur pour l'alignement horizontal
|
||||||
|
start_y = 400 # Ajustez cette valeur pour l'alignement vertical
|
||||||
|
spacing_y = 60 # Espace entre les lignes de transaction
|
||||||
|
|
||||||
|
for transaction in transactions[:3]: # Max 3 transactions
|
||||||
|
transaction_text = f"{transaction['date']} - {transaction['type']} : {transaction['montant']}€"
|
||||||
|
draw.text((start_x, start_y), transaction_text, fill="black", font=font_small)
|
||||||
|
start_y += spacing_y
|
||||||
|
|
||||||
|
# Supprimer le texte "Victoria’s Vice™"
|
||||||
|
erase_box = (30, image.height - 50, 250, image.height - 20)
|
||||||
|
draw.rectangle(erase_box, fill=(255, 255, 255))
|
||||||
|
|
||||||
|
# Sauvegarde de l'image générée
|
||||||
|
output_path = f"ressources/bank_{user_id}.png"
|
||||||
|
image.save(output_path)
|
||||||
|
print(f"✅ Image bancaire générée : {output_path}")
|
||||||
|
return output_path
|
||||||
34
utils/logger.py
Normal file
34
utils/logger.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
import pytz # Nécessite le package pytz
|
||||||
|
|
||||||
|
# Définir le fuseau horaire France
|
||||||
|
paris_tz = pytz.timezone("Europe/Paris")
|
||||||
|
|
||||||
|
class FranceFormatter(logging.Formatter):
|
||||||
|
def formatTime(self, record, datefmt=None):
|
||||||
|
dt = datetime.fromtimestamp(record.created, tz=paris_tz)
|
||||||
|
if datefmt:
|
||||||
|
return dt.strftime(datefmt)
|
||||||
|
return dt.isoformat()
|
||||||
|
|
||||||
|
# Création du logger
|
||||||
|
logger = logging.getLogger()
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Handler vers fichier
|
||||||
|
file_handler = logging.FileHandler("log.txt", encoding="utf-8")
|
||||||
|
formatter = FranceFormatter("%(asctime)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
# Fonctions de log
|
||||||
|
def log_info(message):
|
||||||
|
logger.info(message)
|
||||||
|
|
||||||
|
def log_warning(message):
|
||||||
|
logger.warning(message)
|
||||||
|
|
||||||
|
def log_error(message):
|
||||||
|
logger.error(message)
|
||||||
82
utils/stats_manager.py
Normal file
82
utils/stats_manager.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
import sqlite3
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Chemin de la base de données (dans un sous-dossier "data" pour garder le projet propre)
|
||||||
|
DB_PATH = "data/stats.db"
|
||||||
|
|
||||||
|
# Crée le dossier "data" si besoin
|
||||||
|
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
|
||||||
|
|
||||||
|
# Connexion à la base de données
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Création de la table si elle n'existe pas
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS commandes (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
nom TEXT,
|
||||||
|
user_id INTEGER,
|
||||||
|
guild_id INTEGER,
|
||||||
|
date TIMESTAMP
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def enregistrer_utilisation(nom_commande, user_id, guild_id):
|
||||||
|
"""Enregistre l'utilisation d'une commande."""
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO commandes (nom, user_id, guild_id, date) VALUES (?, ?, ?, ?)",
|
||||||
|
(nom_commande, user_id, guild_id, datetime.datetime.now())
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def get_stats():
|
||||||
|
"""Retourne les statistiques d'utilisation du bot."""
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM commandes")
|
||||||
|
total = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
cursor.execute("SELECT nom, COUNT(*) as nb FROM commandes GROUP BY nom ORDER BY nb DESC LIMIT 5")
|
||||||
|
top_commandes = cursor.fetchall()
|
||||||
|
|
||||||
|
cursor.execute("SELECT user_id, COUNT(*) as nb FROM commandes GROUP BY user_id ORDER BY nb DESC LIMIT 1")
|
||||||
|
top_user = cursor.fetchone()
|
||||||
|
|
||||||
|
return total, top_commandes, top_user
|
||||||
|
|
||||||
|
|
||||||
|
def get_stats_detailed():
|
||||||
|
# Exemple de données simulées, à remplacer par tes vraies données
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
total_commandes = 1234
|
||||||
|
top_commandes = [("help", 250), ("stats_bot", 180), ("play", 160), ("ban", 100), ("kick", 90)]
|
||||||
|
top_utilisateurs = [(123456789012345678, 300), (987654321098765432, 220), (111222333444555666, 180), (444555666777888999, 160), (555666777888999000, 130)]
|
||||||
|
|
||||||
|
today = datetime.today()
|
||||||
|
evolution_commandes = []
|
||||||
|
for i in range(7): # dernière semaine
|
||||||
|
day = today - timedelta(days=6 - i)
|
||||||
|
evolution_commandes.append((day, 150 + i*10))
|
||||||
|
|
||||||
|
repartition_statuts = {"À faire": 50, "En cours": 30, "Terminée": 70, "Bloqué": 10}
|
||||||
|
|
||||||
|
commandes_par_jour = {
|
||||||
|
"Lundi": 180,
|
||||||
|
"Mardi": 210,
|
||||||
|
"Mercredi": 150,
|
||||||
|
"Jeudi": 200,
|
||||||
|
"Vendredi": 220,
|
||||||
|
"Samedi": 90,
|
||||||
|
"Dimanche": 40,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"total_commandes": total_commandes,
|
||||||
|
"top_commandes": top_commandes,
|
||||||
|
"top_utilisateurs": top_utilisateurs,
|
||||||
|
"evolution_commandes": evolution_commandes,
|
||||||
|
"repartition_statuts": repartition_statuts,
|
||||||
|
"commandes_par_jour": commandes_par_jour
|
||||||
|
}
|
||||||
30
utils/welcome_message.py
Normal file
30
utils/welcome_message.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
from utils.logger import log_info, log_error
|
||||||
|
|
||||||
|
class WelcomeMessage(commands.Cog):
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_member_join(self, member):
|
||||||
|
try:
|
||||||
|
# ID du salon discussion
|
||||||
|
welcome_channel_id = 1278483527783944242
|
||||||
|
welcome_channel = member.guild.get_channel(welcome_channel_id)
|
||||||
|
|
||||||
|
if welcome_channel:
|
||||||
|
welcome_message = (
|
||||||
|
f"## BIENVENUE <:panda_welcome:1297298999849517056> !\n\n"
|
||||||
|
f"> **L'équipe staff te souhaite la bienvenue sur Victoria's Vice {member.mention} !**\n\n"
|
||||||
|
f"> Pour ta candidature <:arrow_1:1297491509201080362> <#1278477608392196176> / <#1278477152215371806> \n\n"
|
||||||
|
f"> Si tu as des questions <:arrow_1:1297491509201080362> <#1279037583820718120>\n\n"
|
||||||
|
f"*> Bien cordialement, L'équipe staff de Victoria's Vice*"
|
||||||
|
)
|
||||||
|
|
||||||
|
await welcome_channel.send(welcome_message)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Erreur lors de l'envoi du message de bienvenue: {e}")
|
||||||
|
|
||||||
|
async def setup(bot):
|
||||||
|
await bot.add_cog(WelcomeMessage(bot))
|
||||||
1
visite_médicale.json
Normal file
1
visite_médicale.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue