This repository was archived by the owner on Dec 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBankAccount.cpp
469 lines (422 loc) · 21.1 KB
/
BankAccount.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
// Implementation of class
#include <fstream> // Used to read/write to a txt file
#include <limits> // Used to handle invalid input std::cin
#include <cmath> // Round used in input_precision_check
#include "BankAccount.h"
/*
* *************************************************************************************************************
* The methods below focus on what the users can do once they log in to their respective account
* *************************************************************************************************************
*/
void BankAccount::user_menu(std::vector<BankAccount>& all_bank_accounts){
// Show user a menu to choose an option
bool return_to_user_menu {true}; // Use for options that need to return the user to the User Menu
do{
return_to_user_menu = true;
int user_choice {};
std::cout << "\n___User_Menu___" << std::endl;
std::cout << "Please choose an option" << std::endl;
std::cout << "1: Deposit\n"
"2: Withdraw\n"
"3: Check Balance\n"
"4: Transfer to Another User\n"
"5: Return to Main Menu\n"
"Choice: ";
std::cin >> user_choice;
// When input is an int, std::cin is 1, true; other types will return 0, false
// If a value with decimals is entered, then user_choice will automatically round down to int
if (!std::cin){
// Input is NOT an int
std::cin.clear(); //clear bad input flag if user doesn't input an int
// Remove the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error: Invalid input. Please enter an integer." << std::endl;
// Will return to user menu
}
else{
// Input is an int, continue
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (user_choice == 1){
deposit();
// Will return to user menu
}
else if (user_choice == 2){
withdraw();
// Will return to user menu
}
else if (user_choice == 3){
std::cout << "Account: " << Name << std::endl;
std::cout << "Balance: $" << get_user_balance() << std::endl;
// Will return to user menu
}
else if (user_choice == 4){
bool transfer_status;
transfer_status = transfer_to_another_user(all_bank_accounts);
if (transfer_status){
std::cout << "Transfer successful." << std::endl;
}
else{
std::cout << "Transfer Failed." << std::endl;
}
// Will return to user menu
}
else if (user_choice == 5){
std::cout << "Returning to Main Menu" << std::endl;
std::cout << std::endl;
return_to_user_menu = false;
// Will NOT return to user menu
}
else{
std::cout << "Error: Invalid choice. Please enter a valid option." << std::endl;
// Will return to user menu
}
}
}
while (return_to_user_menu);
}
void BankAccount::deposit(){
double user_deposit {};
std::cout << "How much would you like to deposit? $";
std::cin >> user_deposit;
// When input is an int or double, std::cin is 1, true; other types will return 0, false
if (!std::cin){
// Input is NOT an int or double
std::cin.clear(); //clear bad input flag if user doesn't input an int
// Remove the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error: Invalid input. Please enter an integer or double." << std::endl;
// Will return to user menu
}
else{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (user_deposit < 0.0){
// Prevent depositing a negative number
std::cout << "Error: Negative number entered. Cannot deposit $" << user_deposit << std::endl;
std::cout << "Please try again." << std::endl;
}
else{
user_deposit = input_precision_check(user_deposit);
Balance = Balance + user_deposit;
std::cout << "Successfully deposited $" << user_deposit << std::endl;
}
}
}
void BankAccount::auto_deposit(double user_deposit){
// This method is the same as deposit but does not include correspondence with user
Balance = Balance + user_deposit;
}
void BankAccount::withdraw(){
double user_withdraw {};
std::cout << "How much would you like to withdraw? $";
std::cin >> user_withdraw;
// When input is an int or double, std::cin is 1, true; other types will return 0, false
if (!std::cin){
// Input is NOT an int or a double
std::cin.clear(); //clear bad input flag if user doesn't input an int
// Remove the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error: Invalid input. Please enter an integer or double." << std::endl;
// Will return to user menu
}
else{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (Balance - user_withdraw < 0.0){
// Prevent withdrawing more than what is in the account
std::cout << "Error: Insufficient Funds. Cannot withdraw $" << user_withdraw << std::endl;
std::cout << "Please try again." << std::endl;
}
else if (user_withdraw < 0.0){
// Prevent withdrawing a negative number
std::cout << "Error: Negative number entered. Cannot withdraw $" << user_withdraw << std::endl;
std::cout << "Please try again." << std::endl;
}
else{
user_withdraw = input_precision_check(user_withdraw);
Balance = Balance - user_withdraw;
std::cout << "Withdrawal of $" << user_withdraw << " successful." << std::endl;
}
}
}
double BankAccount::get_user_balance() const{
return Balance;
}
std::string BankAccount::get_user_name() const{
return Name;
}
bool BankAccount::transfer_to_another_user(std::vector<BankAccount>& all_bank_accounts){
std::string transfer_to_name {};
double transfer_balance {0.0};
bool transfer_status {false}; // Assume the transfer will fail
std::cout << "What is the name on the account that you want to transfer to? ";
getline(std::cin, transfer_to_name);
// Verify name of account to transfer to
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){ // Loop through vector of bank accounts to find requested name
if (all_bank_accounts[i].get_user_name() == transfer_to_name){
// The account exists, so continue transfer process
std:: cout << "How much would you like to transfer? $";
std::cin >> transfer_balance;
// When input is an int or double, std::cin is 1, true; other types will return 0, false
if (!std::cin){
// Input is NOT an int or a double
std::cin.clear(); //clear bad input flag if user doesn't input an int
// Remove the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error: Invalid input. Please enter an integer or double." << std::endl;
return transfer_status;
// Will return to user menu (Failed)
}
else{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Check to see if user can transfer the requested amount to another user
if (Balance - transfer_balance < 0.0){
std::cout << "Error: Insufficient Funds. Cannot transfer $" << transfer_balance << std::endl;
return transfer_status;
// Will return to user menu (Failed)
}
else{
transfer_balance = input_precision_check(transfer_balance);
Balance = Balance - transfer_balance; // Remove money from current user's account
std::cout << "Successfully deposited $" << transfer_balance << std::endl;
// Deposit transfer balance to other user's account
all_bank_accounts[i].auto_deposit(transfer_balance);
transfer_status = true;
return transfer_status;
// Will return to user menu (Success)
}
}
}
}
std::cout << "The account for " << transfer_to_name << " does not exist." << std::endl;
return transfer_status;
// Will return to user menu (Failed)
}
double BankAccount::input_precision_check(double user_input){
// Make sure user_input is to only two decimals (Equivalent to rounding down to two decimals)
int original_whole {(int)user_input}; // Only the whole number of the original value
double original_decimals {}; // Only the decimals of the original value
/*
user_input - (double)original_whole; // Remove the whole number from user input to get only decimals
(user_input - (double)original_whole)*100; // Multiply by 100 to isolate two decimal values
round((user_input - (double)original_whole)*100); // Round if user inputs more than two decimals
(int)((user_input - (double)original_whole)*100); // Convert to int to get only the two decimal values
(double)((int)((user_input - (double)original_whole)*100)); // Convert to double to prepare for division
((double)((int)((user_input - (double)original_whole)*100)))/100; // Divide by 100 to convert back to two decimal values
*/
original_decimals = ((double)((int)round(((user_input - (double)original_whole)*100))))/100;
user_input = original_whole + original_decimals; // Add both parts to get original to only two decimals
return user_input;
}
/*
* *************************************************************************************************************
* The functions below focus on what users can do with their accounts
* *************************************************************************************************************
*/
void new_bank_account(std::vector<BankAccount>& all_bank_accounts){
std::string input_name;
bool name_taken {false}; // Assume name is available
do{
name_taken = false;
std::cout << "We are excited you want to create an account with us!\nPlease begin by entering your name: ";
getline(std::cin, input_name);
// Go through each name in all_bank_accounts vector to see if the input_name is already taken
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){
if (all_bank_accounts[i].get_user_name() == input_name){
// Name is already taken
name_taken = true;
std::cout << input_name << " is already used. Please enter a different name." << std::endl;
std::cout << std::endl;
}
}
if (!name_taken){
// Name entered is available
name_taken = false;
std::cout << input_name << " is available." << std::endl;
BankAccount user(input_name); // Create the bank account object for this user
all_bank_accounts.push_back(user); // Store a copy of the object in the all_bank_accounts vector because the original will be erased at the end of this scope
std::cout << "Account created for " << input_name << std::endl;
std::cout << std::endl;
}
}
while(name_taken);
}
void remove_bank_account(std::vector<BankAccount>& all_bank_accounts){
std::string input_name;
bool account_exists = false;
std::cout << "What is the name on the account that you wish to remove? ";
getline(std::cin, input_name);
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){ // Loop through all accounts in all_bank_accounts vector
if (all_bank_accounts[i].get_user_name() == input_name){
all_bank_accounts.erase(all_bank_accounts.begin()+ i); // Erase user's bank account in vector
std::cout << input_name << "'s Account Removed." << std::endl;
std::cout << std::endl;
account_exists = true;
}
}
if (!account_exists){
std::cout << "Error: This account does not exist. Please try again." << std::endl;
}
}
void show_all_bank_accounts(const std::vector<BankAccount>& all_bank_accounts){
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){
std::cout << "User: " << all_bank_accounts[i].get_user_name() << std::endl;
std::cout << "Balance: $" << all_bank_accounts[i].get_user_balance() << std::endl;
std::cout << std::endl;
}
}
bool valid_login(const std::vector<BankAccount>& all_bank_accounts, const std::string& user_input){
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){
if (all_bank_accounts[i].get_user_name() == user_input){
return true;
}
}
return false; // Did not find login in vector of bank accounts
}
void main_menu(std::vector<BankAccount>& all_bank_accounts){
// Begin Main Menu
// Log in, Create a new account, delete an account, or exit bank
bool return_to_main_menu {true};
int user_choice {};
do{
std::cout << "___Main_Menu___" << std::endl;
std::cout << "1: Log In\n"
"2: Create A New Account\n"
"3: Delete an Account\n"
"4: Quit\n"
"Choice: ";
std::cin >> user_choice;
// When input is an int, std::cin is 1, true; other types will return 0, false
// If a value with decimals is entered, then user_choice will automatically round down to int
if (!std::cin){
// Input is NOT an int
std::cin.clear(); //clear bad input flag if user doesn't input an int
// Remove the bad input
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Error: Invalid input. Please enter an integer." << std::endl;
// Will return to user menu
}
else{
//std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (user_choice == 1){
// If the bank account vector is empty, then return to main menu
if (all_bank_accounts.empty()){
std::cout << "Error: There are currently no bank accounts. Please create an account.\n" << std::endl;
// Will return to main menu
}
else{
// Log in using login
std::string user_input {};
bool is_login_valid {false}; // Assume login is incorrect for security
std::cout << "Please enter the name associated with your account: ";
getline(std::cin, user_input);
// Not needed for string input
//std::cin.clear();
//std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Check if name is in the system
is_login_valid = valid_login(all_bank_accounts, user_input);
if (is_login_valid){
// Move into user menu for this specific user
std::cout << "Log in Successful." << std::endl;
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
for (unsigned int i = 0; i < vector_size; i++){
if (all_bank_accounts[i].get_user_name() == user_input){ // Find the account that matches the login
all_bank_accounts[i].user_menu(all_bank_accounts); // Go to user menu
// Will return to main menu after exiting user menu
}
}
}
else{
std::cout << "Error: Invalid login. There is no account with that name." << std::endl;
std::cout << std::endl;
// Will return to main menu
}
}
}
else if (user_choice == 2){
// Create new bank account
new_bank_account(all_bank_accounts); // Pass in vector of all bank accounts to store new bank account object
// Will return to main menu
}
else if (user_choice == 3){
// If the bank account vector is empty, then return to main menu
if (all_bank_accounts.empty()){
std::cout << "Error: There are currently no bank accounts. Please create an account.\n" << std::endl;
}
else{
// Delete a bank account
remove_bank_account(all_bank_accounts); // Pass in vector of all bank accounts to remove user's bank account object
// Will return to main menu
}
}
else if (user_choice == 4){
// Quit the program
std::cout << "Have a nice day!" << std::endl;
return_to_main_menu = false;
}
/*
else if (user_choice == 5){
// Display all the accounts
// ONLY USED FOR DEBUGGING
show_all_bank_accounts(all_bank_accounts);
}
*/
else{
std::cout << "Error: Invalid choice. Please try again." << std::endl;
}
}
std::cout << std::endl;
}
while(return_to_main_menu);
}
bool save_accounts(std::vector<BankAccount>& all_bank_accounts, const std::string& defaultDirectory){
// Variable name of txt file; used to write all bank account information at the end of the program
std::fstream loginFile;
std::string line; // Variable to hold line that the program is currently on
// Overwrite txt file with updated information from all accounts in all_bank_accounts vector
loginFile.open(defaultDirectory + "login_file.txt", std::ios::out | std::ios::trunc);
unsigned int vector_size = all_bank_accounts.size(); // Size of vector does not change, so just call the size once
if (loginFile.is_open()){
for (unsigned int i = 0; i < vector_size; i++){
// Write user information to login_file.txt
loginFile << all_bank_accounts[i].get_user_name() << std::endl;
loginFile << all_bank_accounts[i].get_user_balance() << std::endl;
}
loginFile.close();
return true;
}
else{
std::cout << "Error: Login file could not be opened." << std::endl;
return false;
}
}
void upload_accounts(std::vector<BankAccount>& all_bank_accounts, const std::string& defaultDirectory){
// Variable name of txt file; used to read then store all bank account information to all_bank_accounts vector
// at the beginning of the program
std::fstream loginFile;
std::string line_name; // Variable to hold line that the program is currently on
std::string line_balance;
loginFile.open(defaultDirectory + "login_file.txt", std::ios::in); // Read txt file and record all data to all_bank_accounts vector
if (loginFile.is_open()){
while(getline(loginFile, line_name)) { // Loop through txt file until there is a blank line
BankAccount user(line_name); // Create an object with the name on this line
getline(loginFile, line_balance); // Get the balance for this account (Line after the user's name)
user.BankAccount::auto_deposit(std::stod(line_balance)); // Update the balance for this account
all_bank_accounts.emplace_back(user); // Copy object to vector because the current object will be deleted after exiting the scope
}
loginFile.close();
}
else{
// std::cout << "Log in file does not exist." << std::endl;
// No worries if there is no login_file.txt at the beginning of the program.
// Program will create file and save all account information at the end of the program.
}
}