56 lines
1.6 KiB
Python
56 lines
1.6 KiB
Python
|
|
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),
|
||
|
|
}
|