Banking system
This commit is contained in:
		
						commit
						bba3b8e36d
					
				| 
						 | 
				
			
			@ -0,0 +1,275 @@
 | 
			
		|||
#include <stdexcept>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#define RESET       "\033[0m"
 | 
			
		||||
#define RED         "❌ \033[31m"
 | 
			
		||||
#define GREEN       "✅ \033[32m"
 | 
			
		||||
#define BOLDWHITE   "\033[1m\033[37m"
 | 
			
		||||
 | 
			
		||||
using money_t   = int64_t;
 | 
			
		||||
using account_n = std::string;
 | 
			
		||||
constexpr size_t ACCOUNT_LEN = 4;
 | 
			
		||||
 | 
			
		||||
class Bank;
 | 
			
		||||
class Account;
 | 
			
		||||
 | 
			
		||||
enum class MenuState {
 | 
			
		||||
    MENU,
 | 
			
		||||
    VIEW = 1,
 | 
			
		||||
    ADD_ACCOUNT = 2,
 | 
			
		||||
    TRANSFER = 3,
 | 
			
		||||
    DEPOSIT = 4,
 | 
			
		||||
    WITHDRAW = 5,
 | 
			
		||||
    EXIT = 6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//######################################################
 | 
			
		||||
 | 
			
		||||
class BankingException : public std::exception {
 | 
			
		||||
public: const char* what() const noexcept override {
 | 
			
		||||
        return "Internal exception!";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
class InsufficientFundsException : public BankingException {
 | 
			
		||||
    const char* what() const noexcept override {
 | 
			
		||||
        return "Insufficient funds!";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
class InvalidAmountException : public BankingException {
 | 
			
		||||
    const char* what() const noexcept override {
 | 
			
		||||
        return "Invalid amount!";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
class InvalidAccountException : public BankingException {
 | 
			
		||||
    const char* what() const noexcept override {
 | 
			
		||||
        return "Invalid account number!";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
class InvalidArgument : public BankingException {
 | 
			
		||||
    const char* what() const noexcept override {
 | 
			
		||||
        return "Invalid argument!";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//######################################################
 | 
			
		||||
 | 
			
		||||
std::istream& operator>>(std::istream& is, MenuState& state) {
 | 
			
		||||
    int a;
 | 
			
		||||
    if (!(is >> a)) {
 | 
			
		||||
        is.clear();
 | 
			
		||||
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 | 
			
		||||
        throw InvalidArgument();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    state = static_cast<MenuState>(a);
 | 
			
		||||
 | 
			
		||||
    return is;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
T getInput(std::istream& is) {
 | 
			
		||||
    T n;
 | 
			
		||||
    if (!(is >> n) || n < 0) {
 | 
			
		||||
        is.clear();
 | 
			
		||||
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 | 
			
		||||
        throw InvalidAmountException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
account_n getInput<account_n>(std::istream& is) {
 | 
			
		||||
    std::string s;
 | 
			
		||||
    int64_t n;
 | 
			
		||||
 | 
			
		||||
    if (!(is >> s)) {
 | 
			
		||||
        is.clear();
 | 
			
		||||
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 | 
			
		||||
        throw InvalidAmountException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::istringstream iss(s);
 | 
			
		||||
    if (!(iss >> n) || n < 0 || s.size() != ACCOUNT_LEN) {
 | 
			
		||||
        is.clear();
 | 
			
		||||
        is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 | 
			
		||||
        throw InvalidAmountException();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr const char* MENU_MSG = "=== Bank Account Management System ===\n1. View balance\n2. Create account\n3. Transfer funds\n4. Deposit funds\n5. Withdraw funds\n6. Exit\n";
 | 
			
		||||
 | 
			
		||||
//######################################################
 | 
			
		||||
 | 
			
		||||
class Account{
 | 
			
		||||
    private:
 | 
			
		||||
        money_t m_balance;
 | 
			
		||||
    public:
 | 
			
		||||
        Account(money_t m = 0) : m_balance(m) {}
 | 
			
		||||
        ~Account() = default;
 | 
			
		||||
 | 
			
		||||
        money_t getBalance() {
 | 
			
		||||
            return m_balance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool deposit(money_t m) {
 | 
			
		||||
            if (m < 1) throw InvalidAmountException();
 | 
			
		||||
            if (m + m_balance < m_balance) throw std::overflow_error("Account overflow");
 | 
			
		||||
            m_balance += m;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool withdraw(money_t m) {
 | 
			
		||||
            if (m > m_balance) throw InsufficientFundsException();
 | 
			
		||||
            m_balance -= m;
 | 
			
		||||
            return true;
 | 
			
		||||
        } 
 | 
			
		||||
 | 
			
		||||
        void setBalance(money_t m) {
 | 
			
		||||
            m_balance = m;
 | 
			
		||||
        }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//######################################################
 | 
			
		||||
 | 
			
		||||
class Bank
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
    std::map<account_n, Account> db;
 | 
			
		||||
public:
 | 
			
		||||
    Bank()  = default;
 | 
			
		||||
    ~Bank() = default;
 | 
			
		||||
 | 
			
		||||
    account_n addAccount(account_n n = 0, money_t b = 0) {
 | 
			
		||||
        if (n == "0000") n = db.size(); // generate account number
 | 
			
		||||
        auto it = db.emplace(n, Account(b));
 | 
			
		||||
        if( !it.second ) throw InvalidAccountException();
 | 
			
		||||
        return it.first->first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool transfer(account_n from, account_n to, money_t amount) {
 | 
			
		||||
        auto itFrom = db.find(from);
 | 
			
		||||
        auto itTo = db.find(to);
 | 
			
		||||
        money_t fromState;
 | 
			
		||||
 | 
			
		||||
        if (itFrom == db.end() || itTo == db.end() || itFrom == itTo) throw InvalidAccountException();
 | 
			
		||||
 | 
			
		||||
        fromState = itFrom->second.getBalance();
 | 
			
		||||
        itFrom->second.withdraw(amount);
 | 
			
		||||
        
 | 
			
		||||
        try {
 | 
			
		||||
            itTo->second.deposit(amount);
 | 
			
		||||
        } catch(std::exception& e) {
 | 
			
		||||
            itFrom->second.setBalance(fromState);
 | 
			
		||||
            throw;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool deposit(account_n a, money_t m) {
 | 
			
		||||
        auto it = db.find(a);
 | 
			
		||||
        if (it == db.end()) throw InvalidAccountException();
 | 
			
		||||
        return it->second.deposit(m);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool withdraw(account_n a, money_t m) {
 | 
			
		||||
        auto it = db.find(a);
 | 
			
		||||
        if (it == db.end()) throw InvalidAccountException();
 | 
			
		||||
        return it->second.withdraw(m);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    money_t getBalance(account_n a) {
 | 
			
		||||
        auto it = db.find(a);
 | 
			
		||||
        if (it == db.end()) throw InvalidAccountException();
 | 
			
		||||
        return it->second.getBalance();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//######################################################
 | 
			
		||||
 | 
			
		||||
int main(int ragc, char* argv[]) {
 | 
			
		||||
    std::ostream& os = std::cout;
 | 
			
		||||
    std::istream& is = std::cin;
 | 
			
		||||
 | 
			
		||||
    MenuState state = MenuState::MENU;
 | 
			
		||||
 | 
			
		||||
    Bank b;
 | 
			
		||||
    for (;;) {
 | 
			
		||||
        try {
 | 
			
		||||
            account_n from = "0000";
 | 
			
		||||
            account_n to   = "0000";
 | 
			
		||||
            money_t amount = 0;
 | 
			
		||||
 | 
			
		||||
            os << BOLDWHITE << MENU_MSG << RESET;
 | 
			
		||||
            is >> state;
 | 
			
		||||
 | 
			
		||||
            switch (state) {
 | 
			
		||||
            case MenuState::VIEW :
 | 
			
		||||
                os << "Account number: ";
 | 
			
		||||
                from = getInput<account_n>(is);
 | 
			
		||||
                amount = b.getBalance(from);
 | 
			
		||||
                os << GREEN << "Balance: " << "$" << amount << "\n" << RESET;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::TRANSFER :
 | 
			
		||||
                os << "From account: ";
 | 
			
		||||
                from = getInput<account_n>(is);
 | 
			
		||||
                os << "To account: ";
 | 
			
		||||
                to = getInput<account_n>(is);
 | 
			
		||||
                os << "Amount: $";
 | 
			
		||||
                amount = getInput<money_t>(is);
 | 
			
		||||
                b.transfer(from, to, amount);
 | 
			
		||||
                os << GREEN << "$" << amount << " transfered from " << from << " to " << to << "\n" << RESET;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::ADD_ACCOUNT :
 | 
			
		||||
                os << "New account number (0 for auto): ";
 | 
			
		||||
                from = getInput<account_n>(is);
 | 
			
		||||
                os << "Starting balance: $";
 | 
			
		||||
                amount = getInput<money_t>(is);
 | 
			
		||||
                from = b.addAccount(from, amount);
 | 
			
		||||
                os << GREEN << "Account " << from << " created with $" << amount << RESET;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::DEPOSIT :
 | 
			
		||||
                os << "To account: ";
 | 
			
		||||
                to = getInput<account_n>(is);
 | 
			
		||||
                os << "Amount: $";
 | 
			
		||||
                amount = getInput<money_t>(is);
 | 
			
		||||
                b.deposit(to, amount);
 | 
			
		||||
                os << GREEN << "$" << amount << " deposited\n" << RESET;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::WITHDRAW :
 | 
			
		||||
                os << "From account: ";
 | 
			
		||||
                from = getInput<account_n>(is);
 | 
			
		||||
                os << "Amount: $";
 | 
			
		||||
                amount = getInput<money_t>(is);
 | 
			
		||||
                b.withdraw(from, amount);
 | 
			
		||||
                os << GREEN << "$" << amount << " withdrawed\n" << RESET;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::EXIT :
 | 
			
		||||
                os << "Exiting...\n";
 | 
			
		||||
                return EXIT_SUCCESS;
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case MenuState::MENU :
 | 
			
		||||
            default:
 | 
			
		||||
                throw InvalidArgument();
 | 
			
		||||
            }
 | 
			
		||||
        } catch (BankingException& e) {
 | 
			
		||||
            os << RED << e.what() << RESET;
 | 
			
		||||
            // return EXIT_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
        state = MenuState::MENU;
 | 
			
		||||
        os << "\n\n";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue