V2.0: Refonte système bancaire - DB SQLite, RIB FR, TVA auto, multi-banques

- Remplace JSON par SQLite (aiosqlite) pour atomicité et intégrité
- Nouveau format RIB français avec checksum modulo 97
- Chaque banque a son propre rôle Discord (isolation par serveur)
- TVA automatique Particulier -> Entreprise, redirection au Fisc
- Institutions gouvernementales avec droit d'audit optionnel
- Commandes: /gouv, /banque, /audit, /mes-ribs
- Supprime: 16 anciens fichiers (entreprises, FBM, URSAFF, etc.)
- Reset complet des données, repart de zéro
This commit is contained in:
utilisateurqu 2026-08-18 17:42:03 +02:00
parent 2e38d05152
commit c9ad155bf6
38 changed files with 3689 additions and 5106 deletions

View file

@ -1,138 +1,71 @@
import json
import discord
from discord import app_commands
from discord.ext import commands
from datetime import datetime
from utils.bank_manager import BankManager
from utils.rib import decoder_rib
bank_manager = BankManager()
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)
@app_commands.command(name="virement", description="Faire un virement à un autre compte via RIB")
@app_commands.describe(
rib_source="Votre RIB (compte source)",
rib_dest="RIB du destinataire",
montant="Montant à envoyer",
)
async def virement(
self,
interaction: discord.Interaction,
rib_source: str,
rib_dest: str,
montant: float,
):
if montant <= 0:
await interaction.response.send_message("❌ Le montant doit être supérieur à 0.", 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)
compte_source = await bank_manager.get_compte_by_rib(interaction.guild.id, rib_source)
if not compte_source:
await interaction.response.send_message("❌ RIB source introuvable.", ephemeral=True)
return
if compte_source["user_id"] != interaction.user.id:
await interaction.response.send_message("❌ Ce RIB ne vous appartient pas.", ephemeral=True)
return
# Rechercher le destinataire (utilisateur ou entreprise)
destinataire_id = None
banque_destinataire = None
is_entreprise = False
try:
result = await bank_manager.virement(
guild_id=interaction.guild.id,
rib_source=rib_source,
rib_dest=rib_dest,
montant=montant,
emetteur_id=interaction.user.id,
)
# 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
msg = f"✅ Virement de **{result['montant_envoye']:.2f}€** effectué."
if result["tva_prelevee"] > 0:
msg += f"\n💰 TVA prélevée : **{result['tva_prelevee']:.2f}€** → Fisc."
msg += f"\n**Reçu par le destinataire :** {result['montant_recu']:.2f}€"
# 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
await interaction.response.send_message(msg, ephemeral=True)
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
dest_compte = await bank_manager.get_compte_by_rib(interaction.guild.id, rib_dest)
if dest_compte and dest_compte["account_type"] == "particulier":
dest_user = await self.bot.fetch_user(dest_compte["user_id"])
await dest_user.send(
f"📥 Vous avez reçu **{result['montant_recu']:.2f}€** de la part de **{interaction.user.display_name}**."
)
except (discord.Forbidden, Exception):
pass
except ValueError as e:
await interaction.response.send_message(f"❌ {e}", ephemeral=True)
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))
await bot.add_cog(Virement(bot))