+ bank.py
This commit is contained in:
parent
781dbaf709
commit
e9cca1d053
286
bank.py
286
bank.py
@ -1,7 +1,8 @@
|
|||||||
"""
|
# Имитация функций банка
|
||||||
Имитация функций банка
|
# задача: https://stepik.org/lesson/967334/step/7?unit=973876
|
||||||
|
# решение: https://gitea.b4tman.ru/temp/py_stepik/src/branch/master/bank.py
|
||||||
|
|
||||||
Условия задачи:
|
"""
|
||||||
Проект онлайн - банк(В стадии разработки)
|
Проект онлайн - банк(В стадии разработки)
|
||||||
|
|
||||||
Необходимо создать "онлайн" банк, у которого будут реализованы следующие функции. Разумеется, мы не создаем полноценный онлайн банк, это просто имитация.
|
Необходимо создать "онлайн" банк, у которого будут реализованы следующие функции. Разумеется, мы не создаем полноценный онлайн банк, это просто имитация.
|
||||||
@ -29,6 +30,9 @@ import datetime
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
session = {}
|
||||||
|
|
||||||
|
|
||||||
def get_hello_hour():
|
def get_hello_hour():
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
return ["Доброй ночи", "Доброе утро", "Добрый день", "Добрый вечер"][now.hour // 6]
|
return ["Доброй ночи", "Доброе утро", "Добрый день", "Добрый вечер"][now.hour // 6]
|
||||||
@ -73,13 +77,23 @@ class SimpleDataBase(metaclass=Singleton):
|
|||||||
with open(self.__class__.__FILENAME, "w", encoding="utf-8") as f:
|
with open(self.__class__.__FILENAME, "w", encoding="utf-8") as f:
|
||||||
json.dump(self.data, f)
|
json.dump(self.data, f)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _is_data(attr):
|
||||||
|
return "data" == attr
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
|
if self.__class__._is_data(attr):
|
||||||
|
return super().__getattr__(attr)
|
||||||
return self.data[attr]
|
return self.data[attr]
|
||||||
|
|
||||||
def __setattr__(self, attr, value):
|
def __setattr__(self, attr, value):
|
||||||
|
if self.__class__._is_data(attr):
|
||||||
|
return super().__setattr__(attr, value)
|
||||||
self.data[attr] = value
|
self.data[attr] = value
|
||||||
|
|
||||||
def __delattr__(self, attr):
|
def __delattr__(self, attr):
|
||||||
|
if self.__class__._is_data(attr):
|
||||||
|
return super().__delattr__(attr)
|
||||||
del self.data[attr]
|
del self.data[attr]
|
||||||
|
|
||||||
|
|
||||||
@ -98,15 +112,15 @@ class User:
|
|||||||
self.salt = ""
|
self.salt = ""
|
||||||
self.is_verifyed = False
|
self.is_verifyed = False
|
||||||
|
|
||||||
def set_password(self, password):
|
def set_password(self, password: str):
|
||||||
self.salt = uuid.uuid4().hex
|
self.salt = uuid.uuid4().hex
|
||||||
self.hash = hashlib.sha512((password + self.salt).encode("utf-8")).hexdigest()
|
self.hash = hashlib.sha512((password + self.salt).encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
def authenticate(self, password):
|
def authenticate(self, password: str) -> bool:
|
||||||
hash = hashlib.sha512((password + self.salt).encode("utf-8")).digest()
|
hash = hashlib.sha512((password + self.salt).encode("utf-8")).digest()
|
||||||
return hmac.compare_digest(hash, bytes.fromhex(self.hash))
|
return hmac.compare_digest(hash, bytes.fromhex(self.hash))
|
||||||
|
|
||||||
def email_verification(self, code):
|
def email_verification(self, code: int) -> bool:
|
||||||
res = self.verification_code == code
|
res = self.verification_code == code
|
||||||
if not self.is_verifyed:
|
if not self.is_verifyed:
|
||||||
self.is_verifyed = res
|
self.is_verifyed = res
|
||||||
@ -116,18 +130,28 @@ class User:
|
|||||||
users = Users()
|
users = Users()
|
||||||
users.save_user(self)
|
users.save_user(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, data: dict):
|
||||||
|
user = cls(*(data[k] for k in "name fio email verification_code".split()))
|
||||||
|
for k in "is_verifyed salt hash".split():
|
||||||
|
setattr(user, k, data[k])
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
class Users(metaclass=Singleton):
|
class Users(metaclass=Singleton):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db = SimpleDataBase()
|
self.db = SimpleDataBase()
|
||||||
|
|
||||||
def get_user(self, name):
|
def get_user(self, name: str) -> User:
|
||||||
return self.db.users.get(name)
|
data = self.db.users.get(name)
|
||||||
|
return data and User.from_dict(data)
|
||||||
|
|
||||||
def save_user(self, user):
|
def save_user(self, user: User):
|
||||||
self.db.users[user.name] = asdict(user)
|
self.db.users[user.name] = asdict(user)
|
||||||
|
|
||||||
def add_user(self, name, fio, email, verification_code, password):
|
def add_user(
|
||||||
|
self, name: str, fio: str, email: str, verification_code: int, password: str
|
||||||
|
) -> bool:
|
||||||
if self.get_user(name) is not None:
|
if self.get_user(name) is not None:
|
||||||
return False
|
return False
|
||||||
user = User(name, fio, email, verification_code)
|
user = User(name, fio, email, verification_code)
|
||||||
@ -135,11 +159,11 @@ class Users(metaclass=Singleton):
|
|||||||
self.save_user(user)
|
self.save_user(user)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def authenticate(self, name, password):
|
def authenticate(self, name: str, password: str) -> User | None:
|
||||||
user = self.get_user(name)
|
user = self.get_user(name)
|
||||||
if user is None:
|
if user is None:
|
||||||
return False
|
return False
|
||||||
return user.authenticate(password)
|
return user.authenticate(password) and user or None
|
||||||
|
|
||||||
|
|
||||||
def fake_email_send(email, code):
|
def fake_email_send(email, code):
|
||||||
@ -148,6 +172,8 @@ def fake_email_send(email, code):
|
|||||||
|
|
||||||
|
|
||||||
def registration():
|
def registration():
|
||||||
|
"""Регистрация"""
|
||||||
|
|
||||||
print(f"{get_hello_hour()}! Давайте Вас зарегистрируем!")
|
print(f"{get_hello_hour()}! Давайте Вас зарегистрируем!")
|
||||||
fio = input("Ваше ФИО: ")
|
fio = input("Ваше ФИО: ")
|
||||||
name = input("Ваш логин: ")
|
name = input("Ваш логин: ")
|
||||||
@ -164,13 +190,19 @@ def registration():
|
|||||||
"На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)"
|
"На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)"
|
||||||
)
|
)
|
||||||
users.db.commit()
|
users.db.commit()
|
||||||
exit(0)
|
|
||||||
|
session["user"] = users.get_user(name)
|
||||||
else:
|
else:
|
||||||
print("Ошибка, выберите другой логин!")
|
print("Ошибка, выберите другой логин!")
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def login():
|
def login() -> User | None:
|
||||||
|
"""Вход"""
|
||||||
|
|
||||||
|
if "user" in session:
|
||||||
|
print(f"Вы уже вошли в систему, {session['user'].fio}!")
|
||||||
|
return session["user"]
|
||||||
|
|
||||||
print(f"{get_hello_hour()}! Добро пожаловать в систему банка!")
|
print(f"{get_hello_hour()}! Добро пожаловать в систему банка!")
|
||||||
name = input("Ваш логин: ")
|
name = input("Ваш логин: ")
|
||||||
password = getpass("Введите пароль: ")
|
password = getpass("Введите пароль: ")
|
||||||
@ -178,20 +210,42 @@ def login():
|
|||||||
users = Users()
|
users = Users()
|
||||||
user = users.authenticate(name, password)
|
user = users.authenticate(name, password)
|
||||||
if user:
|
if user:
|
||||||
print("Вы успешно вошли в систему!")
|
print(f"Вы успешно вошли в систему, {user.fio}!")
|
||||||
else:
|
else:
|
||||||
print("Ошибка: Неправильный логин или пароль!")
|
print("Ошибка: Неправильный логин или пароль!")
|
||||||
exit(1)
|
return None
|
||||||
|
session["user"] = user
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
def logout():
|
||||||
|
"""Выход пользователя"""
|
||||||
|
|
||||||
|
if "user" not in session:
|
||||||
|
print("Для того чтобы выйти из системы, сначала нужно в неё войти :)")
|
||||||
|
return
|
||||||
|
|
||||||
|
user = session["user"]
|
||||||
|
del session["user"]
|
||||||
|
print(f"До новых встреч, {user.fio}!")
|
||||||
|
|
||||||
|
|
||||||
def user_verification():
|
def user_verification():
|
||||||
|
"""Идентификация пользователя"""
|
||||||
|
|
||||||
user = login()
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if user.is_verifyed:
|
||||||
|
print("Вы уже идентифцированы!")
|
||||||
|
return
|
||||||
|
|
||||||
users = Users()
|
users = Users()
|
||||||
code = int(input("Введите код идентификации: "))
|
code = int(input("Введите код идентификации: "))
|
||||||
res = user.email_verification(code)
|
res = user.email_verification(code)
|
||||||
if res:
|
if res:
|
||||||
print("Вы успешно идентивицированы!")
|
print("Вы успешно идентифицированы!")
|
||||||
users.db.commit()
|
users.db.commit()
|
||||||
else:
|
else:
|
||||||
print("К сожалению код не подходит!")
|
print("К сожалению код не подходит!")
|
||||||
@ -200,52 +254,82 @@ def user_verification():
|
|||||||
fake_email_send(user.email, user.verification_code)
|
fake_email_send(user.email, user.verification_code)
|
||||||
user.save()
|
user.save()
|
||||||
print(
|
print(
|
||||||
"На Ваш email отправлен код идентификации (создан файл в текущей папке с именем=email)"
|
f"На Ваш email отправлен код идентификации!\n\t(создан файл в текущей папке с именем={user.email})"
|
||||||
)
|
)
|
||||||
users.db.commit()
|
users.db.commit()
|
||||||
exit(0)
|
|
||||||
else:
|
else:
|
||||||
exit(1)
|
print("Выход")
|
||||||
|
|
||||||
|
|
||||||
def open_account():
|
def open_account():
|
||||||
|
"""Открытие счета"""
|
||||||
|
|
||||||
user = login()
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
db = SimpleDataBase()
|
db = SimpleDataBase()
|
||||||
if user.name in db.accounts:
|
if user.name in db.accounts:
|
||||||
print("Счет уже открыт")
|
print("Счет уже открыт")
|
||||||
exit(1)
|
return
|
||||||
db.accounts[user.name] = 0
|
db.accounts[user.name] = 0
|
||||||
db.commit()
|
db.commit()
|
||||||
print("Счет успешно открыт")
|
print("Счет успешно открыт")
|
||||||
|
|
||||||
|
|
||||||
def print_account_balance():
|
def print_account_details():
|
||||||
|
"""Информация о пользователе"""
|
||||||
|
|
||||||
user = login()
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n - - - ")
|
||||||
|
print("Ваше ФИО:", user.fio)
|
||||||
|
print("Ваш email:", user.email)
|
||||||
|
print(
|
||||||
|
"Ваш статус:", user.is_verifyed and "Идентифицирован" or "Ожидает идентификации"
|
||||||
|
)
|
||||||
|
|
||||||
db = SimpleDataBase()
|
db = SimpleDataBase()
|
||||||
if user.name not in db.accounts:
|
if user.name not in db.accounts:
|
||||||
print("Счет не открыт")
|
print("Счет не открыт")
|
||||||
exit(1)
|
else:
|
||||||
balance = round(db.accounts[user.name] / 100, 2)
|
balance = round(db.accounts[user.name] / 100, 2)
|
||||||
print(f"На балансе: {balance} руб.")
|
print(f"На балансе: {balance} руб.")
|
||||||
|
|
||||||
|
if user.name not in db.rating:
|
||||||
|
print("У Вас ещё нет рейтинга")
|
||||||
|
else:
|
||||||
|
print(f"Ваш рейтинг: {db.rating[user.name]} баллов")
|
||||||
|
|
||||||
|
print("\n - - - ")
|
||||||
|
|
||||||
|
|
||||||
def addition_from_card():
|
def addition_from_card():
|
||||||
|
"""Пополнение баланса с карты"""
|
||||||
|
|
||||||
user = login()
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
db = SimpleDataBase()
|
db = SimpleDataBase()
|
||||||
|
|
||||||
if user.name not in db.accounts:
|
if user.name not in db.accounts:
|
||||||
print("Сначала нужно открыть счет")
|
print("Сначала нужно открыть счет")
|
||||||
exit(2)
|
return
|
||||||
|
|
||||||
is_valid = False
|
is_valid = False
|
||||||
while not is_valid:
|
while not is_valid:
|
||||||
card = input("Введите номер карты: ")
|
card = input("Введите номер карты: ")
|
||||||
is_valid = validate_credit_card(card)
|
is_valid = validate_credit_card(card)
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
|
print("Номер не правильный")
|
||||||
if "да" != input("Введите да, чтобы попытаться ещё раз: "):
|
if "да" != input("Введите да, чтобы попытаться ещё раз: "):
|
||||||
break
|
break
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
exit(1)
|
print("Выход")
|
||||||
|
return
|
||||||
|
|
||||||
amount = float(input("Введите сумму пополнения: "))
|
amount = float(input("Введите сумму пополнения: "))
|
||||||
# рубли и копейки комбинируем в int, чтобы избежать проблем с float
|
# рубли и копейки комбинируем в int, чтобы избежать проблем с float
|
||||||
@ -256,12 +340,17 @@ def addition_from_card():
|
|||||||
|
|
||||||
|
|
||||||
def payment_for_phone():
|
def payment_for_phone():
|
||||||
|
"""Оплата мобильного телефона"""
|
||||||
|
|
||||||
user = login()
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
db = SimpleDataBase()
|
db = SimpleDataBase()
|
||||||
|
|
||||||
if user.name not in db.accounts:
|
if user.name not in db.accounts:
|
||||||
print("Сначала нужно открыть счет")
|
print("Сначала нужно открыть счет")
|
||||||
exit(2)
|
return
|
||||||
|
|
||||||
phone = input("Введите номер телефона: ")
|
phone = input("Введите номер телефона: ")
|
||||||
# TODO: Валидация номера телефона
|
# TODO: Валидация номера телефона
|
||||||
@ -274,7 +363,142 @@ def payment_for_phone():
|
|||||||
print("Платеж выполнен успешно, деньги (типа) отправлены на номер", phone)
|
print("Платеж выполнен успешно, деньги (типа) отправлены на номер", phone)
|
||||||
|
|
||||||
|
|
||||||
# TODO: пункт 7
|
def quiz():
|
||||||
# TODO: пункт 8
|
"""Рейтинговая викторина"""
|
||||||
# TODO: пункт 9
|
|
||||||
# TODO: main
|
print(' (тема: "Финансовая грамотность")')
|
||||||
|
questions = [
|
||||||
|
(
|
||||||
|
"""Финансовую защиту благосостояния семьи обеспечивает капитал:
|
||||||
|
а) резервный
|
||||||
|
б) текущий
|
||||||
|
в) инвестиционный""",
|
||||||
|
"а",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""В соответствии с законом о страховании вкладчик получит право на возмещение по своим вкладам в банке в случае:
|
||||||
|
а) потери доверия к банку у населения
|
||||||
|
б) отзыва у банка лицензии
|
||||||
|
в) повышения инфляции""",
|
||||||
|
"б",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Инфляция:
|
||||||
|
а) повышение заработной платы бюджетникам
|
||||||
|
б) повышение покупательной способности денег
|
||||||
|
в) снижение покупательной способности денег""",
|
||||||
|
"в",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Кредит, выдаваемый под залог объекта, который приобретается (земельный участок, дом, квартира), называется:
|
||||||
|
а) ипотечный
|
||||||
|
б) потребительский
|
||||||
|
в) целевой""",
|
||||||
|
"а",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Счет до востребования с минимальной процентной ставкой, то есть текущий счет, открывается для карты:
|
||||||
|
а) кредитной
|
||||||
|
б) дебетовой с овердрафтом
|
||||||
|
в) дебетовой""",
|
||||||
|
"в",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Фондовый рынок — это место, где:
|
||||||
|
а) продаются и покупаются строительные материалы
|
||||||
|
б) продаются и покупаются ценные бумаги
|
||||||
|
в) продаются и покупаются продукты питания""",
|
||||||
|
"б",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Биржа — это место, где:
|
||||||
|
а) продаются и покупаются автомобили
|
||||||
|
б) продаются и покупаются ценные бумаги
|
||||||
|
в) место заключения сделок между покупателями и продавцами""",
|
||||||
|
"в",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Страховые выплаты компенсируются в случае:
|
||||||
|
а) материального ущерба
|
||||||
|
б) морального ущерба
|
||||||
|
в) желания страхователя получить прибыль""",
|
||||||
|
"а",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Выплачиваемая нынешним пенсионерам и формируемая пенсионерам будущим трудовая пенсия по старости, выплачиваемая государством:
|
||||||
|
а) добавочная
|
||||||
|
б) второстепенная
|
||||||
|
в) базовая""",
|
||||||
|
"в",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"""Выплачиваемая нынешним пенсионерам и формируемая пенсионерам будущим трудовая пенсия по старости, выплачиваемая государством:
|
||||||
|
а) главная
|
||||||
|
б) накопительная
|
||||||
|
в) дополнительная""",
|
||||||
|
"б",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
user = login()
|
||||||
|
if user is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
db = SimpleDataBase()
|
||||||
|
|
||||||
|
if user.name in db.rating:
|
||||||
|
print(f"Ваш текущий рейтинг: {db.rating[user.name]} баллов")
|
||||||
|
if "выход" == input("Введите 'выход', для того чтобы выйти из тестирования: "):
|
||||||
|
return
|
||||||
|
|
||||||
|
score = 0
|
||||||
|
random.shuffle(questions)
|
||||||
|
for question, q_answer in questions:
|
||||||
|
print("- - - - - - - - - - - -\n")
|
||||||
|
print(f"Вопрос: \n{question}\n")
|
||||||
|
answer = input("Ваш ответ: ")
|
||||||
|
if answer.strip().lower() == q_answer.strip().lower():
|
||||||
|
print(f"Верно")
|
||||||
|
score += 1
|
||||||
|
else:
|
||||||
|
print("Не верно")
|
||||||
|
|
||||||
|
print(f"Результат: {score} балла")
|
||||||
|
old_rating = db.rating.get(user.name, 0)
|
||||||
|
if old_rating < score:
|
||||||
|
db.rating[user.name] = score
|
||||||
|
print(f"Ваш рейтинг обновлен и составляет: {score} балла")
|
||||||
|
db.commit()
|
||||||
|
else:
|
||||||
|
print("Вы набрали меньший балл, и ваш рейтинг оставлен без изменений")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
modes = [
|
||||||
|
registration,
|
||||||
|
login,
|
||||||
|
print_account_details,
|
||||||
|
open_account,
|
||||||
|
user_verification,
|
||||||
|
addition_from_card,
|
||||||
|
payment_for_phone,
|
||||||
|
quiz,
|
||||||
|
logout,
|
||||||
|
]
|
||||||
|
while True:
|
||||||
|
print("Выберите режим:")
|
||||||
|
for i, func in enumerate(modes, 1):
|
||||||
|
print(f"{i} - {func.__doc__}")
|
||||||
|
print(" [ Для выхода введите любую другую строку или нажмите Ввод ] ")
|
||||||
|
i = input("Ваш выбор: ")
|
||||||
|
if not i.isdigit() or not 0 < int(i) <= len(modes):
|
||||||
|
print("Выход")
|
||||||
|
return
|
||||||
|
mode = modes[int(i) - 1]
|
||||||
|
print(f"Режим: {mode.__doc__}")
|
||||||
|
mode()
|
||||||
|
|
||||||
|
|
||||||
|
# не пишу тут if __name__ == "__main__":
|
||||||
|
# чтобы можно было вставить например в ipython или ptpython и т.д.
|
||||||
|
main()
|
||||||
|
Loading…
Reference in New Issue
Block a user