Skip to content

Commit 3f99332

Browse files
Merge pull request #327 from codebreaker64/branch-PED-bugs
Branch ped bugs
2 parents 3d815bd + 44d166a commit 3f99332

File tree

8 files changed

+195
-25
lines changed

8 files changed

+195
-25
lines changed

docs/DeveloperGuide.md

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- [Storage component](#storage-component)
1717
- [Common classes](#common-classes)
1818
- [Implementation](#implementation)
19+
- [Delete](#Delete-feature)
1920
- [Add Reservation Feature](#add-reservation-feature)
2021
- [[proposed] Undo/Redo](#proposed-undoredo-feature)
2122
- [Documentation, logging, testing, configuration, dev-ops](#documentation-logging-testing-configuration-dev-ops)
@@ -274,6 +275,50 @@ add occasions when not needed, it was made optional to improve user experience.
274275

275276
--------------------------------------------------------------------------------------------------------------------
276277

278+
### Delete feature
279+
280+
The delete feature allows restaurant managers to delete any unwanted or accidental reservations via the command `delete
281+
<INDEX> cfm`.
282+
283+
#### How is it implemented
284+
285+
The delete functionality is implemented through the `DeleteCommand` class. The feature is primarily made up of the
286+
following components:
287+
288+
1. `DeleteCommand` - Delete the reservation based on index shown on the list.
289+
2. `DeleteCommandParser` - Parses and validates the user input into a `DeleteCommand` object
290+
291+
#### Parsing the user input
292+
293+
1. The user enters a command in the format `delete 1 cfm`.
294+
2. The `LogicManager` passes the command string to `ReserveMateParser`.
295+
3. `ReserveMateParser` identifies the command as a `delete` command and delegates to `DeleteCommandParser`.
296+
4. `DeleteCommandParser` extracts and validates the index. If the index or `cfm` is missing, a parse
297+
exception will be thrown.
298+
5. `DeleteCommandParser` will create `DeleteCommand` object with the index.
299+
300+
#### Command execution
301+
302+
1. `LogicManager` calls the `execute()` method of the `DeleteCommand` object.
303+
2. The `DeleteCommand` will delete the reservation based on the index from the `Model`.
304+
305+
#### Displaying the result
306+
307+
A new `commandResult` with the success message is created and is returned to the `LogicManager`. The GUI would be
308+
updated.
309+
310+
![DeleteCommandResult](images/deleteCommandResult.png)
311+
312+
The following sequence diagram shows how the delete command works:
313+
![DeleteSequenceDiagram](images/DeleteSequenceDiagram.png)
314+
315+
#### Design Considerations
316+
317+
##### Making user type `cfm`
318+
319+
To prevent accidental deletions due to typing the wrong index, users are required to confirm their action by entering
320+
an additional 'cfm'. This extra step gives them time to double-check the index they’ve entered.
321+
277322
### [Proposed] Undo/redo feature
278323

279324
The proposed undo/redo mechanism is facilitated by `VersionedReserveMate`. It extends `ReserveMate` with an undo/redo
@@ -663,7 +708,7 @@ Priorities: High (Must have) - `* * *`, Medium (Good to have) - `* *`, Low (Exte
663708
Use Case ends.
664709

665710
* 2a. The reservation list is empty.
666-
711+
667712
* 2a1. ReserveMate shows an error message.
668713

669714
Use case ends.
@@ -1114,15 +1159,13 @@ and inefficiency. <br>
11141159
e.g., `d/2025-04-20 1800-2000`, allowing users to create a single reservation for multiple hours. Internally, the system
11151160
will auto-allocate the necessary consecutive slots without requiring the user to enter multiple commands.
11161161

1117-
11181162
2. **Simplify preference saving by removing redundant 'save' keyword in `pref` command**: <br>
11191163
**Current Issue**: The `pref` command currently requires users to type `pref save [index] [preference]`,
11201164
e.g., `pref save 1 sitting outdoors`. Since the `pref` command only supports saving preferences, the inclusion of the
11211165
`save` keyword is redundant and adds unnecessary typing for users. <br>
11221166
**Planned Enhancement**: We plan to simplify the command format by removing the need for the `save` keyword.
11231167
Users will be able to directly type `pref [index] [preference]`.
11241168

1125-
11261169
3. **Prevents accidental updates due to shifting list indexes after sorting**: <br>
11271170
**Current Issue**: After executing `pref save` or `edit` for a reservation at a given index, the list re-sorts
11281171
(by date, time and last insertion), which might cause indexes to change. If the user tries to update the same reservation
@@ -1153,7 +1196,6 @@ to within the next 60 days**. The inconsistency may mislead users into thinking
11531196
`Note: Reservations can only exist within 60 days from today. Filtering beyond this range will not return future
11541197
reservations.`
11551198

1156-
11571199
6. **Display preference and occasion tags in customer reservation details to differentiate similar reservations**: <br>
11581200
**Current Issues**: Currently, users have to manually type `show INDEX` each time they want to check the preferences
11591201
and occasions associated with a reservation. This process can be time-consuming and inefficient, especially for
@@ -1163,3 +1205,34 @@ make it difficult to differentiate between them. <br>
11631205
directly** in the reservation information. This allows users to quickly see preferences and occasions without having to
11641206
run an addition command. By incorporating **preferences and occasions**, reservations with similar names can be easily
11651207
differentiated. <br>
1208+
1209+
7. **Let users define the maximum number of reservations per hourly slot**: <br>
1210+
**Current Issue**: ReserveMate currently does not enforce a maximum number of reservations per time slot, which may not
1211+
fit the needs of all use cases. For instance, a venue with limited capacity might want to only allow a certain number
1212+
of concurrent reservations during peak hours. <br>
1213+
**Planned Enhancement**: We plan to introduce a configurable setting that allows admins or users (with the right
1214+
permissions) to define the maximum number of reservations allowed per hour slot. This offers greater flexibility for
1215+
different reservation scenarios and business rules.
1216+
1217+
8. **Change free command output format to show each available hour instead of a continuous range**: <br>
1218+
**Current Issue**: The `free` command currently displays available time in continuous ranges, e.g., `2025-04-28 0000 to
1219+
2025-04-28 1800`. While concise, this format may confuse users. They might interpret it as a single large continuous
1220+
block rather than individual 1-hour slots, or be uncertain whether a reservation can be made at the ending time. <br>
1221+
**Planned Enhancement**: We plan to revise the output format of the free command to explicitly show each available
1222+
starting reservation slot. For example:
1223+
```
1224+
Available free time slots:
1225+
- 2025-04-28 0000
1226+
- 2025-04-28 0100
1227+
...
1228+
- 2025-04-28 1700
1229+
```
1230+
1231+
9. **Relax phone number constraints to support international numbers for tourists**: <br>
1232+
**Current Issue**: The current phone number validation only accepts Singaporean numbers (8-digit numbers starting with
1233+
8 or 9), which excludes valid international phone numbers commonly used by tourists. This limitation may prevent
1234+
tourists from making reservations using the system. <br>
1235+
**Planned Enhancement**: We plan to relax the phone number
1236+
format to allow valid international formats, such as +44 7123 456789 or +1-202-555-0191. Validation will ensure proper
1237+
structure but allow flexibility in country codes. This makes the system more inclusive and tourist-friendly.
1238+

docs/UserGuide.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,10 +589,9 @@ Format: `delete <INDEX> cfm`
589589
> **Use Case #1**: Deleting the 2nd reservation after listing all.
590590
>
591591
> **Input:**
592-
>
593-
> `list`
594-
>
595-
> `delete 2 cfm`
592+
>
593+
> <br> 1. `list`
594+
> <br> 2. `delete 2 cfm`
596595
>
597596
> **Output:**
598597
> ```
@@ -605,9 +604,9 @@ Format: `delete <INDEX> cfm`
605604
>
606605
> **Input:**
607606
>
608-
> `find Jane`
609-
>
610-
> `delete 1 cfm`
607+
> <br> 1. `find Jane`
608+
> <br> 2. `delete 1 cfm`
609+
>
611610
>
612611
> **Output:**
613612
> ```
@@ -1158,6 +1157,11 @@ Format: `free <DATE>`
11581157
**Constraints**
11591158
- Date must be in `YYYY-MM-DD` format. Do not include `HHmm`.
11601159
1160+
**Note**
1161+
- Each reservation is 1 hour long. For example, if a time slot ends at `2025-04-28 1800`,
1162+
it means the available <br> time is from `2025-04-28 1700` to `2025-04-28 1800`.
1163+
So, you can add a reservation at `2025-04-28 1700`.
1164+
11611165
---
11621166
11631167
- **Successful Execution:**
@@ -1172,7 +1176,7 @@ Format: `free <DATE>`
11721176
> ```
11731177
> Available free time slots:
11741178
> - 2025-04-28 0000 to 2025-04-28 1800
1175-
> - 2025-04-28 1900 to 2025-04-28 2300
1179+
> - 2025-04-28 1900 to 2025-04-29 0000
11761180
> ```
11771181
>
11781182
> ---

docs/diagrams/tracing/LogicSequenceDiagram.puml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
skinparam ArrowFontStyle plain
44

55
Participant ":LogicManager" as logic LOGIC_COLOR
6-
Participant ":AddressBookParser" as abp LOGIC_COLOR
6+
Participant ":ReserveMateParser" as abp LOGIC_COLOR
77
Participant ":EditCommandParser" as ecp LOGIC_COLOR
88
Participant "command:EditCommand" as ec LOGIC_COLOR
99

@@ -14,7 +14,7 @@ create ecp
1414
abp -> ecp
1515
abp -> ecp ++: parse(arguments)
1616
create ec
17-
ecp -> ec ++: index, editCustomerDescriptor
17+
ecp -> ec ++: index, editReservationDescriptor
1818
ec --> ecp --
1919
ecp --> abp --: command
2020
abp --> logic --: command

src/main/java/seedu/reserve/logic/commands/FreeCommand.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public class FreeCommand extends Command {
3232
public static final String MESSAGE_ALL_FREE_SLOTS = "All timings are available on this date.";
3333
private static final Logger logger = LogsCenter.getLogger(FreeCommand.class);
3434
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm");
35+
private static final int MIN_SLOT_DURATION_HOURS = 1;
36+
private static final int DAYS_TO_ADD = 1;
3537

3638
private final ReservationBetweenDatePredicate predicate;
3739
private final LocalDateTime searchStart;
@@ -45,7 +47,7 @@ public class FreeCommand extends Command {
4547
public FreeCommand(DateTime date) {
4648
requireNonNull(date);
4749
this.searchStart = date.value;
48-
this.searchEnd = date.value.plusHours(23);
50+
this.searchEnd = date.value.plusDays(DAYS_TO_ADD);
4951
this.predicate = new ReservationBetweenDatePredicate(date,
5052
new DateTime(this.searchEnd.format(FORMATTER)));
5153
logger.fine("Created FreeCommand for date: " + date);
@@ -90,7 +92,7 @@ private List<TimeSlot> getAllFreeSlots(List<Reservation> reservations) {
9092
addSlotIfValid(freeSlots, searchStart, firstReservationStart);
9193

9294
// Check slots between reservations
93-
LocalDateTime previousEnd = firstReservationStart.plusHours(1);
95+
LocalDateTime previousEnd = firstReservationStart.plusHours(MIN_SLOT_DURATION_HOURS);
9496
for (int i = 1; i < reservations.size(); i++) {
9597
LocalDateTime currentStart = reservations.get(i).getDateTime().value;
9698
addSlotIfValid(freeSlots, previousEnd, currentStart);

src/main/java/seedu/reserve/logic/parser/FreeCommandParser.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,5 @@ public FreeCommand parse(String args) throws ParseException {
4545
}
4646

4747
return new FreeCommand(date);
48-
4948
}
50-
51-
52-
53-
5449
}

src/main/java/seedu/reserve/logic/parser/ShowCommandParser.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* Parses input arguments and creates a new ShowCommand object
1616
*/
1717
public class ShowCommandParser implements Parser<ShowCommand> {
18-
1918
private static final Logger logger = LogsCenter.getLogger(ShowCommandParser.class);
2019

2120
/**

src/test/java/seedu/reserve/logic/commands/FreeCommandTest.java

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void execute_hasFreeSlots_showsFreeSlots() {
4242
String expectedMessage = "Available free time slots:"
4343
+ "\n- 2025-05-01 0000 to 2025-05-01 1000"
4444
+ "\n- 2025-05-01 1100 to 2025-05-01 1400"
45-
+ "\n- 2025-05-01 1500 to 2025-05-01 2300";
45+
+ "\n- 2025-05-01 1500 to 2025-05-02 0000";
4646

4747
assertCommandSuccess(freeCommand, model, expectedMessage, model);
4848
}
@@ -72,7 +72,7 @@ public void execute_freeSlotBeforeFirstReservation_showsEarlySlot() {
7272
FreeCommand freeCommand = new FreeCommand(new DateTime(TEST_DATE.toString()));
7373
String expectedMessage = "Available free time slots:"
7474
+ "\n- 2025-05-01 0000 to 2025-05-01 1200"
75-
+ "\n- 2025-05-01 1300 to 2025-05-01 2300";
75+
+ "\n- 2025-05-01 1300 to 2025-05-02 0000";
7676

7777
assertCommandSuccess(freeCommand, model, expectedMessage, model);
7878
}
@@ -87,7 +87,55 @@ public void execute_freeSlotAfterLastReservation_showsLateSlot() {
8787
FreeCommand freeCommand = new FreeCommand(new DateTime(TEST_DATE.toString()));
8888
String expectedMessage = "Available free time slots:"
8989
+ "\n- 2025-05-01 0000 to 2025-05-01 0800"
90-
+ "\n- 2025-05-01 0900 to 2025-05-01 2300";
90+
+ "\n- 2025-05-01 0900 to 2025-05-02 0000";
91+
92+
assertCommandSuccess(freeCommand, model, expectedMessage, model);
93+
}
94+
95+
@Test
96+
public void execute_singleReservationAtStartOfDay_showsCorrectSlots() {
97+
Reservation r1 = new ReservationBuilder()
98+
.withDateTime(TEST_DATE.value.format(FORMATTER)) // Exactly at start of day
99+
.build();
100+
model.addReservation(r1);
101+
102+
FreeCommand freeCommand = new FreeCommand(new DateTime(TEST_DATE.toString()));
103+
String expectedMessage = "Available free time slots:"
104+
+ "\n- 2025-05-01 0100 to 2025-05-02 0000";
105+
106+
assertCommandSuccess(freeCommand, model, expectedMessage, model);
107+
}
108+
109+
@Test
110+
public void execute_singleReservationAtEndOfDay_showsCorrectSlots() {
111+
Reservation r1 = new ReservationBuilder()
112+
.withDateTime(TEST_DATE.value.plusHours(23).format(FORMATTER)) // Last hour of day
113+
.build();
114+
model.addReservation(r1);
115+
116+
FreeCommand freeCommand = new FreeCommand(new DateTime(TEST_DATE.toString()));
117+
String expectedMessage = "Available free time slots:"
118+
+ "\n- 2025-05-01 0000 to 2025-05-01 2300";
119+
120+
assertCommandSuccess(freeCommand, model, expectedMessage, model);
121+
}
122+
123+
@Test
124+
public void execute_consecutiveReservations_showsSingleGap() {
125+
// 10-11 and 11-12 (should show as one continuous free slot after)
126+
Reservation r1 = new ReservationBuilder()
127+
.withDateTime(TEST_DATE.value.plusHours(10).format(FORMATTER))
128+
.build();
129+
Reservation r2 = new ReservationBuilder()
130+
.withDateTime(TEST_DATE.value.plusHours(11).format(FORMATTER))
131+
.build();
132+
model.addReservation(r1);
133+
model.addReservation(r2);
134+
135+
FreeCommand freeCommand = new FreeCommand(new DateTime(TEST_DATE.toString()));
136+
String expectedMessage = "Available free time slots:"
137+
+ "\n- 2025-05-01 0000 to 2025-05-01 1000"
138+
+ "\n- 2025-05-01 1200 to 2025-05-02 0000";
91139

92140
assertCommandSuccess(freeCommand, model, expectedMessage, model);
93141
}

src/test/java/seedu/reserve/logic/parser/FreeCommandParserTest.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
import static seedu.reserve.logic.parser.CommandParserTestUtil.assertParseFailure;
66
import static seedu.reserve.logic.parser.CommandParserTestUtil.assertParseSuccess;
77

8+
import java.time.LocalDate;
9+
import java.time.LocalDateTime;
10+
import java.time.format.DateTimeFormatter;
11+
812
import org.junit.jupiter.api.Test;
913

1014
import seedu.reserve.logic.Messages;
1115
import seedu.reserve.logic.commands.FreeCommand;
1216
import seedu.reserve.model.reservation.DateTime;
1317

1418
public class FreeCommandParserTest {
19+
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
20+
1521
private FreeCommandParser parser = new FreeCommandParser();
1622

1723
@Test
@@ -47,6 +53,49 @@ public void parse_invalidArgs_throwsParseException() {
4753
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FreeCommand.MESSAGE_USAGE));
4854
}
4955

56+
@Test
57+
public void parse_whitespaceOnly_throwsParseException() {
58+
// Various whitespace patterns
59+
assertParseFailure(parser, " ",
60+
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FreeCommand.MESSAGE_USAGE));
61+
62+
assertParseFailure(parser, " d/ ",
63+
DateTime.MESSAGE_CONSTRAINTS_FREE);
64+
}
65+
66+
@Test
67+
public void parse_withExplicitTime_throwsParseException() {
68+
// Should reject if time is explicitly specified
69+
assertParseFailure(parser, " d/2025-05-01 1200",
70+
DateTime.MESSAGE_CONSTRAINTS_FREE);
71+
72+
assertParseFailure(parser, " d/2025-05-01 0000",
73+
DateTime.MESSAGE_CONSTRAINTS_FREE);
74+
}
75+
76+
@Test
77+
public void parse_caseInsensitivePrefix_validCommand() {
78+
// Should work with different prefix cases
79+
assertParseSuccess(parser, " D/2025-05-01",
80+
new FreeCommand(new DateTime("2025-05-01 0000")));
81+
}
82+
83+
@Test
84+
public void parse_dateBeyond60Days_throwsParseException() {
85+
LocalDateTime today = LocalDate.now().atStartOfDay();
86+
87+
String invalidDateStr = today.plusDays(61).format(FORMATTER);
88+
String boundaryDateStr = today.plusDays(59).format(FORMATTER);
89+
90+
// Test invalid case (61 days)
91+
assertParseFailure(parser, " d/" + invalidDateStr,
92+
DateTime.MESSAGE_CONSTRAINTS_FREE);
93+
94+
// Test boundary case (60 days)
95+
assertParseSuccess(parser, " d/" + boundaryDateStr,
96+
new FreeCommand(new DateTime(boundaryDateStr + " 0000")));
97+
}
98+
5099
@Test
51100
public void parse_multipleDates_throwsParseException() {
52101
// Multiple dates

0 commit comments

Comments
 (0)