So I wrote this a while ago and yesterday I was going through it and trying to remember every line of code and how it works. Well, the program simulates a online bank account as well as an ATM. You register your account, you are able to withdraw, deposit, and transfer money. There is a limit to the amount you can transfer and withdraw in a day, there is a limit number for attempts, if you exceed it you will be locked out of the account for 24 hours, you can see all the transactions you've made, and there is a log for the admin, and all of that is saved to file.
Anyway, it is a pretty long program (thus the feeling that the design is wrong), what I am asking is not to go by line by line and review it, just to check out how the program works and review its design and give some feedback. However, if you want to review the code itself or if you something that is not right I would appreciate your feedback on that.
Paths.h
#ifndef PATHS_H_INCLUDED
#define PATHS_H_INCLUDED
class Paths
{
public:
static const std::string BASE_PATH;
static const std::string USER_PATH;
static const std::string ADMIN_PATH;
static const std::string USER_INFO;
static const std::string USER_TRANSACTION;
static const std::string ADMIN_BACKUP;
static const std::string ADMIN_LOCKED_ACCOUNTS;
static const std::string ADMIN_LOG;
static const std::string ADMIN_WITHDRAWAL_DATE;
static const std::string ADMIN_WITHDRAWAL_VAL;
static const std::string ADMIN_TRANSFER_DATE;
static const std::string ADMIN_TRANSFER_VAL;
};
#endif // PATHS_H_INCLUDED
Paths.cpp
#include <iostream>
#include "Paths.h"
using namespace std;
const string Paths::BASE_PATH = "C:\\ProgramData\\BankAcount";
const string Paths::USER_PATH = BASE_PATH + "\\User";
const string Paths::ADMIN_PATH = BASE_PATH + "\\Administrator";
const string Paths::USER_INFO = USER_PATH + "\\Info\\";
const string Paths::USER_TRANSACTION = USER_PATH + "\\Transactions\\";
const string Paths::ADMIN_BACKUP = ADMIN_PATH + "\\Backup\\";
const string Paths::ADMIN_LOCKED_ACCOUNTS = ADMIN_PATH + "\\LockedAccounts\\";
const string Paths::ADMIN_LOG = ADMIN_PATH + "\\Log\\";
const string Paths::ADMIN_TRANSFER_DATE = ADMIN_PATH + "\\Limits\\Transfer\\Dates\\";
const string Paths::ADMIN_TRANSFER_VAL = ADMIN_PATH + "\\Limits\\Transfer\\Values\\";
const string Paths::ADMIN_WITHDRAWAL_DATE = ADMIN_PATH + "\\Limits\\Withdrawal\\Dates\\";
const string Paths::ADMIN_WITHDRAWAL_VAL = ADMIN_PATH + "\\Limits\\Withdrawal\\Values\\";
classAccount.h
#ifndef CLASSACCOUNT_H_INCLUDED
#define CLASSACCOUNT_H_INCLUDE
class Account
{
protected:
std::string name;
std::string new_name;
long long int balance;
std::string account_num;
std::string file_path;
std::string pin, new_pin;
char buffer[256];
void createFolder() const;
void withdrawal();
void deposit ();
void viewBalance() const;
void transfer();
void logTransactions(const std::string& log_account_num, const std::string& transaction_type, const int& amount) const;
void transactions(const std::string& account_num) const;
void log( bool note ) const;
void logInsideAccount(const std::string& in_account) const;
void withdrawalLimit(int withdrawalAmount);
void transferLImit (int transferAmount);
void createLimitFiles();
void dayShiftCheck();
void deleteFile(std::string file_to_delete);
void settings();
void changePin();
void pinChanged();
void changeName();
void nameChanged();
void clearTransactions();
void transactionsCleared();
// int numberOfTransactions = 0;
void lockAccount();
void lockAccountCheck();
void signUp();
void signIn();
void myAccount(std::ifstream* fileStream);
void signOut ();
void parseAccountInfo(const char* buffer, std::string& assigned_name, std::string& assigned_account_num, long long int& assigned_Balance, std::string& assigned_pin) const;
void backupAccountFile(const std::string& file) const;
void backupTransactionFile(const std::string& file) const;
std::string accountExistenceCheckSignIn(std::string& account_num);
std::string accountExistenceCheckSignUp(std::string& account_num) ;
std::string accountExistenceCheckTransfer(std::string& account_num) ;
public:
void mainMenu();
};
#endif
classAccount.cpp
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <stdlib.h>
#include <conio.h>
#include <direct.h>
#include <windows.h>
// #include <algorithm>
// #include <list>
#include <sys/types.h>
#include <sys/stat.h>
#include "classAccount.h"
#include "Paths.h" // a class where constant strings, that contains entire paths to where file containing the necessary info, will be managed
using namespace std;
// a function that creates the directories where the account files will be storaged
// it checks wether the necessary folders are already created before creating the folders
void Account::createFolder() const
{
class stat info; // used when checking the existence of the folder
if(stat(Paths::BASE_PATH.c_str(), &info) != 0) // I could ommit this path and it still would be created in the next lines but I chose to write
system(("mkdir " + Paths::BASE_PATH).c_str()); // it so the code can be slightly more readable, at least in my opinion
if(stat(Paths::USER_PATH.c_str(), &info) != 0)
system(("mkdir " + Paths::USER_PATH).c_str() );
if(stat(Paths::USER_INFO.c_str(), &info) != 0)
system(("mkdir " + Paths::USER_INFO).c_str() );
if(stat(Paths::USER_TRANSACTION.c_str(), &info) != 0)
system(("mkdir " + Paths::USER_TRANSACTION).c_str() );
if(stat(Paths::ADMIN_PATH.c_str(), &info) != 0) // I could ommit this path and it still would be created in the next lines but I chose to write
system(("mkdir " + Paths::ADMIN_PATH).c_str() ); // so the code can be slightly more readable, at least in my opinion
if(stat(Paths::ADMIN_BACKUP.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_BACKUP).c_str() );
if(stat(Paths::ADMIN_LOCKED_ACCOUNTS.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_LOCKED_ACCOUNTS).c_str() );
if(stat(Paths::ADMIN_LOG.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_LOG).c_str() );
// paths to where the dates and values information will be saved for withdrawal and transfer limits purposes
if(stat(Paths::ADMIN_WITHDRAWAL_DATE.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_WITHDRAWAL_DATE).c_str() );
if(stat(Paths::ADMIN_WITHDRAWAL_VAL.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_WITHDRAWAL_VAL).c_str() );
if(stat(Paths::ADMIN_TRANSFER_DATE.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_TRANSFER_DATE).c_str() );
if(stat(Paths::ADMIN_TRANSFER_VAL.c_str(), &info) != 0)
system(("mkdir " + Paths::ADMIN_TRANSFER_VAL).c_str() );
}
void Account::deleteFile(std::string file_to_delete)
{
// convert string to const char* so it can be used in file_path for deletion
/*
const char* deleteFile = sfile_path.data();
const char* deleteFile = sfile_path.c_str();
const char* delete_file = &file_to_delete[0];
*/
remove(file_to_delete.c_str());
}
// display the simple menu at the beginning
void Account::mainMenu()
{
system("cls");
createFolder();
// mkdir("D:\Bank Account");
account_num.clear();
pin.clear();
char option;
cout << "\n\n\n\n\n\n \t\t\t\t\t" << "1 -> Sign In" << endl;
cout << " \t\t\t\t\t" << "2 -> Sign Up" << endl << endl;
cout << " \t\t\t\t\t" << " -> ";
option = _getch();
while (option != '1' && option != '2' && option != 27)
{
option = _getch();
}
switch (option)
{
case '1':
system("cls");
signIn();
break;
case '2':
system("cls");
signUp();
break;
case '0':
cout << "\nProcess returned 0" << endl << "Press enter key to continue";
cin.get();
exit(0);
break;
case 27:
cout << "\nProcess returned 0" << endl << "Press enter key to continue";
cin.get();
exit(0);
break;
default:
mainMenu();
break;
}
}
// a function to lock the account that had 3 failed attempts on a password input
void Account::lockAccount()
{
string sfile_path = Paths::ADMIN_LOCKED_ACCOUNTS + account_num;
time_t now = time(nullptr);
string time_now = ctime(&now); // takes the system times into a string, showing the lock time
tm* lock_time = localtime(&now);
ofstream lock (sfile_path); // create the file that contains the time of the lock
lock << lock_time->tm_mday << " " << lock_time->tm_hour << " " << lock_time->tm_min;
lock.close();
}
// a function that everytime a user goes to sign in it checks if the account is locked or not
void Account::lockAccountCheck()
{
string sfile_path = Paths::ADMIN_LOCKED_ACCOUNTS + account_num;
ifstream file_in (sfile_path);
// checks for the existence of a file that contains the time of the lock, if the file doesn't exist it returns meaning that
// the account is not locked
if ( ! file_in.good() )
{
return;
}
time_t now = time(nullptr);
string time_now = ctime(&now);
tm* lock_time = localtime(&now);
char bufferLine[256];
// integers that hold the dates values
int filelock_timeDay;
int filelock_timeHour;
int filelock_timeMinute;
int lock_timeDay = lock_time->tm_mday;
int lock_timeHour = lock_time->tm_hour;
int lock_timeMinute = lock_time->tm_min;
// it gets the information of the time from the lock account file and hold it in char
file_in.getline(bufferLine, 256);
istringstream lockFile (bufferLine); // it parses the contents of the file
// it assigns each date value to the respective variable
lockFile >> filelock_timeDay;
lockFile >> filelock_timeHour;
lockFile >> filelock_timeMinute;
// count the days, hours and minutes to check if the time of the lock has passed
// it compares the time of the system against the lock time
int count_day = lock_timeDay - filelock_timeDay;
int count_hour = lock_timeHour - filelock_timeHour;
int count_minute = lock_timeMinute - filelock_timeMinute;
file_in.close();
if ( count_day == 0 )
{
cout << endl << endl << "Your Account Has Been Locked Since " << filelock_timeDay << " - " << 1 + lock_time->tm_mon
<< " - " << 1900 + lock_time->tm_year << " | " << filelock_timeHour << ":" << filelock_timeMinute << endl << endl;
cout << "Locking Period: 24 Hours" ;
cout << endl<< endl << "Press enter key to continue";
char ch;
ch = _getch();
while (ch != 13)
{
ch = _getch();
}
mainMenu();
}
else if (count_day > 0 && count_hour < 0 )
{
cout << endl << endl << "Your Account Has Been Locked Since " << filelock_timeDay << " - " << 1 + lock_time->tm_mon
<< " - " << 1900 + lock_time->tm_year << " | " << filelock_timeHour << ":" << filelock_timeMinute << endl << endl;
cout << "Locking Period: 24 Hours" ;
cout << endl<< endl << "Press enter key to continue";
char ch;
ch = _getch();
while (ch != 13)
{
ch = _getch();
}
mainMenu();
}
/*
else if (count_day > 0 && filelock_timeHour < lock_timeHour)
{
}
*/
else if (count_day > 0 && count_hour >= 0 && lock_timeHour == filelock_timeHour && count_minute < 0 )
{
cout << endl << endl << "Your Account has Been Locked Since " << filelock_timeDay << " - " << 1 + lock_time->tm_mon
<< " - " << 1900 + lock_time->tm_year << " | " << filelock_timeHour << ":" << filelock_timeMinute << endl << endl;
cout << "Locking Period: 24 Hours" ;
cout << endl<< endl << "Press enter jey to continue";
char ch;
ch = _getch();
while (ch != 13)
{
ch = _getch();
}
mainMenu();
}
deleteFile(sfile_path); // the file that contains the locking info will be deleted after it is known that it has passed 24hours after the lock
}
// a function that creates a file that contains log information
void Account::log(bool note ) const // the bool note is a bool that logs wether the account was locked because of too many failed password attempts
{
time_t now = time(nullptr);
// string time_now = ctime(&now);
tm* log_time = localtime(&now);
int log_day, log_month, log_year;
string sLog_day, sLog_month, sLog_year;
log_day = log_time->tm_mday;
log_month = 1 + log_time->tm_mon;
log_year = 1900 + log_time->tm_year;
// the dates obtained and held in integer variables will be coverted to string so they can be added to the file path
sLog_day = to_string(log_day);
sLog_month = to_string(log_month);
sLog_year = to_string(log_year);
string sfile_path = Paths::ADMIN_LOG + sLog_day + " - " + sLog_month + " - " + sLog_year;
ifstream file_in(sfile_path);
string existent_content;
char c;
while (file_in.good() && ! file_in.eof())
{
c = file_in.get();
existent_content.push_back(c);
}
ofstream log(sfile_path);
log << existent_content << endl << endl;
log << "-----------------------------------------------------------------------------------" << endl << endl;
log << "Account Number: " << account_num << " | " << "Name: " << name << endl;
log << "Sign In " << " at " << log_time->tm_hour << ":" << log_time->tm_min << ":" << log_time->tm_sec;
//log << "Sign In " << " at " << __DATE__;
// if the note is true it logs in the file that the account was blocked for 24 hours and informing the time of the occured
if (note == true)
{
log << endl << "Account Locked For 24 Hours Started At " << log_time->tm_hour << ":" << log_time->tm_min << ":" << log_time->tm_sec;
}
log.close();
}
// a function that creates a file that logs every activity inside an account
void Account::logInsideAccount(const string& inAccount_activity) const // the string will take the type of activity made
{
time_t now = time(nullptr);
// string time_now = ctime(&now);
tm* log_time = localtime(&now);
int log_day, log_month, log_year;
string sLog_day, sLog_month, sLog_year;
log_day = log_time->tm_mday;
log_month = 1 + log_time->tm_mon;
log_year = 1900 + log_time->tm_year;
sLog_day = to_string(log_day);
sLog_month = to_string(log_month);
sLog_year = to_string(log_year);
string sfile_path = Paths::ADMIN_LOG + sLog_day + " - " + sLog_month + " - " + sLog_year;
ifstream file_in(sfile_path);
string existent_content;
char c;
// while the log file is ok and hasn't reached the end it will keep copying the content to the string existent_content
while (file_in.good() && ! file_in.eof())
{
c = file_in.get();
existent_content.push_back(c);
}
ofstream log(sfile_path);
log << existent_content << endl;
log << " - " << inAccount_activity << " at " << log_time->tm_hour << ":" << log_time->tm_min << ":" << log_time->tm_sec ;
// log << " - " << inAccount_activity << " at " << __TIME__ ;
log.close(); // closes the file after use
}
// log every transaction
void Account::logTransactions(const string& log_account_num, const string& transaction_type, const int& amount) const
{
time_t now = time(nullptr);
char* time_now = ctime(&now);
string sfile_path = Paths::USER_TRANSACTION + log_account_num;
ifstream file_in(sfile_path); // it enters the file
string existent_content;
char c;
// copies the exitent content in the transaction file to a string
while (file_in.good() && ! file_in.eof())
{
c = file_in.get();
existent_content.push_back(c);
}
file_in.close(); // closes the file after use
/* should've used ios::app for appending thus eliminating the need to write the previous
code to save the existing content of the file */
ofstream fileOut (sfile_path); // creates the file with the same name and path of the previous file, thus overwriting
/* Desnecessary */
fileOut << existent_content << endl << endl; // it writes the already logged transactions to the file and below it writes the recent transaction to the file
/* Desnecessary */
fileOut << "-> " << time_now;// << endl ;
fileOut << "[ " << transaction_type << " ] -> ";
fileOut << "Amount: " << amount;
fileOut.close(); // closes the file after use
backupTransactionFile(log_account_num);
}
void Account::parseAccountInfo(const char* buffer, string& assigned_name, string& assigned_account_num,
long long int& assigned_balance, string& assigned_pin) const
{
// associate an istrstream object with the accountut
// character string
istringstream account(buffer);
account >> assigned_name;
// now the account number
account >> assigned_account_num;
// and the balance
account >> assigned_balance;
account >> assigned_pin;
}
// a function that creates a backup file of the account file and of the transaction
void Account::backupAccountFile(const string& file) const
{
string sfile_path = Paths::USER_INFO + file; // original file path
string source(sfile_path);
string target = Paths::ADMIN_BACKUP + file; // backup file path
ifstream input (source.c_str(), ios_base::in | ios_base::binary);
ofstream output (target.c_str(), ios_base::out | ios_base::binary | ios_base::trunc);
if (input.good() && output.good())
{
while( ! input.eof() && input.good())
{
char buffer[4096];
input.read(buffer, 4096);
output.write(buffer, input.gcount());
}
}
}
void Account::backupTransactionFile(const string& file) const
{
string sfile_path = Paths::USER_TRANSACTION + file;
string source(sfile_path);
string target = Paths::ADMIN_BACKUP + file + "-trans" ;
ifstream input (source.c_str(), ios_base::in | ios_base::binary);
ofstream output (target.c_str(), ios_base::in | ios_base::binary | ios_base::trunc);
if (input.good() && output.good())
{
while ( ! input.eof() && input.good())
{
char buffer[4096];
input.read(buffer, 4096);
output.write(buffer, input.gcount());
}
}
}
// function that checks wether the file exists or not when the user is signing in
string Account::accountExistenceCheckSignIn(string& account_num) // the string takes the account number input by the user
{
string sfile_path = Paths::USER_INFO + account_num;
char ch_num;
int num_length = 1;
ifstream file_stream(sfile_path);
// a condition that checks wether the file exists or not, if it is good it means that the file exists thus the account too
if (file_stream.good())
{
return sfile_path;
}
account_num.clear();
while (true)
{
cout << endl << endl << "Account Doesn't Exist!!" << endl;
cout << endl << "Enter Your Bank Account Number: ";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (account_num.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! account_num.empty())
{
-- num_length;
account_num.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and account_num will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (account_num.empty())
cout << "\b \b";
account_num.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( account_num.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
}
// when the user learns that the account doesnt exist he or she has the optionion of entering '0' and go back to the main menu
if (account_num[0] == '0' && account_num.size() == 1)
{
mainMenu();
}
sfile_path = Paths::USER_INFO + account_num;
ifstream file_stream (sfile_path);
// the user will keep being noticed that the account doesnt exist until he or she either inputs a valid account number or '0'
if (file_stream.good())
{
break;
}
account_num.clear();
num_length = 1;
}
return sfile_path; // the function will return the path of the acoount file
}
// function that checks wether the file exists or not when the user is signing up
string Account::accountExistenceCheckSignUp(string& account_num)
{
string sfile_path = Paths::USER_INFO + account_num;
char ch_num;
int num_length = 1;
ifstream file_stream(sfile_path);
// a condition that checks wether the file exists or not, if it doesnt exit it breaks out the loop meaning that the account
// doesnt exist so it is safe to create an account with that number
if ( ! file_stream.good())
{
return sfile_path;;
}
account_num.clear();
while (true)
{
cout << endl << endl << "Account Already Exists!!" << endl;
cout << "Account Number: ";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (account_num.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! account_num.empty())
{
-- num_length;
account_num.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and account_num will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (account_num.empty())
cout << "\b \b";
account_num.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( account_num.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
}
// when the user learns that the account doesnt exist he or she has the optionion of entering '0' and go back to the main menu
if (account_num[0] == '0' && account_num.size() == 1)
{
mainMenu();
}
sfile_path = Paths::USER_INFO + account_num;
ifstream file_stream (sfile_path);
// the user will keep being noticed that the account doesnt exist until he or she either inputs a valid account number or '0'
if ( ! file_stream.good())
{
break;
}
account_num.clear();
num_length = 1;
}
cout << endl;
return sfile_path;
}
// a function that checks for the existence of a file that is aimed to be transfered an amount
string Account::accountExistenceCheckTransfer(string& transfer_account_number)
{
string sfile_path = Paths::USER_INFO + transfer_account_number;
char ch_num;
int num_length = 1;
ifstream file_stream(sfile_path);
if (file_stream.good())
{
return sfile_path;
}
while (true)
{
transfer_account_number.clear();
num_length = 1;
cout << endl << endl << "Account Doesn't Exist!!" << endl;
cout << setw(10) << "To Account Number: ";
ch_num = _getch();
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
while (ch_num == 13 && num_length <= 16)
{
if (transfer_account_number.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (transfer_account_number.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! transfer_account_number.empty())
{
-- num_length;
transfer_account_number.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and transfer_account_number will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (transfer_account_number.empty())
cout << "\b \b";
transfer_account_number.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( transfer_account_number.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
while (ch_num == 13 && num_length <= 16)
{
if (transfer_account_number.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
}
}
while (transfer_account_number == account_num)
{
transfer_account_number.clear();
num_length = 1;
cout << endl << endl << "Can't Transfer Money To Your Own Account!" << endl;
cout << setw(10) << "To Account Number: ";
ch_num = _getch();
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
while (ch_num == 13 && num_length <= 16)
{
if (transfer_account_number.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (transfer_account_number.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! transfer_account_number.empty())
{
-- num_length;
transfer_account_number.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and transfer_account_number will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (transfer_account_number.empty())
cout << "\b \b";
transfer_account_number.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( transfer_account_number.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
while (ch_num == 13 && num_length <= 16)
{
if (transfer_account_number.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
ifstream file (file_path);
myAccount(&file);
}
}
}
}
sfile_path = Paths::USER_INFO + transfer_account_number;
ifstream file_stream (sfile_path);
if (file_stream.good())
{
break;
}
}
return sfile_path;
}
// create a set of files that will contain days and amounts of withdrawal and transfer thta helps ensuring the limit for withdrawal and transfer
void Account::createLimitFiles()
{
// a file path to where the file that will contain the current day will be saved
string datefile_path = Paths::ADMIN_WITHDRAWAL_DATE + account_num;
ofstream date_file (datefile_path); // it is to check the current day to ensure the amount of the withdrawal in one day won't be exceeded
time_t now = time(nullptr);
tm* day_check = localtime(&now);
date_file << day_check->tm_mday;
date_file.close();
// a file path to where the file that will contain theamount of withdrawal in one day will be saved
string valuefile_path = Paths::ADMIN_WITHDRAWAL_VAL + account_num;
ofstream valueFile (valuefile_path);
valueFile << 0; // the initial amount is 0
valueFile.close();
// a file path to where the file that will contain the current day will be saved
string datefile_pathTransfer = Paths::ADMIN_TRANSFER_DATE + account_num;
ofstream dateFileTransfer (datefile_pathTransfer); // it is to check the current day to ensure the amount of the withdrawal in one day won't be exceeded
dateFileTransfer << day_check->tm_mday;
dateFileTransfer.close();
// a file path to where the file that will contain theamount of withdrawal in one day will be saved
string valuefile_pathTransfer = Paths::ADMIN_TRANSFER_VAL + account_num;
ofstream valueFileTransfer (valuefile_pathTransfer);
valueFileTransfer << 0; // the initial amount is 0
valueFileTransfer.close();
}
// function that gets the user through the 'sign up' steps
void Account::signUp()
{
// cin.get(); // dont know why but it seems like when it enters the functions signIn and signUp it comes with an ENTER already pressed
balance = 0; // balance is set to zero because when the user creates a new account his ir her balance will be zero
string sname;
// int arrow = 224;
// char chName;
// bool check = false;
system("cls");
cout << "\t\t\t Sign Up" << endl << endl;
cout << "Name: ";
getline(cin, sname);
if (sname == "0")
{
mainMenu();
}
while (sname.empty())
{
system("cls");
cout << "\t\t\t Sign Up" << endl << endl;
cout << "Name: ";
getline(cin, sname);
if (sname == "0")
{
mainMenu();
}
}
for (unsigned int i = 0; i < sname.size(); ++i)
{
if (( ! isalpha(sname[i]) && ! isspace(sname[i]) ) || isspace(sname[0]))
{
cout << endl << "Invalid Name \n Re-enter: ";
getline(cin, sname);
if (sname == "0")
{
mainMenu();
}
while (sname.empty())
{
cout << endl << "Can't Be Empty \n Re-enter: ";
getline(cin, sname);
if (sname == "0")
{
mainMenu();
}
}
i = -1;
}
}
system("cls");
char ch_num;
int num_length = 1;
cout << "\t\t\t Sign Up" << endl << endl;
cout << "Name: " << sname;
cout << endl << endl << "Account Number: ";
ch_num = getch();
if (ch_num == 27)
{
mainMenu();
}
// in case the user presses enter right away
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (account_num.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! account_num.empty())
{
-- num_length;
account_num.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and account_num will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (account_num.empty())
cout << "\b \b";
account_num.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( account_num.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
}
// after the account number has been input this will call the function that checks wether the ccount number already exists or not
file_path = accountExistenceCheckSignUp(account_num);
system("cls");
cout << "\t\t\t Sign Up" << endl << endl;
cout << "Name: " << sname << endl << endl;
cout << "Account Number: " << account_num << endl << endl;
char ch_pin;
int pin_length = 1; // it counts how many characters the user has input into the pin, it is initialized to 1 in case the user hits the backspace
cout << "Pin: ";
ch_pin = getch();
while (ch_pin == 13 && pin_length <= 4)
{
if (pin.empty())
cout << "\b \b";
ch_pin = getch();
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_pin != 13)
{
if (pin.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_pin == 8)
{
if ( ! pin.empty())
{
-- pin_length;
pin.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and pin_check will be take the character input by the user
// only numbers are accepted
else if (pin_length <= 4 && isdigit(ch_pin))
{
if (pin.empty())
cout << "\b \b";
pin.push_back(ch_pin);
cout << ch_pin;
++pin_length;
}
else if ( pin.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_pin = getch();
while (ch_pin == 13 && pin_length <= 4)
{
if (pin.empty())
{
cout << " \b";
}
ch_pin = getch();
}
}
// it creates a file that will contain all the account information
ofstream file(file_path);
int temp_iterator = 0; // a temporary int variable to ensure that after a space is deleted the letter next will be uppercased and not lowercased
// this for condition ensures the names will begin with an uppercase letter and there will be no space between
for (unsigned int i = 0; i < sname.size(); i++)
{
if (! isupper(sname[0]))
sname[0] = toupper(sname[0]);
if (isspace(sname[i]))
{
sname.erase(i, i - (i - 1));
sname[i] = toupper(sname[i]);
temp_iterator = i;
i += 1; // Be FCKNG CAREFUL, I HAD =+ WRITTEN
}
if( isupper(sname[i]) && toupper(sname[0]))
{
sname[i] = tolower(sname[i]);
sname[temp_iterator] = toupper(sname[temp_iterator]);
}
}
// it will write the account needed information to the recently created file
file << sname << " " << account_num << " " << " " << balance << " " << pin;
file.close();
backupAccountFile(file_path);
system("cls");
cout << "\a \nAccount Successfully Created!!!";
Sleep(1000);
system("cls");
createLimitFiles();
ifstream file_stream(file_path); // it enters the just created account file so the user can directly sign in after sign up
myAccount(&file_stream);
}
// function that gets the user through the 'sign in' steps
void Account::signIn()
{
cout << "\t\t\t Sign In" << endl << endl;
// cin.get(); // dont know why but it seems like when it enters the functions signIn and signUp it comes with an ENTER already pressed
char ch_num;
int num_length = 1;
cout << "Enter Your Bank Account Number: ";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
// in case the user user presses enter right away
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
cout << "\b \b";
ch_num = getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_num != 13)
{
if (account_num.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_num == 8)
{
if ( ! account_num.empty())
{
-- num_length;
account_num.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and account_num will be take the character input by the user
// only numbers are accepted
else if (num_length <= 16 && isdigit(ch_num))
{
if (account_num.empty())
cout << "\b \b";
account_num.push_back(ch_num);
cout << ch_num;
++num_length;
}
else if ( account_num.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
while (ch_num == 13 && num_length <= 16)
{
if (account_num.empty())
{
cout << " \b";
}
ch_num = _getch();
// if the user wishes to go back to the menu he/she presses esc
if (ch_num == 27)
{
mainMenu();
}
}
}
// it checks for the existence of the account
file_path = accountExistenceCheckSignIn(account_num);
// it checks if the account is locked
lockAccountCheck();
ifstream file_stream(file_path);
file_stream.getline(buffer, 256);
parseAccountInfo(buffer, name, account_num, balance, pin);
// char* sParseName = new char[100];
// sParseName = parseName;
// decohereLetter(sParseName);
file_stream.close();
system("cls");
cout << "\t\t\t My Account" << endl << endl;
cout << "Welcome " << name << endl << endl;
char ch_pin;
int pin_length = 1; // it counts how many characters the user has input into the pin, it is initialized to 1 in case the user hits the backspace
string pin_check;
cout << "Pin: ";
ch_pin = getch();
while (ch_pin == 13 && pin_length <= 4)
{
if (pin_check.empty())
cout << "\b \b";
ch_pin = getch();
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_pin != 13)
{
if (pin_check.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_pin == 8)
{
if ( ! pin_check.empty())
{
-- pin_length;
pin_check.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and pin_check will be take the character input by the user
// only numbers are accepted
else if (pin_length <= 4 && isdigit(ch_pin))
{
if (pin_check.empty())
cout << "\b \b";
pin_check.push_back(ch_pin);
cout << "*";
++pin_length;
}
else if ( pin_check.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_pin = _getch();
while (ch_pin == 13 && pin_length <= 4)
{
if (pin_check.empty())
{
cout << " \b";
}
ch_pin = _getch();
}
}
int pin_checkCount = 1;
bool note = false;
// if the pin input is wrong the pin_check will be cleared
if (pin_check != pin)
{
pin_check.clear();
}
// and the pin lenght will be reset to 1
pin_length = 1;
while (pin_check != pin)
{
// if the pin input is wrong the pin_check will be cleared
if (pin_check != pin)
{
pin_check.clear();
}
// and the pin lenght will be reset to 1
pin_length = 1;
system("cls");
cout << "\t\t\t My Account" << endl << endl;
cout << "Welcome " << name << endl << endl;
// it counts how many passwords input attempts the user has tried, when it equal 3 the account is locked for 24 hours
if (pin_checkCount == 3)
{
cout << endl << "3 Attempts Failed!!" << endl;
cout << "Your Account Has Been Locked For the Next 24 Hours" << endl;
cout << endl << "Press enter key to continue";
note = true; //the note is set to true to log the fact the account got locked
log(note);
lockAccount();
char ch = _getch();
while(ch != 13)
{
ch = _getch();
}
mainMenu();
}
cout << "Wrong Pin!!" << endl;
cout << "Pin: ";
ch_pin = _getch();
while (ch_pin == 13 && pin_length < 5)
{
if (pin_check.empty())
{
cout << "\b \b";
}
ch_pin = _getch();
}
// while the user doesnt hit enter, 13 is the ASCII code for enter
while (ch_pin != 13)
{
if (pin_check.empty())
{
cout << " \b";
}
// when the user hits backspace, 8 s the ASCII code for backspace
if (ch_pin == 8)
{
// if the pin_check isn't empty the pin lenght will decreased amd pin characters too
if ( ! pin_check.empty())
{
-- pin_length;
pin_check.pop_back();
}
cout << "\b \b";
}
// if the pin lenght is equal or below 4 asterisk will be displayed to mask the pin and pin_check will be take the character input by the user
// only numbers are accepted
else if (pin_length <= 4 && isdigit(ch_pin))
{
if (pin_check.empty())
cout << "\b \b";
pin_check.push_back(ch_pin);
cout << "*";
++pin_length;
}
else if ( pin_check.empty()) // when the user clear the input this condition won't allow the cursor to improper forward move
{
cout << "\b \b";
}
ch_pin = _getch();
while (ch_pin == 13 && pin_length <= 4)
{
if (pin_check.empty())
cout << " \b";
ch_pin = _getch();
}
}
++pin_checkCount;
}
pin_check.clear(); // the pin_check will be cleared in case another log in is made
log(note); // it will log the time of the 'sign in'
myAccount(&file_stream); // once the user is signed into his or her account the function 'myAccount' will be called
}
// function that lets the user navigate into his or her account
void Account::myAccount(ifstream* file_stream)
{
system("cls");
while (true)
{
char option;
backupAccountFile(account_num);
file_stream->getline(buffer, 256);
parseAccountInfo(buffer, name, account_num, balance, pin);
file_stream->close();
cout << endl << "Account: " << name << endl << endl;
cout << setw(10) << "1 -> Balance";
cout << setw(22) << "2 -> Withdrawal" << endl << endl;
cout << setw(10) << "3 -> Deposit";
cout << setw(20) << "4 -> Transfer" << endl << endl;
cout << setw(10) << "5 -> Transactions";
cout << setw(16) << "6 -> Settings " << endl << endl;
cout << setw(10) << "0 -> Sign Out" << endl << endl;
cout << setw(17) << "-> ";
option = _getch();
while (option != '0' && option != '1' && option != '2' && option != '3' && option != '4' && option != '5' && option != '6')
{
option = _getch();
}
switch(option)
{
case '1':
logInsideAccount("View Balance");
viewBalance();
break;
case '2':
logInsideAccount("Withdrawal");
withdrawal();
break;
case '3':
logInsideAccount("Deposit");
deposit();
break;
case '4':
logInsideAccount("Transfer");
transfer();
break;
case '5':
// it logs the activity (View Transaction) made in the account
logInsideAccount("View Transactions");
transactions(account_num);
break;
case '6':
logInsideAccount("Enter Settings");
settings();
break;
case '0':
signOut();
default:
myAccount(file_stream);
}
}
}
void Account::viewBalance() const
{
system("cls");
cout << endl << "Account: " << name << endl << endl;
cout << "Balance: " << balance << endl << endl;
cout << "******** Click Enter To Return ********";
char ch;
ch = _getch();
while (ch != 13)
{
ch = _getch();
}
system("cls");
}
void Account::withdrawal()
{
system("cls");
string sAmount;
long double amount;
cout << "\t\t\t\t Withdrawal" << endl;
cout << endl << "Account: " << name << endl << endl;
cout << endl << " Amount Of Withdrawal: ";
getline(cin, sAmount);
for (unsigned int i = 0; i < sAmount.size(); ++i)
{
if (! isdigit(sAmount[i]))
{
cout << endl << "Invalid Amount!! \nAmount: ";
getline(cin, sAmount);
i = -1;
}
}
amount = atof(sAmount.c_str()); // it coverts the string to a float number
while (amount > balance)
{
cout << endl << "Insufficient Balance!!";
cout << endl << " Amount Of Withdrawal: ";
getline(cin, sAmount);
for (unsigned int i = 0; i < sAmount.size(); ++i)
{
if (! isdigit(sAmount[i]))
{
cout << endl << "Invalid Amount!! \n Amount Of Withdrawal: ";
getline(cin, sAmount);
i = -1;
}
}
/*
amount = strtod(sAmount.c_str(), nullptr);
amount = atof(sAmount.c_str());
*/
amount = stof(sAmount); // converting string to int
}
system("cls");
char option;
if (amount != 0)
{
cout << endl << "Account: " << name << endl << endl;
cout << "Withdrawal Amount: " << amount << endl << endl;
cout << setw(18) << "Confirm" << endl << endl;
cout << setw(10) << "1 -> Yes" << setw(20) << "Other -> No" << endl << endl;
cout << setw(15) << "-> ";
option = _getch();
switch (option)
{
case '1':
withdrawalLimit(amount);
balance -= amount;
logTransactions(account_num, "Withdrawal", amount);
break;
default:
withdrawal();
break;
}
ofstream drawFile (file_path);
drawFile << name << " " << account_num << " " << " " << balance << " " << pin; // updates the information in the account file
drawFile.close();
}
system("cls");
}
void Account::withdrawalLimit(int withdrawalAmount)
{
dayShiftCheck();
string sfile_path = Paths::ADMIN_WITHDRAWAL_VAL + account_num;
char buffer [256];
int amountDayDrawal;
ifstream file (sfile_path);
file.getline(buffer, 256);
istringstream amountFile (buffer);
amountFile >> amountDayDrawal;
file.close();
int amount_limit = amountDayDrawal + withdrawalAmount;
ofstream day_amount_file (sfile_path);
if ( amount_limit > 20000)
{
system("cls");
cout << "\a \n\n\n\n\n\n \t" << "Exceeded The Withdrawal Amount Limit For The Day" << endl << "\t" << "Withdrawal Amount Limit -> 20000" << endl;
Sleep(2000);
day_amount_file << amountDayDrawal;
day_amount_file.close();
ifstream file_stream (file_path);
myAccount(&file_stream);
}
else
{
day_amount_file << amount_limit;
day_amount_file.close();
}
}
// not complete
main.cpp
#include <iostream>
#include <windows.h>
#include "classAccount.h"
using namespace std;
int main()
{
cout << "\n\n\n\n\n\n \t\t\t\t\t" << "Helder Batalha" << endl;
Sleep(500);
system("cls");
Account acc;
acc.mainMenu();
return 0;
}
The file classAccount.cpp is not complete as it contains about 3000 lines of codes. So here is the file classAccount.cpp.