Skip to content

Commit

Permalink
Add importAll command (nus-cs2103-AY1718S2#78)
Browse files Browse the repository at this point in the history
* fix merge errors

* Add dummy classes to support import feature

* Add details in JobEntry and SessionData

* more edits

* Add classes to support ImportSession

* Apply SLAP to make methods smaller

* Add ImportSession method to read excel file.

* Add SheetHeaderFields class

* Add SheetWithHeaderFields to extract row and column operations

* Finish ImportSession feature to write to file

* trailing whitespace

* Extract messages in ImportSession as constants. Write dummy ImportAllCommand, with functional support classes.

* Use unmodifiableList for getting lists in sessionData and jobEntry.

* Implement importAll command

* fix modelStub

* fix checkstyle error

* fix checkstyle error

* Rename method addUnreviewedJobEntries to addSheet
  • Loading branch information
yuhongherald authored Mar 27, 2018
1 parent 65c10ef commit 3be6a04
Show file tree
Hide file tree
Showing 28 changed files with 1,184 additions and 21 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jacocoTestReport {
dependencies {
String testFxVersion = '4.0.7-alpha'

// https://mvnrepository.com/artifact/org.apache.poi/poi
compile group: 'org.apache.poi', name: 'poi', version: '3.17'
// https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml
compile group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'

compile group: 'org.fxmisc.easybind', name: 'easybind', version: '1.0.3'
compile group: 'org.controlsfx', name: 'controlsfx', version: '8.40.11'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.7.0'
Expand Down
28 changes: 18 additions & 10 deletions src/main/java/seedu/address/logic/commands/CommandWords.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class CommandWords implements Serializable {
FindCommand.COMMAND_WORD,
HelpCommand.COMMAND_WORD,
HistoryCommand.COMMAND_WORD,
ImportAllCommand.COMMAND_WORD,
ListCommand.COMMAND_WORD,
RedoCommand.COMMAND_WORD,
SelectCommand.COMMAND_WORD,
Expand Down Expand Up @@ -124,16 +125,7 @@ public String getCommandKey(String value) throws CommandWordException {
*/
public void setCommandWord(String currentWord, String newWord) throws CommandWordException {
requireNonNull(currentWord, newWord);
if (currentWord.equals(newWord)) {
throw new CommandWordException(getMessageNoChange());
}
if (isDefaultCommandWord(newWord)
&& !commands.get(newWord).equals(currentWord)) {
throw new CommandWordException(getMessageOverwriteDefault(newWord));
}
if (commands.containsValue(newWord)) {
throw new CommandWordException(getMessageUsed(newWord));
}
checkCommandWordValidity(currentWord, newWord);
if (isDefaultCommandWord(currentWord)) {
commands.remove(currentWord);
commands.put(currentWord, newWord);
Expand All @@ -152,6 +144,22 @@ public void setCommandWord(String currentWord, String newWord) throws CommandWor
throw new CommandWordException(getMessageUnused(currentWord));
}

/**
* throws a (@code CommandWordException) if (@code currentWord) or (@code newWord) is not valid
*/
private void checkCommandWordValidity(String currentWord, String newWord) throws CommandWordException {
if (currentWord.equals(newWord)) {
throw new CommandWordException(getMessageNoChange());
}
if (isDefaultCommandWord(newWord)
&& !commands.get(newWord).equals(currentWord)) {
throw new CommandWordException(getMessageOverwriteDefault(newWord));
}
if (commands.containsValue(newWord)) {
throw new CommandWordException(getMessageUsed(newWord));
}
}

/**
* Copies key and value of (@code command) from (@code commands)
* to (@code verifiedCommands). Creates a new entry with default
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/seedu/address/logic/commands/ImportAllCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import java.io.IOException;

import java.util.ArrayList;
import java.util.List;

import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.job.Job;
import seedu.address.model.session.ImportSession;
import seedu.address.model.session.exceptions.DataIndexOutOfBoundsException;
import seedu.address.model.session.exceptions.FileAccessException;
import seedu.address.model.session.exceptions.FileFormatException;

//@@author yuhongherald
/**
* Attempts to import all (@code JobEntry) into Servicing Manager
*/
public class ImportAllCommand extends UndoableCommand {

public static final String COMMAND_WORD = "importAll";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Imports job entries from from an excel file. "
+ "Parameters: FILEPATH\n"
+ "Example: " + COMMAND_WORD + "yourfile.xls";

public static final String MESSAGE_SUCCESS = "%s has been imported, with %d job entries!";

private final String filePath;

public ImportAllCommand(String filePath) {
requireNonNull(filePath);
this.filePath = filePath;
}

public String getMessageSuccess(int entries) {
return String.format(MESSAGE_SUCCESS, filePath, entries);
}

@Override
public CommandResult executeUndoableCommand() throws CommandException {
ImportSession importSession = ImportSession.getInstance();
try {
importSession.initializeSession(filePath);
} catch (FileAccessException e) {
e.printStackTrace();
} catch (FileFormatException e) {
throw new CommandException("Excel file first row headers are not defined properly. "
+ "Type 'help' to read more.");
}
try {
importSession.reviewAllRemainingJobEntries(true);
List<Job> jobs = new ArrayList<>(importSession.getSessionData().getReviewedJobEntries());
model.addJobs(jobs);
importSession.closeSession();
return new CommandResult(getMessageSuccess(jobs.size()));
} catch (DataIndexOutOfBoundsException e) {
throw new CommandException("Excel file has bad format. Try copying the cell values into a new excel file "
+ "before trying again");
} catch (IOException e) {
throw new CommandException("Unable to export file. Please close the application and try again.");
}
}

@Override
public boolean equals(Object other) {
return other == this // short circuit if same object
|| (other instanceof ImportAllCommand // instanceof handles nulls
&& filePath.equals(((ImportAllCommand) other).filePath));
}

}
5 changes: 2 additions & 3 deletions src/main/java/seedu/address/logic/commands/SetCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ public class SetCommand extends UndoableCommand {
public static final String COMMAND_WORD = "set";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Sets a command word to user preference. "
+ "Parameters: CURRENT_COMMAND_WORD NEW_COMMAND_WORD"
+ "Example: " + "set" + " "
+ "OLD_COMMAND" + "NEW_COMMAND";
+ "Parameters: CURRENT_COMMAND_WORD NEW_COMMAND_WORD\n"
+ "Example: " + COMMAND_WORD + " set st";

public static final String MESSAGE_SUCCESS = "%s has been replaced with %s!";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

//@@author yuhongherald
/**
* Represents an error which occurs during execution of {@link SetCommand}.
* Represents an error which occurs during execution of {@link seedu.address.logic.commands.SetCommand}.
*/
public class CommandWordException extends Exception {
public CommandWordException(String message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.HistoryCommand;
import seedu.address.logic.commands.ImportAllCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.RedoCommand;
import seedu.address.logic.commands.SelectCommand;
Expand Down Expand Up @@ -95,6 +96,9 @@ public Command parseCommand(String userInput) throws ParseException {
case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);

case ImportAllCommand.COMMAND_WORD:
return new ImportAllCommandParser().parse(arguments);

case ListCommand.COMMAND_WORD:
return new ListCommand();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package seedu.address.logic.parser;

import static seedu.address.commons.core.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.ParserUtil.parseFilename;

import seedu.address.commons.exceptions.IllegalValueException;
import seedu.address.logic.commands.ImportAllCommand;
import seedu.address.logic.parser.exceptions.ParseException;

//@@author yuhongherald

/**
* Parses input arguments and creates a new AddCommand object
*/
public class ImportAllCommandParser implements Parser<ImportAllCommand> {

/**
* Parses the given {@code String} of arg
* uments in the context of the ImportAllCommand
* and returns an ImportAllCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public ImportAllCommand parse(String args) throws ParseException {
try {
String filePath = parseFilename(args);
return new ImportAllCommand(filePath);
} catch (IllegalValueException ive) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, ImportAllCommand.MESSAGE_USAGE));
}
}

}
22 changes: 19 additions & 3 deletions src/main/java/seedu/address/logic/parser/ParserUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static java.util.Objects.requireNonNull;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
Expand Down Expand Up @@ -32,14 +33,15 @@ public class ParserUtil {
public static final String MESSAGE_INSUFFICIENT_PARTS = "Number of parts must be more than 1.";
public static final String MESSAGE_INSUFFICIENT_WORDS = "Command word to be changed and new command word must "
+ "be provided, separated by a space.";
public static final String MESSAGE_INVALID_FILENAME = "File name must be the path to an existing file, in the "
+ "same folder as this application";
public static final String WHITESPACE = "\\s+";
public static final String APPLICATION_DIRECTORY = ".\\";

/**
* Parses {@code multipleWordString} into an {@code String[]} containing command words and returns it.
* Leading and trailing whitespaces will be trimmed.
* @param multipleWordString
* @return
* @throws IllegalValueException
* @throws IllegalValueException if words found is not equal to 2
*/
public static String[] parseWords(String multipleWordString) throws IllegalValueException {
String[] commandWords = multipleWordString.trim().split(WHITESPACE);
Expand All @@ -50,6 +52,20 @@ public static String[] parseWords(String multipleWordString) throws IllegalValue

}

/**
* Parses {@code filePath} and checks if (@code file) specified exists.
* Leading and trailing whitespaces will be trimmed.
* @throws IllegalValueException if file does not exist
*/
public static String parseFilename(String filePath) throws IllegalValueException {
File file = new File(filePath.trim());
if (!file.exists()) {
throw new IllegalValueException(MESSAGE_INVALID_FILENAME);
}
return APPLICATION_DIRECTORY + filePath.trim();

}

/**
* Parses {@code oneBasedIndex} into an {@code Index} and returns it. Leading and trailing whitespaces will be
* trimmed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public class SetCommandParser implements Parser<SetCommand> {

/**
* Parses the given {@code String} of arg
* uments in the context of the AddCommand
* and returns an AddCommand object for execution.
* uments in the context of the SetCommand
* and returns a SetCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public SetCommand parse(String args) throws ParseException {
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/seedu/address/model/Model.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package seedu.address.model;

import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import javafx.collections.ObservableList;
Expand Down Expand Up @@ -48,6 +50,12 @@ public interface Model {
/** Adds the given employee */
void addPerson(Employee employee) throws DuplicateEmployeeException;

/** Adds a list of (@code Job) into (@code AddressBook), and automatically imports new employees */
void addJobs(List<Job> job);

/** Adds employees in list into (@code AddressBook) if it is not present */
void addMissingEmployees(Set<Employee> employees);

/** Sort all persons' name in list alphabetically. */
void sortPersonList();

Expand Down
25 changes: 24 additions & 1 deletion src/main/java/seedu/address/model/ModelManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.logging.Logger;

Expand Down Expand Up @@ -64,7 +67,7 @@ public void initJobNumber() {
}
int largest = filteredJobs.get(0).getJobNumber().asInteger();
for (Job job : filteredJobs) {
if ( job.getJobNumber().asInteger() > largest) {
if (job.getJobNumber().asInteger() > largest) {
largest = job.getJobNumber().asInteger();
}
}
Expand Down Expand Up @@ -125,6 +128,26 @@ public synchronized void addPerson(Employee employee) throws DuplicateEmployeeEx
indicateAddressBookChanged();
}

@Override
public void addJobs(List<Job> jobs) {
for (Job job : jobs) {
addMissingEmployees(job.getAssignedEmployees());
addJob(job);
}
}

@Override
public void addMissingEmployees(Set<Employee> employees) {
Iterator<Employee> employeeIterator = employees.iterator();
while (employeeIterator.hasNext()) {
try {
addPerson(employeeIterator.next());
} catch (DuplicateEmployeeException e) {
// discard the result
}
}
}

@Override
public void updatePerson(Employee target, Employee editedEmployee)
throws DuplicateEmployeeException, EmployeeNotFoundException {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/seedu/address/model/job/Job.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
* Represents a Job in the car servicing manager
*/
public class Job {
protected final RemarkList remarks;

private final Person client;
private final VehicleNumber vehicleNumber;
private final JobNumber jobNumber;
private final Date date;
private final Status status;

private final UniqueEmployeeList assignedEmployees;
private final RemarkList remarks;

public Job(Person client, VehicleNumber vehicleNumber, JobNumber jobNumber,
Date date, UniqueEmployeeList assignedEmployees, Status status, RemarkList remarks) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package seedu.address.model.session;

import java.util.ArrayList;

import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import seedu.address.model.session.exceptions.DataIndexOutOfBoundsException;

//@@author yuhongherald
/**
* For fields that resides in one or more columns
*/
public interface ExcelColumnSpannable {
public int getStartIndex();
public int getEndIndex();
public ArrayList<String> readData(Workbook workbook, int sheetNumber, int rowNumber)
throws DataIndexOutOfBoundsException;
public ArrayList<String> readDataFromSheet(Sheet sheet, int rowNumber) throws DataIndexOutOfBoundsException;
}
18 changes: 18 additions & 0 deletions src/main/java/seedu/address/model/session/ExcelRowReference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package seedu.address.model.session;

/**
* For row entries of an excel sheet
*/
public interface ExcelRowReference {

/**
* Returns the excel sheet number of this element.
*/
public int getSheetNumber();

/**
* Returns the excel row number of this element
* @return
*/
public int getRowNumber();
}
Loading

0 comments on commit 3be6a04

Please sign in to comment.