commit bba3b8e36d48f0544c66b72a7ccfe0a04be5aa31 Author: Hladu357 Date: Thu Feb 20 11:57:28 2025 +0100 Banking system diff --git a/CT1/banking.cpp b/CT1/banking.cpp new file mode 100644 index 0000000..62ca733 --- /dev/null +++ b/CT1/banking.cpp @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include + +#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::max(), '\n'); + throw InvalidArgument(); + } + + state = static_cast(a); + + return is; +} + +template +T getInput(std::istream& is) { + T n; + if (!(is >> n) || n < 0) { + is.clear(); + is.ignore(std::numeric_limits::max(), '\n'); + throw InvalidAmountException(); + } + + return n; +} + +template <> +account_n getInput(std::istream& is) { + std::string s; + int64_t n; + + if (!(is >> s)) { + is.clear(); + is.ignore(std::numeric_limits::max(), '\n'); + throw InvalidAmountException(); + } + + std::istringstream iss(s); + if (!(iss >> n) || n < 0 || s.size() != ACCOUNT_LEN) { + is.clear(); + is.ignore(std::numeric_limits::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 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(is); + amount = b.getBalance(from); + os << GREEN << "Balance: " << "$" << amount << "\n" << RESET; + break; + + case MenuState::TRANSFER : + os << "From account: "; + from = getInput(is); + os << "To account: "; + to = getInput(is); + os << "Amount: $"; + amount = getInput(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(is); + os << "Starting balance: $"; + amount = getInput(is); + from = b.addAccount(from, amount); + os << GREEN << "Account " << from << " created with $" << amount << RESET; + break; + + case MenuState::DEPOSIT : + os << "To account: "; + to = getInput(is); + os << "Amount: $"; + amount = getInput(is); + b.deposit(to, amount); + os << GREEN << "$" << amount << " deposited\n" << RESET; + break; + + case MenuState::WITHDRAW : + os << "From account: "; + from = getInput(is); + os << "Amount: $"; + amount = getInput(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"; + } +} \ No newline at end of file