Beispiel #1
0
    def __init__(self, config: Optional[str] = None):
        create_db()
        fill_db()

        # parse config if exists
        try:
            _config_path = Path(config)
            with open(_config_path) as file:
                _config = yaml.safe_load(file)["config"]
        except TypeError:
            LOGGER.INFO("No config file specified. Falling back to default")
            _config = {}
        except FileNotFoundError:
            LOGGER.INFO("Config file not found. Falling back to default")
            _config = {}

        self.name = _config.get("name", "BankLite")  # defaults to BankLite
        self.currency = _config.get("currency", "USD")  # defaults to USD
        self.initial_reserve = _config.get("initial_reserve", 1e9)  # defaults to 1 billion

        self.conn = sqlite3.connect("banklite.db", check_same_thread=False)

        # main services
        self.ledger_service = LedgerService(conn=self.conn)
        self.account_service = AccountService(conn=self.conn)
        self.customer_service = CustomerService(conn=self.conn)

        # create reserve account
        self.reserve_account = self.account_service.create_reserve_account()

        # fill reserve with initial deposit
        self.ledger_service.record_entry(
            account=self.reserve_account, amount=self.initial_reserve
        )
Beispiel #2
0
    def create_commercial_customer(self, customer_zip: int, phone_number: str,
                                   email: str, ein: str,
                                   name: str) -> CommercialCustomer:
        """

        :param customer_zip: Customer's zip code of operation
        :param phone_number: Customer's main office or financial office number
        :param email: Customer's main office of financial office email
        :param ein: Customer's EIN
        :param name: Customer's operating name
        """
        customer = CommercialCustomer(create_id(), customer_zip, phone_number,
                                      email, ein, name)

        if self.customer_exists(customer):
            return self.get_customer_by_id(customer.customer_id)

        LOGGER.INFO("CustomerCreation(customer_id=%s)", customer.customer_id)
        self.conn.execute(f"""
            INSERT INTO customers
            VALUES ({customer.customer_id}, DATETIME('now'), '{customer.ein}',
            NULL, '{customer.first_name}', NULL, '{customer.zip}',
            '{customer.phone}', '{customer.email}')
            """)
        self.conn.commit()
        return customer
Beispiel #3
0
    def create_retail_customer(
        self,
        customer_zip: int,
        phone_number: str,
        email: str,
        ssn: str,
        first_name: str,
        last_name: str,
    ) -> RetailCustomer:
        """
        Creates a customer entry according to information passed in

        :param customer_zip: Zip code associated with customer
        :param phone_number: Phone number associated with customer
        :param email: Email associated with customer
        :param ssn: Social security number for customer
        :param first_name: Customer's first name
        :param last_name: Customer's last name
        """
        customer = RetailCustomer(create_id(), customer_zip, phone_number,
                                  email, ssn, first_name, last_name)

        if self.customer_exists(customer):
            return self.get_customer_by_id(customer.customer_id)

        LOGGER.INFO("CustomerCreation(customer_id=%s)", customer.customer_id)
        self.conn.execute(f"""
            INSERT INTO customers
            VALUES ({customer.customer_id}, DATETIME('now'), NULL, '{customer.ssn}',
            '{customer.first_name}', '{customer.last_name}', '{customer.zip}',
            '{customer.phone}', '{customer.email}')
            """)
        self.conn.commit()
        return customer
Beispiel #4
0
    def list_accounts(
            self, customer_id: Union[str,
                                     int]) -> Union[List[BaseAccount], None]:
        """

        :param customer_id: ID used for identifying a customer account
        :return:
        """
        LOGGER.INFO("SearchCustomerAccounts(customer_id=%s)", customer_id)
        try:
            data = self.conn.execute(
                f"SELECT * FROM accounts WHERE customer_id = {customer_id}"
            ).fetchall()
        except IndexError:
            LOGGER.DEBUG("CustomerNotFound(id=%s)", customer_id)
            return None

        ls = []
        for row in data:
            acct_type = row[3]
            if acct_type == 1:
                ls.append(CheckingAccount(row[0], row[1]))
            else:
                ls.append(SavingsAccount(row[0], row[1], row[-1]))

        return ls
Beispiel #5
0
    def get_reserve_balance(self) -> float:
        """

        :return: The total amount available in the reserve
        """
        reserve_balance = self.conn.execute(
            "SELECT SUM(amount) FROM ledger").fetchone()
        LOGGER.INFO("GetReserveBalance(%f)", reserve_balance[0])
        return reserve_balance[0]
Beispiel #6
0
def fill_db(db_file: Optional[str] = "banklite.db") -> None:
    """
    Insert values into tables on initiation of banking system

    :param db_file: Name of file (defaults to "banklite.db"
    """
    # create database
    with sqlite3.connect(db_file) as conn:
        for model in ALL_MODELS:
            if model.inserts:
                LOGGER.INFO("TableFilled(%s)", model.table_name)
                conn.execute(_insert_to_table(model))
Beispiel #7
0
    def record_entry(self, account: BaseAccount, amount: float) -> None:
        """
        Record entry in ledger table

        :param account: Account associated with ledger entry
        :param amount: Amount to record in ledger
        """
        tx_id = create_id()
        LOGGER.INFO("LedgerEntry(%s, %s)", account.account_id, str(amount))
        self.conn.execute(f"""
            INSERT INTO ledger
            VALUES ({tx_id}, {account.account_id}, DATETIME('now'), {amount})
            """)
        self.conn.commit()
Beispiel #8
0
    def get_customer_by_id(
        self, customer_id: Union[str, int]
    ) -> Union[RetailCustomer, CommercialCustomer, None]:
        """

        :param customer_id: ID used for identifying a customer account
        :return: Customer object
        """
        LOGGER.INFO("SearchCustomer(customer_id=%s)", customer_id)
        try:
            data = self.conn.execute(
                f"SELECT * FROM customers WHERE id = {customer_id}").fetchall(
                )[0]
            LOGGER.INFO("CustomerFound(customer_id=%s)", data[0])
            if data[2] is None:
                return RetailCustomer(customer_id, data[6], data[7], data[8],
                                      data[3], data[4], data[5])
            elif data[2] is not None and data[3] is None:
                return CommercialCustomer(customer_id, data[6], data[7],
                                          data[8], data[2], data[4])
        except IndexError:
            LOGGER.DEBUG("CustomerNotFound(id=%s)", customer_id)
            return None
Beispiel #9
0
    def create_savings_account(self, customer: BaseCustomer,
                               rate: float) -> SavingsAccount:
        acct_id = create_id()
        acct = SavingsAccount(acct_id, customer.customer_id, rate)

        if self.account_exists(acct):
            return self.get_account_by_id(acct_id=acct_id)

        LOGGER.INFO("AccountCreation(account_id=%s)", acct.account_id)
        self.conn.execute(f"""
            INSERT INTO accounts
            VALUES(
                {acct.account_id}, {acct.customer_id}, DATETIME('NOW'), {acct.type}, {acct.rate}
            )
            """)
        self.conn.commit()
        return acct
Beispiel #10
0
    def create_reserve_account(self) -> ReserveAccount:
        """
        Creates a record for the special reserve account

        """
        acct = ReserveAccount()

        if self.account_exists(acct):
            return self.get_account_by_id(acct_id="1")

        LOGGER.INFO("AccountCreation(account_id=%s)", acct.account_id)
        self.conn.execute(f"""
            INSERT INTO accounts
            VALUES({acct.account_id}, NULL, DATETIME('NOW'), {acct.type}, {acct.rate})
            """)
        self.conn.commit()
        return acct
Beispiel #11
0
def create_db(db_file: Optional[str] = "banklite.db") -> None:
    """
    Create database and tables for banklite system

    :param db_file: Name of file (defaults to "banklite.db"
    """
    # remove db files if not already cleaned up
    if _db_exists():
        db_files = list(Path.cwd().rglob("*.db"))
        for file in db_files:
            LOGGER.DEBUG("FileDeleted(%s)", file.name)
            file.unlink()

    # create database
    with sqlite3.connect(db_file) as conn:
        for model in ALL_MODELS:
            LOGGER.INFO("TableCreated(%s)", model.table_name)
            conn.execute(_create_table(model))
Beispiel #12
0
    def get_accounts_by_id(
        self, acct_ids: List[str]
    ) -> List[Union[ReserveAccount, CheckingAccount, SavingsAccount]]:
        """
        Return an account object and associated data based on the accounts ID

        :param acct_ids: List of IDs for accounts to return
        :return: Account object associated with ID
        """
        for acct_id in acct_ids:
            LOGGER.INFO("SearchAccount(id=%s)", acct_id)

        ls = []

        data = self.conn.execute(f"""
                SELECT *
                FROM accounts
                WHERE id in (
                    {','.join([acct_id for acct_id in acct_ids])}
                )
            """).fetchall()

        if len(data) > 0:
            for acct in data:
                acct_type = acct[3]
                if acct_type == 0:
                    ls.append(ReserveAccount())
                elif acct_type == 1:
                    ls.append(CheckingAccount(acct[0], acct[1]))
                else:
                    ls.append(SavingsAccount(acct[0], acct[1], acct[-1]))
        else:
            for acct_id in acct_ids:
                LOGGER.DEBUG("AccountNotFound(id=%s)", acct_id)

        for acct_id in acct_ids:
            if acct_id not in [acct.account_id for acct in ls]:
                LOGGER.DEBUG("AccountNotFound(id=%s)", acct_id)

        return ls
Beispiel #13
0
    def get_account_by_id(
        self, acct_id: str
    ) -> Union[ReserveAccount, CheckingAccount, SavingsAccount, None]:
        """
        Return an account object and associated data based on the accounts ID

        :param acct_id: ID of account to return
        :return: Account object associated with ID
        """
        LOGGER.INFO("SearchAccount(id=%s)", acct_id)
        try:
            data = self.conn.execute(
                f"SELECT * FROM accounts WHERE id={acct_id}").fetchall()[0]
            acct_type = data[3]
            if acct_type == 0:
                return ReserveAccount()
            elif acct_type == 1:
                return CheckingAccount(data[0], data[1])
            else:
                return SavingsAccount(data[0], data[1], data[-1])
        except IndexError:
            LOGGER.DEBUG("AccountNotFound(id=%s)", acct_id)
            return None
Beispiel #14
0
    def create_checking_account(self,
                                customer: BaseCustomer) -> CheckingAccount:
        """
        Creates a record for a new checking account associated
        with the customer passed in

        :param customer: Customer associated with new account
        """

        acct_id = create_id()
        acct = CheckingAccount(acct_id, customer.customer_id)

        if self.account_exists(acct):
            return self.get_account_by_id(acct_id=acct_id)

        LOGGER.INFO("AccountCreation(account_id=%s)", acct.account_id)
        self.conn.execute(f"""
            INSERT INTO accounts
            VALUES(
                {acct.account_id}, {acct.customer_id}, DATETIME('NOW'), {acct.type}, {acct.rate}
            )
            """)
        self.conn.commit()
        return acct