Banking system
This commit is contained in:
commit
f873d51127
|
@ -0,0 +1,15 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -std=c++20 -Wall -pedantic -O2
|
||||
|
||||
SRCS = $(wildcard *.cpp)
|
||||
EXECS = $(SRCS:.cpp=)
|
||||
|
||||
all: $(EXECS)
|
||||
|
||||
%: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXECS)
|
||||
|
||||
.PHONY: all clean
|
|
@ -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