A lightweight Django web app that converts Iranian bank account numbers ⇄ IBAN (Sheba) and validates them using the ISO-13616 / Mod-97 check. It includes bank-specific BBAN formatting rules for major Iranian banks and simple server-rendered forms.
Repo structure uses a standard Django layout with
manage.py, a project config, app packages,templates/, andstatic/. A sample SQLite DB is checked in for convenience. :contentReference[oaicite:0]{index=0}
- Two-way conversion
- Account ➜ IBAN (
ibanisthesabtosheba) - IBAN ➜ Account (
ibanistshebatohesab)
- Account ➜ IBAN (
- Validation
Implements the canonical Mod-97 checksum to verify IBAN integrity and length; invalid inputs return explicitinvalidmarkers for each field. - Bank-aware BBAN rules
Handles bank-specific account layouts and zero-padding before calculating check digits. - Simple forms & views
Server-rendered templates and POST forms; no database writes required for core conversion. - Clean outputs
Each conversion returns a dict with normalizediban,bank, andan(account number).
The converter recognizes bank prefixes and formatting for (examples):
- Keshavarzi (
016) - Tejarat (
018) - Refah (
013) - Saderat Iran (
019) - Parsian (
054) - Mehr Iran (
060) - Meli Iran (
017) - Melat (
012) - Sepah (
015)
It includes mappings between bank code ⇄ name and UI bank selector numbers, plus per-bank build rules (e.g., zero-padding to fixed widths, stripping leading digits where required).
-
Normalize input
Strip spaces, dashes, underscores, and anyIR/ircountry code remnants. -
Parse or build BBAN
- Account ➜ IBAN:
Use the incoming account (an) plus the selected bank to build the bank’s BBAN according to its rule (e.g., pad to 10/13 digits, inject bank-specific filler digits). - IBAN ➜ Account:
Extract the bank identifier (BI) and account number from the IBAN’s BBAN section and clean it (e.g., drop leading zeros or rule-specific leading digits).
- Account ➜ IBAN:
-
Compute check digits
Construct the BBAN, append"IR00"per ISO-13616, rotate, replace letters (I=18,R=27), and compute98 - (num % 97)to get the two check digits.
Final IBAN isIR{CD}{BBAN}. -
Verify
For any provided IBAN, verify length=26 andnumeric_rotation % 97 == 1. Invalids setiban,bank,anto'invalid'.
ibanist-django/
├─ config/ # Django project settings & URLs
├─ ibanistapp/ # App with views and conversion logic
├─ templates/ # Forms & result pages (incl. per-bank pages)
├─ static/ # Static assets (optional)
├─ manage.py # Django entry point
├─ db.sqlite3 # Sample DB (not required for logic)
└─ venv/ # (If committed) local Python env
See the repo for the exact folders and files, including
manage.pyand top-level packages. :contentReference[oaicite:1]{index=1}
git clone https://github.com/Amirhosseinpoor/ibanist-django.git
cd ibanist-django
# (Recommended) Create a fresh virtualenv
python -m venv .venv
# Windows: .venv\Scripts\activate
# Unix/Mac:
source .venv/bin/activate
pip install -r requirements.txt # if provided
# Otherwise:
pip install djangopython manage.py runserverOpen: http://127.0.0.1:8000/
Standard Django entry point is
manage.py. (GitHub)
The app uses simple server-rendered pages and POST forms:
-
Account ➜ IBAN:
ibanisthesabtosheba-
POST fields:
an_h— raw account numberbank_h— UI-selected bank key (e.g.,"1"→Keshavarzi,"2"→Tejarat, …)
-
-
IBAN ➜ Account:
ibanistshebatohesab-
POST fields:
iban_h— full IBAN (with or withoutIR)
-
Per-bank entry pages (examples):
benk_hesab_to_sheba/keshavarzi.html, .../tejarat.html, .../refah.html (plus a generic banks.html).
Output template: output.html
Receives a context dict: {"iban": ..., "bank": ..., "an": ...}.
print(Ibanist(an='3019025140830361', bank='6').__str__()["iban"])
# -> IR570600301902514083036001- Input account is normalized, bank prefix
060(Mehr Iran) is used. - The BBAN is assembled per the bank rule (including inserting
"00"near the end for Mehr Iran). - Check digits are computed with Mod-97.
- The final IBAN is returned alongside normalized
bankandan.
from ibanistapp.Main import Ibanist # adjust import to your module path
# Account ➜ IBAN
obj = Ibanist(an="1234567890", bank="2") # "2" might map to Tejarat
result = obj.__str__()
print(result["iban"], result["bank"], result["an"])
# IBAN ➜ Account
obj = Ibanist(iban="IRxx...") # full IBAN
result = obj.__str__()
print(result["an"], result["bank"])The __str__() method returns a dict:
{"iban": "<IBAN|invalid>", "bank": "<name|invalid>", "an": "<account|invalid>"}- Only Iranian IBANs (
IR) are handled; logic is tailored to local BBAN formats. - For some banks, account type can influence BBAN layout (e.g., “deposit” vs “facility”); defaults are applied where not specified.
- The UI uses simple POST forms; there is no API authentication and no persistence beyond request scope.
- Validation checks both format and Mod-97; malformed inputs are marked as
invalid.
- Add unit tests for each bank rule and checksum edge cases.
- Optional Django REST Framework API endpoints for programmatic access.
- Add more banks or newly updated BBAN specifications.
- Better i18n (Persian labels, error messages).
- Client-side input masking and formatting hints.
Typical Django flow:
# Run locally
python manage.py runserver
# (If you make model changes)
python manage.py makemigrations
python manage.py migrateThe project is a standard Django site; manage with the usual
manage.pycommands. (GitHub)
Add your preferred license here (e.g., MIT), and include a LICENSE file in the repository.
- Django web framework (project layout & dev workflow). (GitHub)
- IBAN algorithm reference (ISO-13616 Mod-97 method).