diff --git a/hw_4/.idea/.gitignore b/hw_4/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/hw_4/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/hw_4/.idea/.name b/hw_4/.idea/.name
new file mode 100644
index 0000000..11a5d8e
--- /dev/null
+++ b/hw_4/.idea/.name
@@ -0,0 +1 @@
+main.py
\ No newline at end of file
diff --git a/hw_4/.idea/hw_4.iml b/hw_4/.idea/hw_4.iml
new file mode 100644
index 0000000..2c80e12
--- /dev/null
+++ b/hw_4/.idea/hw_4.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw_4/.idea/inspectionProfiles/profiles_settings.xml b/hw_4/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/hw_4/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw_4/.idea/misc.xml b/hw_4/.idea/misc.xml
new file mode 100644
index 0000000..a0c5da8
--- /dev/null
+++ b/hw_4/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw_4/.idea/modules.xml b/hw_4/.idea/modules.xml
new file mode 100644
index 0000000..7bc33cf
--- /dev/null
+++ b/hw_4/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw_4/.idea/vcs.xml b/hw_4/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/hw_4/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/hw_4/account.csv b/hw_4/account.csv
new file mode 100644
index 0000000..4acb96d
--- /dev/null
+++ b/hw_4/account.csv
@@ -0,0 +1,6 @@
+user_id,type,account_number,bank_id,currency,amount,status
+1,credit,ID--dcd-123568744-,3,USD,1000,gold
+3,debit,ID--xyz-987654-uvw,2,USD,500,silver
+2,credit,ID--qwe-456789-asd,5,EUR,800,platinum
+2,debit,ID--z1-654321-xyz,4,CAD,1200,gold
+4,credit,ID--jkl-987654-mno,1,USD,1500,silver
\ No newline at end of file
diff --git a/hw_4/api.py b/hw_4/api.py
new file mode 100644
index 0000000..645988e
--- /dev/null
+++ b/hw_4/api.py
@@ -0,0 +1,349 @@
+import requests
+import csv
+import validate
+from db_con_decor import db_connection
+import os
+from dotenv import load_dotenv, find_dotenv
+import logging
+from consts import URL
+from datetime import datetime, timedelta
+import random
+
+formatter = logging.Formatter('%(asctime)s:%(levelname)s:%(name)s:%(message)s')
+my_logger = logging.getLogger('CustomLogger')
+my_handler = logging.FileHandler('file.log')
+my_handler.setFormatter(formatter)
+my_logger.setLevel(logging.INFO)
+my_logger.addHandler(my_handler)
+
+load_dotenv(find_dotenv())
+
+
+# gets dict from currencies and their values relative to the dollar
+def get_currency_data():
+
+ response = requests.get(URL.format(os.getenv('API_KEY')))
+ if response.status_code == requests.codes.ok:
+ data = response.json()
+ # make logs
+ my_logger.info("data_get successfully")
+ my_logger.info(data['data'])
+ return data['data']
+ my_logger.error("data_get failure")
+ return None
+
+
+# reads csv file converted to dict
+def read_csv_to_dict(file_path):
+ with open(file_path, 'r') as file:
+ return list(csv.DictReader(file))
+
+
+def unpack_data(data):
+ keys = list(data.keys())
+ return [data[key] for key in keys] if len(keys) > 1 else data[keys[0]]
+
+
+# { filler_date: [{}, {} ]}
+# { "row1": {}, "row2": {} }
+# fills the table bank
+@db_connection
+def add_bank(cur, **kwargs):
+ data = unpack_data(kwargs)
+ my_logger.info(data)
+ # unpack the mass of dicts
+ my_logger.info(data)
+ cur.executemany("INSERT INTO Bank(name) VALUES(:Name)", data) # :param_name, :param_name2
+ my_logger.info("Bank added successfully.")
+
+
+# fills the table user
+@db_connection
+def add_user(cur, **kwargs):
+ data = unpack_data(kwargs)
+ my_logger.info(data)
+ for i in data:
+ i["name"] = validate.validate_user_full_name(i["user_name"])[0]
+ i["surname"] = validate.validate_user_full_name(i["user_name"])[1]
+ cur.executemany("INSERT INTO User(name,surname,birth_day,accounts) VALUES(:name ,:surname,:birthday,:accounts)",
+ data)
+ my_logger.info("User added successfully.")
+
+
+def unpack_to_string(data):
+ result = ''
+ for tup in data:
+ for item in tup:
+ result += str(item) + ','
+ return result.rstrip(',')
+
+
+# fills the table account
+def set_accounts(cur, data):
+ for i in data:
+ cur.execute("SELECT id FROM Account WHERE user_id = ?", (i["user_id"],))
+ numb_of_acc = cur.fetchall()
+ account_str = unpack_to_string(numb_of_acc)
+ my_logger.info(account_str)
+ cur.execute("UPDATE User SET Accounts = ? WHERE id = ?", (account_str, i["user_id"],))
+
+
+@db_connection
+def add_account(cur, **kwargs):
+ data = unpack_data(kwargs)
+ my_logger.info(data)
+ validate.valid_acc(data)
+ cur.executemany('''INSERT INTO Account(user_id, type, account_number, bank_id, currency, amount, status)
+ VALUES(:user_id,:type,:account_number,:bank_id,:currency,:amount,:status)''',
+ data)
+ set_accounts(cur, data)
+ my_logger.info("account added successfully.")
+
+
+# update row in bd
+@db_connection
+def update_row(c, table_name, row_id, column, value):
+ c.execute(f"UPDATE {table_name} SET {column} = ? WHERE id = ?", (value, row_id, ))
+ return "success"
+
+
+@db_connection
+def delete_row(cur, row_id, fnc):
+ match fnc:
+ case "User":
+ cur.execute("DELETE FROM Account WHERE user_id = ?", (row_id,))
+ cur.execute("DELETE FROM User WHERE id = ?", (row_id,))
+ case "Bank":
+ cur.execute("DELETE FROM Account WHERE bank_id = ?", (row_id,))
+ cur.execute("DELETE FROM Bank WHERE id = ?", (row_id,))
+ case "Account":
+ cur.execute("DELETE FROM Account WHERE id = ?", (row_id,))
+ my_logger.info(f"{fnc} delete successfully.")
+ return "success"
+
+
+# it just clears the tables in the database
+@db_connection
+def clear_table(cur, table_name):
+ cur.execute(f"DELETE FROM {table_name}")
+ return 'success'
+
+
+def add_table_by_file(path, table_name):
+ data = read_csv_to_dict(path)
+ match table_name:
+ case "Bank":
+ add_bank(table_filler=data)
+ case "User":
+ add_user(table_filler=data)
+ case "Account":
+ add_account(table_filler=data)
+
+
+def convert_currency(currency_values, orig_currency, conv_currency, amount):
+ return round((amount / currency_values[orig_currency]) * currency_values[conv_currency], 2)
+
+
+def get_bankname(id_user):
+ bank_id = get_data_from_table(table_name="Account", row_name="bank_id", row_id=id_user)
+ my_logger.info("get_bankname successfully.")
+ return get_data_from_table(table_name="Bank", row_name="name", row_id=bank_id)
+
+
+@db_connection
+def get_data_from_table(cur, row_name, table_name, row_id):
+ cur.execute(f"SELECT {row_name} FROM {table_name} WHERE id = ? ", (row_id,))
+ return cur.fetchone()[0]
+
+
+@db_connection
+def insert_transaction(cur, bank_sender_name, sender_id, bank_receiver_name,
+ receiver_id, sender_currency, sent_amount, transfer_time):
+ cur.execute('''
+ INSERT INTO BankTransaction
+ (bank_sender_name, account_sender_id,
+ bank_receiver_name, account_receiver_id,
+ sent_currency, sent_amount, datetime)
+ VALUES(?,?,?,?,?,?,?)''',
+ (bank_sender_name, sender_id,
+ bank_receiver_name, receiver_id,
+ sender_currency, sent_amount, transfer_time,))
+
+
+def transfer_money(sender_id, receiver_id, sent_amount, transfer_time=None):
+ currency_dict = get_currency_data()
+ my_logger.info('valid current success')
+ # pull the necessary data to fill the transaction table
+ bank_sender_name = get_bankname(sender_id)
+ bank_receiver_name = get_bankname(receiver_id)
+ sender_amount = get_data_from_table("Amount", "Account", sender_id)
+ receiver_amount = get_data_from_table("Amount", "Account", receiver_id)
+ sender_currency = get_data_from_table("Currency", "Account", sender_id)
+ receiver_currency = get_data_from_table("Currency", "Account", receiver_id)
+ sent_am_in_sender_cur = sent_amount
+
+ if sender_amount <= sent_amount:
+ raise ValueError("not enough money in the account")
+ if receiver_currency != sender_currency:
+ sent_am_in_sender_cur = convert_currency(currency_dict, receiver_currency, sender_currency, sent_amount)
+
+ # check the time
+ transfer_time = validate.add_transaction_time(transfer_time)
+
+ new_sender_amount = sender_amount - sent_am_in_sender_cur
+ new_receiver_amount = receiver_amount + sent_am_in_sender_cur
+
+ # change the sum values of the users
+ update_row("Account", sender_id, "amount", round(new_sender_amount, 2))
+ update_row("Account", receiver_id, "amount", round(new_receiver_amount, 2))
+
+ # fill the table
+ insert_transaction(bank_sender_name, sender_id, bank_receiver_name, receiver_id,
+ sender_currency, sent_amount, transfer_time)
+ my_logger.info("success")
+ return "success"
+
+
+@db_connection
+def select_random_users_with_discounts(cursor):
+ cursor.execute("SELECT Id FROM User")
+ all_users = cursor.fetchall()
+ random_users = random.sample(all_users, min(10, len(all_users))) # Randomly select up to 10 users
+ user_discounts = {}
+ for user_id in random_users:
+ discount = random.choice([25, 30, 50]) # Randomly choose discount
+ user_discounts[user_id[0]] = discount
+ my_logger.info(user_discounts)
+ my_logger.info("select_random_users_with_discounts success")
+ return user_discounts
+
+
+@db_connection
+def user_with_highest_amount(cursor):
+ cursor.execute('''
+ SELECT User_id
+ FROM Account
+ ORDER BY Amount DESC
+ LIMIT 1
+ ''')
+ user_id = cursor.fetchone()[0]
+ name = get_data_from_table("name", "User", user_id)
+ my_logger.info(name)
+ my_logger.info("user_with_highest_amount success")
+ return name
+
+
+@db_connection
+def bank_with_biggest_capital(cursor):
+ currency_dict = get_currency_data()
+ # Extract all records from the Account table
+ cursor.execute("SELECT Bank_id, Currency, Amount FROM Account")
+ accounts = cursor.fetchall()
+
+ # Create a dictionary to store total capital for each bank in dollars
+ bank_capital = {}
+
+ # Create a dictionary to store the total capital for each bank in dollars
+ for bank_id, currency, amount in accounts:
+ amount_in_usd = convert_currency(currency_dict, currency, 'USD', amount)
+ if bank_id in bank_capital:
+ bank_capital[bank_id] += amount_in_usd
+ else:
+ bank_capital[bank_id] = amount_in_usd
+
+ # Find the bank with the most capital
+ max_capital_bank_id = max(bank_capital, key=bank_capital.get)
+ my_logger.info(f"max capital bank id {max_capital_bank_id}")
+ my_logger.info("bank_with_biggest_capital success")
+ return max_capital_bank_id
+
+
+@db_connection
+def bank_serving_oldest_client(cursor):
+ cursor.execute("SELECT Id, Birth_day FROM User")
+ users = cursor.fetchall()
+
+ cursor.execute("SELECT User_id, Bank_id FROM Account")
+ accounts = cursor.fetchall()
+
+ # Find the oldest user
+ oldest_user_id = None
+ oldest_birth_day = datetime.max
+
+ for user_id, birth_day in users:
+ birth_date = datetime.strptime(birth_day, '%Y-%m-%d')
+ if birth_date < oldest_birth_day:
+ oldest_birth_day = birth_date
+ oldest_user_id = user_id
+
+ # Find the bank that owns the oldest user
+ for user_id, bank_id in accounts:
+ if user_id == oldest_user_id:
+ return bank_id
+
+
+@db_connection
+def print_table(cursor, table_name):
+ cursor.execute(f"PRAGMA table_info({table_name})")
+ column_names = [row[1] for row in cursor.fetchall()]
+ cursor.execute(f"SELECT * FROM {table_name}")
+ rows = cursor.fetchall()
+
+ print(", ".join(column_names))
+ for row in rows:
+ print(", ".join(map(str, row)))
+
+
+@db_connection
+def bank_with_highest_unique_users(cursor):
+ # Create a dictionary to store the number of unique users for each bank
+ unique_users_by_bank = {}
+
+ # Select all transactions from the BankTransaction table
+ cursor.execute("SELECT Bank_sender_name, Account_sender_id FROM BankTransaction")
+ transactions = cursor.fetchall()
+
+ # Count the number of unique users for each bank
+ for bank_name, account_id in transactions:
+ if bank_name not in unique_users_by_bank:
+ unique_users_by_bank[bank_name] = set()
+ unique_users_by_bank[bank_name].add(account_id)
+
+ # Find the bank with the unique users
+ bank_with_highest_users = max(unique_users_by_bank.items(), key=lambda x: len(x[1]))
+
+ return bank_with_highest_users[0]
+
+
+@db_connection
+def delete_users_with_incomplete_info(cursor):
+ while True:
+ cursor.execute("SELECT id FROM User WHERE Name IS NULL OR Surname IS NULL OR Birth_day IS NULL")
+ result = cursor.fetchone()
+ if result is None:
+ break
+ deleted_user_id = result[0]
+ cursor.execute("DELETE FROM Account WHERE User_id = ?", (deleted_user_id,))
+ cursor.execute("DELETE FROM User WHERE id = ?", (deleted_user_id,))
+ return "Deletion complete"
+
+
+@db_connection
+def get_user_transactions(c, user_id):
+
+ # Calculate the date three months ago from today
+ end_date = datetime.now()
+ start_date = end_date - timedelta(days=90)
+
+ # Convert dates to string format for SQL query
+ start_date_str = start_date.strftime('%Y-%m-%d %H:%M:%S')
+ end_date_str = end_date.strftime('%Y-%m-%d %H:%M:%S')
+
+ query = '''
+ SELECT * FROM BankTransaction
+ WHERE (Account_sender_id = ? OR Account_receiver_id = ?)
+ AND Datetime BETWEEN ? AND ?
+ '''
+ c.execute(query, (user_id, user_id, start_date_str, end_date_str))
+ return c.fetchall()
+
\ No newline at end of file
diff --git a/hw_4/bank.csv b/hw_4/bank.csv
new file mode 100644
index 0000000..a31bfa9
--- /dev/null
+++ b/hw_4/bank.csv
@@ -0,0 +1,11 @@
+Name
+Bank of America
+Wells Fargo
+Chase Bank
+Citibank
+HSBC
+TD Bank
+PNC Bank
+Capital One
+US Bank
+BB&T
diff --git a/hw_4/bank.db b/hw_4/bank.db
new file mode 100644
index 0000000..c7d0bcd
Binary files /dev/null and b/hw_4/bank.db differ
diff --git a/hw_4/consts.py b/hw_4/consts.py
new file mode 100644
index 0000000..7a48541
--- /dev/null
+++ b/hw_4/consts.py
@@ -0,0 +1 @@
+URL = 'https://api.freecurrencyapi.com/v1/latest?apikey={}'
diff --git a/hw_4/db_con_decor.py b/hw_4/db_con_decor.py
new file mode 100644
index 0000000..bf97651
--- /dev/null
+++ b/hw_4/db_con_decor.py
@@ -0,0 +1,44 @@
+import sqlite3
+from functools import wraps
+
+
+def db_connection(func):
+ """
+ Декоратор для установки соединения с базой данных и его закрытия после выполнения функции.
+
+ Args:
+ func (function): Функция базы данных, которая будет выполнена.
+
+ Returns:
+ function: Вложенная функция-обертка, которая обеспечивает соединение и закрытие.
+ """
+ # не работает
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ """
+ Вложенная функция-обертка, обеспечивающая соединение и закрытие.
+
+ Args:
+ *args: Позиционные аргументы, переданные в функцию.
+ **kwargs: Именованные аргументы, переданные в функцию.
+
+ Returns:
+ any: Результат выполнения оригинальной функции.
+ """
+ # Устанавливаем соединение с базой данных
+ conn = sqlite3.connect('bank.db')
+ # Создаем объект курсора
+ c = conn.cursor()
+ result = None
+ try:
+ # Вызываем оригинальную функцию, передавая ей курсор и все переданные аргументы
+ result = func(c, *args, **kwargs)
+ except Exception as e:
+ # Обрабатываем ошибки и логируем их
+ print(f"Error: {str(e)}")
+ finally:
+ conn.commit()
+ conn.close()
+ return result
+ # Возвращаем вложенную функцию-обертку в качестве декоратора
+ return wrapper
diff --git a/hw_4/example.csv b/hw_4/example.csv
new file mode 100644
index 0000000..1cd6798
--- /dev/null
+++ b/hw_4/example.csv
@@ -0,0 +1,5 @@
+full_name,birth_day,accounts
+John Doe,1990-05-15,3
+Alice Smith,1985-10-20,5
+Michael Johnson,1978-03-25,2
+Emily Brown,1992-07-12,4
diff --git a/hw_4/initial_db_setup.py b/hw_4/initial_db_setup.py
new file mode 100644
index 0000000..da0c335
--- /dev/null
+++ b/hw_4/initial_db_setup.py
@@ -0,0 +1,47 @@
+import sqlite3
+
+
+def create_database(unique_name=True, unique_surname=True):
+ # Establishing a connection to the database
+ conn = sqlite3.connect('bank.db')
+ c = conn.cursor()
+
+ # Create table Bank
+ c.execute('''CREATE TABLE IF NOT EXISTS Bank (
+ id INTEGER PRIMARY KEY,
+ name TEXT NOT NULL UNIQUE)''')
+
+ # Create table BankTransaction
+ c.execute('''CREATE TABLE IF NOT EXISTS BankTransaction (
+ id INTEGER PRIMARY KEY,
+ Bank_sender_name TEXT NOT NULL,
+ Account_sender_id INTEGER NOT NULL,
+ Bank_receiver_name TEXT NOT NULL,
+ Account_receiver_id INTEGER NOT NULL,
+ Sent_Currency TEXT NOT NULL,
+ Sent_Amount REAL NOT NULL,
+ Datetime TEXT)''')
+
+ # Create table User
+ name_uniq = "UNIQUE" if unique_name else ""
+ surname_uniq = "UNIQUE" if unique_surname else ""
+ c.execute(f'''CREATE TABLE IF NOT EXISTS User (
+ Id INTEGER PRIMARY KEY,
+ Name TEXT NOT NULL {name_uniq},
+ Surname TEXT NOT NULL {surname_uniq},
+ Birth_day TEXT,
+ Accounts INTEGER NOT NULL)''')
+
+ # Create table Account
+ c.execute('''CREATE TABLE IF NOT EXISTS Account (
+ Id INTEGER PRIMARY KEY,
+ User_id INTEGER NOT NULL,
+ Type TEXT NOT NULL,
+ Account_Number TEXT NOT NULL UNIQUE,
+ Bank_id INTEGER NOT NULL,
+ Currency TEXT NOT NULL,
+ Amount REAL NOT NULL,
+ Status TEXT)''')
+
+ conn.commit()
+ conn.close()
diff --git a/hw_4/main.py b/hw_4/main.py
new file mode 100644
index 0000000..e93ffdc
--- /dev/null
+++ b/hw_4/main.py
@@ -0,0 +1,68 @@
+import argparse
+import api
+import initial_db_setup
+
+
+def init_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--add_path', type=str)
+ parser.add_argument('--table_name', type=str)
+ parser.add_argument('--row_id', type=int)
+ parser.add_argument('--column', type=str)
+ parser.add_argument('--value', type=str)
+ parser.add_argument('--delete_row_id', type=int)
+ parser.add_argument('--sender_id', type=int)
+ parser.add_argument('--receiver_id', type=int)
+ parser.add_argument('--sent_currency', type=str)
+ parser.add_argument('--sent_amount', type=int)
+ parser.add_argument('--time', type=str)
+ parser.add_argument('--clear_table', type=str)
+ parser.add_argument('--random_disc', type=str)
+ parser.add_argument('--highest_amount', type=str)
+ parser.add_argument('--bank_with_biggest_capital', type=str)
+ parser.add_argument('--bank_with_highest_unique_users', type=str)
+ parser.add_argument('--get_user_transactions', type=int)
+ parser.add_argument('--print_table', type=str)
+ parser.add_argument('--delete_incomplete', type=str)
+ args = parser.parse_args()
+
+ return args
+
+
+def do_func_with_args(args):
+ # to be able to perform multiple functions
+ if args.add_path and args.table_name:
+ api.add_table_by_file(args.add_path, args.table_name)
+ if args.table_name and args.row_id and args.column and args.value:
+ api.update_row(args.table_name, args.row_id, args.column, args.value)
+ if args.clear_table:
+ api.clear_table(args.clear_table)
+ if args.delete_row_id and args.table_name:
+ api.delete_row(args.delete_row_id, args.table_name)
+ if args.sender_id and args.receiver_id and args.sent_amount:
+ api.transfer_money(args.sender_id, args.receiver_id, args.sent_amount)
+ if args.sender_id and args.receiver_id and args.sent_amount and args.time:
+ api.transfer_money(args.sender_id, args.receiver_id, args.sent_amount, args.time)
+ if args.random_disc:
+ print(api.select_random_users_with_discounts())
+ if args.highest_amount:
+ print(api.user_with_highest_amount())
+ if args.bank_with_biggest_capital:
+ print(api.bank_with_biggest_capital())
+ if args.bank_with_highest_unique_users:
+ print(api.bank_with_highest_unique_users())
+ if args.get_user_transactions:
+ print(api.get_user_transactions())
+ if args.print_table:
+ api.print_table(args.print_table)
+ if args.delete_incomplete:
+ print(api.delete_users_with_incomplete_info())
+
+
+def main():
+ initial_db_setup.create_database()
+ do_func_with_args(init_args())
+
+
+if __name__ == "__main__":
+ main()
diff --git a/hw_4/user.csv b/hw_4/user.csv
new file mode 100644
index 0000000..9349b6c
--- /dev/null
+++ b/hw_4/user.csv
@@ -0,0 +1,6 @@
+user_name,birthday,accounts
+John1!! Doe,1990-05-05,0
+Jane Smith,1985-10-15,0
+Michael Johnson,1978-03-20,0
+Emily Brown,1995-08-08,0
+Alex Rodriguez,1982-12-30,0
\ No newline at end of file
diff --git a/hw_4/validate.py b/hw_4/validate.py
new file mode 100644
index 0000000..8a9e574
--- /dev/null
+++ b/hw_4/validate.py
@@ -0,0 +1,52 @@
+import re
+from datetime import datetime
+
+
+# Validation of user_full_name field
+def validate_user_full_name(user_full_name):
+ # Delete all characters that are not letters
+ user_full_name = re.sub(r'[^a-zA-Z\s]', '', user_full_name)
+ # Separate first and last name by any whitespace characters
+ name, surname = user_full_name.strip().split(maxsplit=1)
+ return name, surname
+
+
+# Validation of fields with a strict set of values
+def validate_field_value(field, value, allowed_values):
+ if value not in allowed_values:
+ raise ValueError("error: not allowed value {} for field {}!".format(value, field))
+
+def valid_acc(data):
+ type_values = ["credit", "debit"]
+ status_values = ["gold", "silver", "platinum"]
+ for i in data:
+ validate_field_value("type", i["type"], type_values)
+ validate_field_value("status", i["status"], status_values)
+ return True
+
+def validate_account_number(account_number):
+ # Replacing special characters with dashes
+ account_number = re.sub(r'[#%_?&]', '-', account_number)
+
+ # Character count check
+ if len(account_number) < 18:
+ raise ValueError("error: too little")
+ if len(account_number) > 18:
+ raise ValueError("error: many chars")
+
+ # Checking the format
+ if not account_number.startswith("ID--"):
+ raise ValueError("error: wrong format")
+
+ # Checking for the right pattern
+ if not re.match(r'ID--[a-zA-Z]{1,3}-\d+-', account_number):
+ raise ValueError("an error: broken ID")
+
+ return account_number
+
+
+# Function for checking and adding transaction time
+def add_transaction_time(transaction_time):
+ if not transaction_time:
+ transaction_time = datetime.now()
+ return transaction_time