forked from samuelstacey/Financial-Tracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSavings.java
More file actions
363 lines (338 loc) · 14.5 KB
/
Savings.java
File metadata and controls
363 lines (338 loc) · 14.5 KB
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
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.time.Instant;
import java.util.InputMismatchException;
/**
* Total Savings
* @author Luke
*/
public class Savings {
private boolean running;
/**
* Will show all options when managing their savings pools and prompt for them to choose one
*/
public void mainMenu(){
running = true;
while (running) {
System.out.println("Please select an option by using the number associated with each command:\n" +
"1. Add new savings pool\n" +
"2. Edit an existing savings pool\n" +
"3. Delete a savings pool\n" +
"4. View your savings pools\n" +
"5. Return to main menu");
try {
String input = App.userIn.readLine();
inputChecker(input);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Unable to take input from console");
} catch (SQLException e){
e.printStackTrace();
System.out.println("Unable to get info from table");
}
}
}
/**
* takes input from main menu and calls correct method
* @param input their choice from main menu options
*/
private void inputChecker(String input) throws IOException, SQLException {
switch (input) {
case "1":
newSavingPool();
break;
case "2":
editSavingPool();
break;
case "3":
removeSavingPool();
break;
case "4":
printAllSavingPools();
break;
case "5":
running = false;
System.out.println("Exiting to Main Menu...\n\n");
break;
default:
System.out.println("Not an option. Choose again");
}
}
/**
* Will prompt for the following and add them as a new pool in table:
* - Name
* - Amount to save
* - starting amount (optional)
* - monthly contribution (option)
* - date to save until
*
* @throws InputMismatchException security incase they give a int for string, or something similar
* @throws IOException if we cant read from console
*/
public void newSavingPool() throws InputMismatchException, IOException, SQLException {
boolean cont = false;
// Name
System.out.println("First, what is the name of the category?");
String name = App.userIn.readLine();
while(!cont){
if(RetrieveAndStore.exists("tblSavings","SavingsAccountName", name)){
System.out.println("A pool with that name already exists, try another:");
name = App.userIn.readLine();
} else {
cont = true;
}
}
cont = false;
// Amount they want to save in the new pool
System.out.println("Awesome, how much do you want to save? (in £)");
String goalString = App.userIn.readLine();
if (!Validation.isDouble(goalString)) return;
double goal = Double.parseDouble(goalString);
while (!cont) { // Will loop until they give a valid input for the amount they want to save
if (goal > 0) {
cont = true;
} else {
System.out.println("Invalid amount, how much do you want to save?");
goalString = App.userIn.readLine();
if (!Validation.isDouble(goalString)) continue;
goal = Double.parseDouble(goalString);
}
}
// If they already have something saved in the account (Optional)
System.out.println("And do you have anything saved here already? (Y/N)");
cont = false;
double startingAmount = 0;
String temp = App.userIn.readLine();
if (temp.toLowerCase().equals("y") || temp.toLowerCase().equals("yes")) {
// If they say yes or y to haveing something pre-saved
System.out.println("How much?");
String startingAmountString = App.userIn.readLine();
if (!Validation.isDouble(startingAmountString)) return;
startingAmount = Double.parseDouble(startingAmountString);
while (!cont) { // Loop until they give a valid amount
if (startingAmount > 0) {
cont = true;
} else {
System.out.println("Invalid amount, how much do you want to save?");
startingAmountString = App.userIn.readLine();
if (!Validation.isDouble(startingAmountString)) continue;
startingAmount = Double.parseDouble(startingAmountString);
}
}
}
// If they will be making a monthly contribution to their pool (Optional)
System.out.println("And will you be making monthly contributions? (Y/N)");
temp = App.userIn.readLine();
double monthlyContribution = 0;
if (temp.toLowerCase().equals("y") || temp.toLowerCase().equals("yes")) {
// If they say yes or y to making monthly contributions
cont = false;
System.out.println("How much?");
String monthlyContributionString = App.userIn.readLine();
if (!Validation.isDouble(monthlyContributionString)) return;
monthlyContribution = Double.parseDouble(monthlyContributionString);
while (!cont) { // Loop until they give a valid amount
if (monthlyContribution > 0) {
cont = true;
} else {
System.out.println("Invalid amount, how much do you want to save?");
monthlyContributionString = App.userIn.readLine();
if (!Validation.isDouble(monthlyContributionString)) continue;
monthlyContribution = Double.parseDouble(monthlyContributionString);
}
}
}
//will get todays date, for use when creating a new table entry
String today = Instant.now().toString();
today = today.substring(8,10) + "/" + today.substring(5,7) + "/" + today.substring(0,4);
//When they want to have the money saved by
System.out.println("Lastly, when do you want to meet this goal? (DD/MM/YYYY)");
String dateToAchieve = App.userIn.readLine();
// Will check if date is in valid format and it is after today
if (!validDate.validFormat(dateToAchieve) || !validDate.compareStringDates(today,dateToAchieve)) {
System.out.println("Invalid date!");
return;
}
if (doesGoalExist(name)) {
RetrieveAndStore.sqlExecute("DELETE FROM tblSavings WHERE SavingsAccountName = '" + name + "'");
}
RetrieveAndStore.sqlExecute("INSERT INTO tblSavings (ID, SavingsAccountName, SavingsGoal, CurrentSavings, " +
"MonthlyContribution, DateCreated, DateProjected) VALUES ("
+ (RetrieveAndStore.maxID("tblSavings", "ID") + 1) + ", '" + name + "', " + goal + ", " +
startingAmount + ", " + monthlyContribution + ", '" + today + "', '" + dateToAchieve + "')");
RetrieveAndStore.rowNumberUpdater("tblSavings","ID");
System.out.println("Great stuff, lets get saving!\n\n");
}
/**
* Allow a user to see all their saving pools
* Made static so can be used in RequestData
* @see RequestData
*/
public static void printAllSavingPools(){
ResultSet rs = RetrieveAndStore.readAllRecords("tblSavings");
try {
while (rs.next()) //Loop through the resultset
{
//Store each budget record to print
int id = rs.getInt("ID");
String name = rs.getString("SavingsAccountName");
double goal = rs.getDouble("SavingsGoal");
double currentSavings = rs.getDouble("CurrentSavings");
double contribution = rs.getDouble("MonthlyContribution");
String dateCreated = rs.getString("DateCreated");
String dateLimit = rs.getString("DateProjected");
// Work out todays date in dd/mm/yyyy format
String today = Instant.now().toString();
today = today.substring(8,10) + "/" + today.substring(5,7) + "/" + today.substring(0,4);
//calculate projections
String projection = "You'll hit your goal "; // Pre-write first half of string to stop repeat code
double time;
double leftToGo = goal-currentSavings; // How far they are from their goal in £
// Checks we wont get 0 division and they haven't yet hit their goal
if (contribution != 0 && currentSavings < goal) {
// If they'll hit their goal EXACTLY on a payment (extra month needed if they dont)
if (leftToGo % contribution == 0) {
if ((time = leftToGo / contribution) == 1) {
projection += "next month! Good Job";
} else { // Tells them how long till they hit their goal
projection += "in " + (int) time + " months, the " + validDate.addMonths(today, (int) time)
+ "\nTIP: Dont worry if that seems like a long time off, with the right bank " +
"(and possibly the right investments too!) that time can always be reduced!";
}
} else { // If they wont hit it on a payment, an extra month will be needed
if ((time = leftToGo / contribution) < 1) { // Check if they will be overpaying
projection += "next month! Good Job";
} else { // Tells them how long till they hit their goal
projection += "in " + (int) time + " months, the " + validDate.addMonths(today, (int) time + 1)
+ "\nTIP: Dont worry if that seems like a long time off, with the right bank " +
"(and possibly the right investments too!) that time can always be reduced!";
}
}
} else if (goal < currentSavings){ // If they hit they hit the saving goal already
projection = "Great work, you've already met your savings goal!";
} else { // If they not contributing offer a friendly reminder that 'every little helps' - Tesco (TM)
projection = "Oh no, it looks like you not saving any extra per month.\n" +
"TIP: Remember, even the smallest amounts of savings can add up in time, especially in a high interest account!";
}
// print the results
System.out.format("%d: %s\nPool: £%.2f/£%.2f @ £%.2fpm\n%s - %s\n%s\n\n", id, name, currentSavings, goal, contribution,
dateCreated, dateLimit, projection);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Allow them to edit any field (except ID) for a pool
* @throws IOException if we cant read from console
*/
public void editSavingPool() throws IOException {
printAllSavingPools(); // Show them all their pools
System.out.println("Please enter the ID number of the Pool you would like to update:");
String poolIDString = App.userIn.readLine();
if (!Validation.isInteger(poolIDString)) return;
int poolID = Integer.parseInt(poolIDString); // Must be less than one as row ID's start from 0 (not anymore they don't)
// Check it is a valid ID
if (!Validation.isRangeValid(1, RetrieveAndStore.maxID("tblSavings", "ID"), poolID)) return;
ResultSet rs = RetrieveAndStore.readAllRecords("tblSavings");
try {
ResultSetMetaData rsmd = rs.getMetaData();
System.out.println("Great, which entry would you liked to update?");
for (int i = 2; i <= rsmd.getColumnCount(); i++) { // Loop through all columns and print column name
System.out.println(String.format("%d: %s", i-1, rsmd.getColumnName(i)));
}
// They choose one of the columns printed above
String columnIntString = App.userIn.readLine();
if (!Validation.isInteger(columnIntString)) return;
int columnInt = Integer.parseInt(columnIntString)+1;
if (!Validation.isRangeValid(2, rsmd.getColumnCount(), columnInt)) return;
String columnName = rsmd.getColumnName(columnInt);
System.out.println("Please input a new value for " + columnName);
if (3<=columnInt && columnInt<=5) { // If they choose a column which takes an integer (e.g. Savings goal) - Double
String newValueString = App.userIn.readLine();
if (!Validation.isDouble(newValueString) || Double.parseDouble(newValueString) <= 0) return;
if(newValueString.contains(".")){
int decimalPos = newValueString.indexOf('.');
if ((newValueString.length() - 1) - decimalPos > 2) {
System.out.println("Invalid number, too precise");
return;
}
}
double newValue = Double.parseDouble(newValueString);
RetrieveAndStore.sqlExecute(String.format("UPDATE %s SET %s = %.2f WHERE %s = %d", "tblSavings",
columnName, newValue, "ID", poolID));
} else if (columnInt == 6 || columnInt == 7){ // For date created and date they aim to meet their goal - String, but in date format
String newValue = App.userIn.readLine();
String today = Instant.now().toString();
today = today.substring(8,10) + "/" + today.substring(5,7) + "/" + today.substring(0,4);
if(!validDate.validFormat(newValue)){
System.out.println("Not a valid date format");
return;
}
rs.next();
for (; rs.getInt("ID") == poolID; rs.next());
if(columnInt == 6 && validDate.compareStringDates(today, newValue, true)
&& validDate.compareStringDates(newValue, rs.getString("DateProjected"))){
// If they change date created, they can choose today as a date.
// No need to let them choose an earlier date but cant be later then when they want it to be done
RetrieveAndStore.sqlExecute(String.format("UPDATE %s SET %s = '%s' WHERE %s = %s", "tblSavings",
columnName, newValue, "ID", poolID));
} else if(columnInt == 7 && validDate.compareStringDates(today, newValue)
&& validDate.compareStringDates(rs.getString("DateCreated"),newValue)){
// Check its after today and after the day the pool was created
RetrieveAndStore.sqlExecute(String.format("UPDATE %s SET %s = '%s' WHERE %s = %s", "tblSavings",
columnName, newValue, "ID", poolID));
} else {
System.out.println("Invalid Time Frame");
return;
}
} else { // For everything else (i.e. category name) - String
String newValue = App.userIn.readLine();
if(RetrieveAndStore.exists("tblSavings","SavingsAccountName",newValue)) {
System.out.println("A pool with that name already exists.\n");
return;
}
RetrieveAndStore.sqlExecute(String.format("UPDATE %s SET %s = '%s' WHERE %s = %d", "tblSavings",
columnName, newValue, "ID", poolID));
}
System.out.println("\n\nSuccessfully update field " + columnName);
} catch (SQLException e) {
e.printStackTrace();
}
}
/**
* Remove a pool from the table
* @throws IOException if it cant receive input from console
*/
public void removeSavingPool() throws IOException {
System.out.println("\n\n");
printAllSavingPools(); // Show them all their current pools
System.out.println("Please enter the ID number of the Pool you would like to delete:");
String poolIDString = App.userIn.readLine();
if (!Validation.isInteger(poolIDString)) return;
int poolID = Integer.parseInt(poolIDString);
if (!Validation.isRangeValid(1, RetrieveAndStore.maxID("tblSavings", "ID"), poolID)) return;
RetrieveAndStore.sqlExecute(String.format("DELETE FROM %s WHERE %s = %d", "tblSavings", "ID", poolID));
RetrieveAndStore.rowNumberUpdater("tblSavings", "ID");
System.out.println("Done, its deleted, gone forever, turned to smithereens, never to be seen again...\n\n");
}
public boolean doesGoalExist(String proposedName) {
ResultSet rs = RetrieveAndStore.readAllRecords("tblSavings");
try {
while (rs.next()) // Loop through the user table
{
// Store username and password to verify inputs
String name = rs.getString("SavingsAccountName");
//compare inputs to db records
if ((proposedName.equals(name))) {
return true;
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
}