Overview
Seller Manager Lite is a desktop application used for managing a business operational and logistical needs. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has >10 kLoC. It was written over the span of 2 months and morphed from the original Address-book 3 application.
Summary of contributions
-
Major enhancement: added ability to generate statistics
-
What it does: allows the user to query total
Revenue
,Cost
andprofit
on all past orders. Contains 2 types of input mode:-
No date input: This mode is to give users a quick way of obtaining the numbers
-
Date input: This mode is to produce a monthly chart view of the statistics
-
-
Justification: Being business owners, this feature should be very essential for the owners to be able to track their statistics and numbers while running their day to day operations. This allows them to more easily plan and monitor their business while using these numbers. By having this feature, the users of this app can review their performance of their products over the past few months, which is essential to business owners.
-
Highlights: This feature cut across several layers in the entire project e.g logic, UI, model and hence designing it in such a way that it was able to work with the existing Model View Controller architecture was a very important albeit tedious step. It required an in-depth analysis of design alternatives. This design choice is elaborated below in the developer guide writeup.
-
The implementation was also challenging as I made very sure no to violate any of the SOLID principles. At the same time, we were also still deciding how to implement the rest of the architecture for the other features. There was a very strong and conscientious effort to make the code easily extendable as there is a high possibility that this feature will have to scale exponentially.
-
A total of 4 attempts of refactoring was needed for me to reach the current version of the main feature.
-
-
Credits: The apache commons math libraries was used in the actual calculation. The main difficulty of this feature come from extracting the correct and appropiate data needed and in the appropiate manner.
-
-
Other Major enhancement:
-
My other contributions to the codebase is as follows:
-
Complete overhaul of User Interface. This includes generating the FXML files, creating the controller files, importing and GUI tests.
-
UI commands. This includes the command that is directly related to switching of UI e.g
switch-o
which allows the user to switch their their focused tab panel with a command.
-
-
-
Other contributions:
-
Project management:
-
Enhancements to existing features:
-
Updated the color scheme and develop first UI prototype along with CSS Changes (Pull Requests: #66, #189, #136, #129)
-
Add Tabbed panels for UI. This includes writing the FXML files and controllers for the UI elements (Pull Requests: #72, #192, #145, #169 )
-
Add command to interact with Tabbed panels for UI (Pull Requests: #110 , #76)
-
Ported GUI tests into code base and added to it (Pull Requests: #103, #139)
-
Wrote tests for Statistics Module, Storage Module (Json) (Pull Requests: #174, #171, #160, #83)
-
-
Documentation:
-
Community:
-
Summary:
-
Contributed total almost 7k LOC: 3k+ functional & 3k+ test code: code or (https://nus-cs2103-ay1920s1.github.io/tp-dashboard/#search=eugeneteu&sort=groupTitle&sortWithin=title&since=2019-09-06&timeframe=commit&mergegroup=false&groupSelect=groupByRepos&breakdown=false&tabOpen=false)
-
Over 41 Pull requests on Github
-
Over 37 issues on Github
-
Complete Contribution here or (https://nus-cs2103-ay1920s1.github.io/tp-dashboard/#search=eugeneteu&sort=groupTitle&sortWithin=title&since=2019-09-06&timeframe=commit&mergegroup=false&groupSelect=groupByRepos&breakdown=false&tabOpen=false)
-
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Generate stats: generate-s
v1.4
only allows statistics on orders marked as Completed
and has a Schedule
.
This function calculates the three type of statistics as shown below.
All statistics that are calculated are only on orders in the archived panel
that has been completed
and with a valid schedule
.
Lacking any of this will cause its non-inclusion into the statistics calculation.
The value calculated is the sum over the total time period within a month, meaning that it will take the date period,
calculate the statistics for orders within that time period, split it by month and display it.
e.g Total revenue
between 2019.11.12 and 2019.11.29 will calculate the order between these 2 dates, sum up the revenue
(as it falls within a single month) and
display this value.
-
Accepts two types of input:
-
Without date input - display total value for that particular statistics.
-
with date input - displays chart (Monthly value) and total value for that particular statistics.
-
Generates the statistics with no date input.
Used for calculating total profit
, total revenue
and total cost
.
Format: generate-s s/stat
Type for stat
includes: profit
, revenue
, cost
The argument must match these three words perfectly.
Shown below:
Generates the statistics with date input in chart format (in pop-up modal dialogue).
Format: generate-s s/stat d1/YYYY.MM.DD d2/YYYY.MM.DD
Example: generate-s s/revenue d1/2019.10.16 d2/2019.11.21
Format for the date is in YYYY.MM.DD e.g 2019.05.12
Shown below:
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
-
My Contributions are:
-
Created the architecture, UI and Logic diagram (refer to DG portion with these diagrams)
-
Wrote the User Interface part of the DG (omitted limitations to user part due to length constraint of PPP)
-
Wrote the Statistic Feature in the DG
-
API: Ui.java
The UI consists of a MainWindow
that is made up of parts
e.g.CommandBox
, ResultDisplay
, TabPanel
, StatusBarFooter
etc.
TabPanel
consists of CustomerListPanel
, OrderListPanel
, PhoneListPanel
, CalendarListPanel
and ArchivedOrderListPanel
All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFX UI framework. The layout of these UI parts is defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
.
The UI
component,
-
Executes user commands using the
Logic
component. -
Listens for changes to
Model
data so that the UI can be updated with the modified data. -
Different changes in each tab or panel are controlled via the enum
UiChange
.
Statistics Calculation and Chart generation feature
Implementation
This statistic calculation and chart generation feature extends Seller Manager Lite
which allows sellers to quickly
generate total statistics from their DataBooks
, through the use of a statistic
module that handles this calculation. There are three type of statistic to be calculated and only on completed orders
:
-
Profit
Cost
Revenue
It implements the following mode of operations:
-
default mode with no date input: generates on all completed order total
profit
,cost
orrevenue
-
The command enter by the user will be e.g for profit type
generate-s s/PROFIT
-
-
mode with date input from the user: The statistic command takes in 2
dates
,starting date
andending date
and generates theprofit
,cost
orrevenue
eachmonth
between this 2 dates.-
command entered by the user will be e.g for profit type`generate-s s/PROFIT s1/YYYY.MM.DD s2/YYYY.MM.DD`
-
Here is the sequence of steps taken by SML when it receives a StatCommand
:
Statistic Module
The statistic module exposes the calculation operations in the Statistics
interface.
analogous to the output mode, there are 2 types of methods in this module, one that returns a
String
and the other a XYChart.Series<String, Number>
.
-
Methods that return a
String
:-
calculateTotalProfitOnCompleted(…)
-
calculateTotalRevenueOnCompleted(…)
-
calculateTotalCostOnCompleted(…)
-
-
Methods that return a
XYChart.Series<String, Number>
:-
calculateTotalProfitOnCompletedGraph(…)
-
calculateTotalRevenueOnCompletedGraph(…)
-
calculateTotalCostOnCompletedGraph(…)
-
All methods were written using java8 Stream() feature. This is such that there are no loops in the code to make it more readable and maintainable.
org.apache.commons.math3.stat.StatUtils
library is used to calculate the raw data inside a double[]
(primitive double array).
While the current v1.4
only use the sum
to calculate the exact profit
, revenue
and cost
, v2.0
implementation
will make use of the linear regression
/ average
methods inside the library to generate more advanced statistics.
Design Considerations / Alternative designs considered
Given that the number of orders in a seller database might be scaled to be very large in the future the main focus of this feature was to calculate statistics only when needed.
-
Alternative design :
-
To implement statistics, maintain a few running statistic counters upon loading of the main app, update these counters/values when the calculation is needed and then display it. This implementation would have been easy to implement within the existing AB3 code since it meant extending the
Model
class with a statistic model as compared to having theUI
class to read from this value.-
Pros: Easy to implement on top of AB3.
-
cons: Seller will be unable to obtain an instance of past statistics at each point without storing the history of the statistics somewhere since any change in the database/models will cause the values to change.
-
-
-
Alternative Design (current design) :
-
Statistics
module will exist outside of the current packages and be standalone.Logic
will handle communication with this module fromUI
. Respective Statistics will then be obtained fromLogic
to be displayed by theStatsWindow
.-
Pros: Ensure that the respective tasks are properly abstracted, adhering to the Single Responsibility Principle.
-
Pros: Being standalone means the way of calculating the statistics can be changed without affecting the rest of the codebase.
-
Cons:
Logic
will have to handle more calls and increases its responsibilities.
-
-
Design Decision 1:
Given that consideration, we decided that it will be the UI
to trigger this call to Logic
for calculation
and then display the result of that call. Thus when Statistics need to be shown, the UI
module will query the
Logic
for the respective data One of the motivations for this approach was to,
as much as possible, maintain the architecture that is already in place in AB3.
Furthermore, given that this feature requires date input from the user, we will need to find a way to get UI
to send
the data to make that query to logic. For the old AB3 implementation, CommandResult
only contains feedback to the user
with the actual changes on data done with a call to the model during execute(model)
.
Design Decision 2:
We decided to extend this command pattern by creating a statsPayload
object. This object will hold the user
queries for the statistic calculation (if there is any) and be bundled along with the CommandResult
class to the
UI
to use in its query to logic. When the Ui executes the command to logic, the CommandResult
is returned with
this object, which the UI
will then use to communicate to Logic
. The resulting change
is that the commandResult
type will have slightly different behaviour.
All commands
that
are not statsCommand
will call the default constructor of the commandResult
class, where there is an
Optional.empty()
in place of the StatsPayload
.
All statsCommand
type will have to call the constructor of commandResult
class and pass the StatsPayload
object in.
The key motivation behind this idea of a payload was to be able to encapsulate details about the calculation inside a
single object, passed it to the appropriate place to be "unwrapped" when needed. This unwrapping is done by the
mainWindow
class in the application and subsequently, the data is passed to the statistic
module.
A high-level view of the packages working together:
Current Implementation
Step-by-step breakdown
Below is a more in-depth explanation at each step.
Note that this breakdown is for the mode with date input.
For the default mode with no date, the steps are almost the same, except that
DefaultStatisticsWindow
is called in place of StatisticsWindow
.
Step 1: User inputs a stats command e.g generate-s s/REVENUE d1/2018.12.13 d2/2019.11.13
.
The commandBox executes it and the MainWindow
runs its executeCommand(commandText)
method.
Referring to the sequence diagram below, this results in logic.execute(commandText)
being called and
the statsCommandParser
parses the input from the user, returning a
Command
object.
Seen here is the sequence diagram of the first step
Step 2: the logic then calls command.execute(command)
.
When this happens, the StatsCommand
executes, which triggers a call to create a new StatsPayload
. Then this is used to
create a new CommandResult
object and returns that to Logic
, completing the execution of the user input command.
Seen here is the sequence diagram of the second step.
Shown below is a quick summary of step 1-2 (Full complete diagram):
Step 3: After the logic component completes its execution and return a CommandResult
, the UI
will call
performUiChanges
that handles the specific UI
change. This then results in the statsPayload
class being
passed to Logic
class and subsequently the statistics
module,
where the appropriate calculation will take place.
Step 4: Statistic Manager
calculates the date.
Depending on the input, the Statistic Manager
will calculate the value and return that, either in the form of
a String
or a XYChart.Series<String, Number>
.
Step 5: with this output from logic, Statistic Window
will then handle the displaying of the statistic, be it in chart
form or string form. With this, the feature has finished executing! Attached below is the summary for step 3-5:
Limitations/Note to developers:
Developers working on adding features to this module should take note of these limitations that we have put in place for v1.4
of SML:
-
Date range starts from 1970 onwards
-
Date of year input starts from 1970 onwards. This is enough to fit our use case. Anything lower will be rejected.
-
-
Extension of additional Calculation methods
-
To easily extend the behaviour with additional methods to calculate, reference the current implementation in
StatisticsManager
; There are utility methods to help you with extracting the relevant information from your data.
-
-
UI Changes
-
Any additional Ui Changes should be handled by the controllers for the UI classes
StatisticWindow
andDefaultStatisticWindow
class.
-