Vicy_Publique/utils/rib.py

56 lines
1.6 KiB
Python
Raw Normal View History

import random
import string
def _checksum(digits: str) -> int:
return (97 - (int(digits) % 97)) % 97
def generer_rib(establishment_code: int, guichet_code: int) -> str:
etab = str(establishment_code).zfill(5)
guichet = str(guichet_code).zfill(5)
numero = "".join(random.choices(string.digits, k=11))
checksum_digits = f"76{etab}{guichet}{numero}"
cle = str(_checksum(checksum_digits)).zfill(2)
return f"FR76 {etab} {guichet} {numero} {cle}"
def valider_rib(rib: str) -> bool:
parts = rib.replace("FR76 ", "").split()
if len(parts) != 3:
return False
etab, guichet, rest = parts
if len(etab) != 5 or len(guichet) != 5:
return False
if len(rest) != 13:
return False
numero = rest[:11]
cle = rest[11:]
if not etab.isdigit() or not guichet.isdigit() or not numero.isdigit() or not cle.isdigit():
return False
checksum_digits = f"76{etab}{guichet}{numero}"
return _checksum(checksum_digits) == int(cle)
def decoder_rib(rib: str) -> dict:
parts = rib.replace("FR76 ", "").split()
if len(parts) != 3:
return None
etab, guichet, rest = parts
numero = rest[:11]
cle = rest[11:]
etab_int = int(etab)
guichet_int = int(guichet)
TYPE_MAP = {4: "particulier", 3: "entreprise", 2: "banque", 1: "institution"}
return {
"etablissement": etab_int,
"guichet": guichet_int,
"numero": numero,
"cle": int(cle),
"type_compte": TYPE_MAP.get(guichet_int, "inconnu"),
"est_gouvernement": etab_int < 100,
"valide": valider_rib(rib),
}