Conversation
Current Code Coverage Percent of this PR:94.24 %Files having coverage below 100%
|
|
@shalapatil Please ensure that you use elastic search here on filters as per Vipul's recommendation |
|
Not reviewing right now, waiting for elastic search implementation |
| def add_filters_if_any(where_clause) | ||
| where_clause = add_date_range_filter(where_clause) | ||
| where_clause = add_clients_filter(where_clause) | ||
| where_clause = add_bill_status_filter(where_clause) | ||
| where_clause = add_team_members_filter(where_clause) | ||
| end | ||
|
|
||
| def add_date_range_filter(where_clause) | ||
| if params[:date_range].present? | ||
| where_clause.merge(work_date: from_date..to_date) | ||
| else | ||
| where_clause | ||
| end | ||
| end | ||
|
|
||
| def add_clients_filter(where_clause) | ||
| if params[:client_id].present? | ||
| clients = Client.includes(:projects).where(id: params[:client_id].split(",")) | ||
| project_ids = clients.map { |client| client.project_ids }.flatten | ||
| where_clause.merge(project_id: project_ids) | ||
| else | ||
| where_clause | ||
| end | ||
| end | ||
|
|
||
| def add_bill_status_filter(where_clause) | ||
| if params[:status].present? | ||
| where_clause.merge(bill_status: params[:status].split(",")) | ||
| else | ||
| where_clause | ||
| end | ||
| end | ||
|
|
||
| def add_team_members_filter(where_clause) | ||
| if params[:team_member].present? | ||
| where_clause.merge(user_id: params[:team_member].split(",")) | ||
| else | ||
| where_clause | ||
| end | ||
| end | ||
|
|
||
| def from_date | ||
| case params[:date_range] | ||
| when "this_month" | ||
| 0.month.ago.beginning_of_month | ||
| when "last_month" | ||
| 1.month.ago.beginning_of_month | ||
| when "this_week" | ||
| 0.weeks.ago.beginning_of_week | ||
| when "last_week" | ||
| 1.weeks.ago.beginning_of_week | ||
| end | ||
| end | ||
|
|
||
| def to_date | ||
| case params[:date_range] | ||
| when "this_month" | ||
| 0.month.ago.end_of_month | ||
| when "last_month" | ||
| 1.month.ago.end_of_month | ||
| when "this_week" | ||
| 0.weeks.ago.end_of_week | ||
| when "last_week" | ||
| 1.weeks.ago.end_of_week | ||
| end | ||
| end |
There was a problem hiding this comment.
as per slack discussion, we are agoing ahead with elasticsearch
| where_clause = add_date_range_filter(where_clause) | ||
| where_clause = add_clients_filter(where_clause) | ||
| where_clause = add_bill_status_filter(where_clause) | ||
| where_clause = add_team_members_filter(where_clause) |
There was a problem hiding this comment.
Just wondering if it's a good idea to reuse the same argument variable.
There was a problem hiding this comment.
Not sure if we follow this practice or not. But if the variable value is going to be updated and the old value is not going to be used anywhere then there is no harm in using the same variable.
| end | ||
|
|
||
| context "when reports page's request is made with combination of filters" do | ||
| before do |
There was a problem hiding this comment.
Use let vs @ variables https://www.betterspecs.org/#let
There was a problem hiding this comment.
@aditya-vector How can we reduce the use of these instance variables? let! seems to have a limit of 10 variables cc @shalapatil
There was a problem hiding this comment.
we can use create_list to create lists of indentical records, and store it in one let variable. we can then use that variable for assertions. @rohitjoshixyz @shalapatil
Check https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md for definition on create_list.
| def add_date_range_filter(where_clause) | ||
| if params[:date_range].present? | ||
| where_clause.merge(work_date: from_date..to_date) | ||
| else | ||
| where_clause | ||
| end | ||
| end | ||
|
|
||
| def add_clients_filter(where_clause) | ||
| if params[:client_id].present? |
There was a problem hiding this comment.
Move this to a service class, controller is getting very big
There was a problem hiding this comment.
Agreed, all filtering for the controller, perhaps
| end | ||
|
|
||
| def add_bill_status_filter(where_clause) | ||
| if params[:status].present? |
There was a problem hiding this comment.
How about using diminutive return?
Eg:
return where_clause if params[:status].blank?
where_clause.merge(bill_status: params[:status].split(","))
Also, I'm inclined towards adding the presence check beforehand and not as a part of the method itself.
| end | ||
|
|
||
| def add_team_members_filter(where_clause) | ||
| if params[:team_member].present? |
app/services/report/filters.rb
Outdated
| def add_date_range_filter_if_any(where_clause) | ||
| return where_clause if date_range_filter.blank? | ||
|
|
||
| where_clause.merge(work_date: from_date..to_date) |
There was a problem hiding this comment.
IMO, this can be fetched as a range directly. Why add separate methods just to fetch a range? We are anyways not using this anywhere else.
| # frozen_string_literal: true | ||
|
|
||
| module Report | ||
| class Filters < ApplicationService |
a872c32 to
6f035ef
Compare
app/services/report/filters.rb
Outdated
| def process | ||
| where_clause = add_date_range_filter_if_any({}) | ||
| where_clause = add_clients_filter_if_any(where_clause) | ||
| where_clause = add_bill_status_filter_if_any(where_clause) | ||
| where_clause = add_team_members_filter_if_any(where_clause) |
There was a problem hiding this comment.
Small feedback - inclusion totally depends on reviewees' discretion,
How about we use the parameter information at a single source instead, may prove easy to extend
class Filters < ApplicationService
FILTER_PARAM_LIST = %i[date_range status team_member client_id]
attr_reader :filter_params
def initialize(filter_params:)
@filter_params = filter_params
end
def process
FILTER_PARAM_LIST.each_with_object({}) do |filter_param_key, where_condition|
where_condition.merge(public_send("#{date_range}_filter")) if filter_params[filter_param_key].present?
end
end
# Optional: Remove `_filter` and use filter_param_key as method directly
def date_range_filter
{ work_date: from_date..to_date }
end
def status_filter
{ bill_status: filter_params[:status].split(",") }
end
# And other filters as methods and other required methods
end
Note: This is untested, so may need small changes
There was a problem hiding this comment.
This is cool! Updated my code with few changes!
6f035ef to
61cbb3b
Compare
af4c1bf to
f43a275
Compare
rohitjoshixyz
left a comment
There was a problem hiding this comment.
Great job with the refactoring @shalapatil 💯
Few minor suggestions, rest LGTM. @akhilgkrishnan Can you review once for the elastic search GitHub action?
| params[:team_member].present? | ||
| end | ||
|
|
||
| def entries |
There was a problem hiding this comment.
entries is too generic, please rename
| def entries | |
| def filtered_reports |
| context "when reports page's request is made without any filters" do | ||
| before do | ||
| @timesheet_entry1 = create(:timesheet_entry, project:) | ||
| TimesheetEntry.search_index.refresh |
There was a problem hiding this comment.
We can consider adding a class method to reindex this model. Non-blocking To Do, is not a priority at all
|
|
||
| context "when reports page's request is made with bill status filter" do | ||
| before do | ||
| @timesheet_entry1 = create(:timesheet_entry, project:, bill_status: "non_billable") |
There was a problem hiding this comment.
Consider adding a trait to the timesheet entry factory for billable and non billable since this getting repeated
| end | ||
|
|
||
| it "returns the time entry reports with given single status value" do | ||
| get "/internal_api/v1/reports?status[]=unbilled" |
There was a problem hiding this comment.
User URL helpers and query params in a hash, this is difficult to read
| end | ||
|
|
||
| it "returns the time entry reports with given single client value" do | ||
| get "/internal_api/v1/reports?client[]=#{client.id}" |
There was a problem hiding this comment.
Same for all specs, try and use URL helper for get calls
| end | ||
|
|
||
| context "when reports page's request is made with combination of filters" do | ||
| before do |
There was a problem hiding this comment.
@aditya-vector How can we reduce the use of these instance variables? let! seems to have a limit of 10 variables cc @shalapatil
| @timesheet_entry1 = create(:timesheet_entry, project:, work_date: last_month_start_date) | ||
| @timesheet_entry2 = create(:timesheet_entry, project:, work_date: this_week_start_date) | ||
| @timesheet_entry3 = create(:timesheet_entry, project:, work_date: this_week_start_date) | ||
| TimesheetEntry.search_index.refresh |
There was a problem hiding this comment.
suggestion: use let instead of instance variables for specs.
There was a problem hiding this comment.
using let is exceeding the limits, which is set to 10 by us. So, can't use it.
There was a problem hiding this comment.
For common records we can use create_list() instead of create() to create array of records and can access the record using timesheet_entry[0], timesheet_entry[1], etc.
There was a problem hiding this comment.
Require different values for each timsheet entry, so can't create the same ones
keshavbiswa
left a comment
There was a problem hiding this comment.
@shalapatil Great work on the refactoring, loved the changes you made. Looks awesome to me !!! 💯
shalapatil
left a comment
There was a problem hiding this comment.
Thank you @keshavbiswa! :)
* Close the edit members modal on saving the changes * Add filtering options for reports list * Add serchkick gem & use it in timesheetentries * Add filters for reports page * Remove model changes as not required anymore * Extract comma separated multiple params * Add request specs for reports index page * Extract comma separated multiple params * Add utility functions to service class * Fix params parsing * Add ES configuration in github validation * Add optimisation * Update Readme for elasticsearch installation * Use ankane elasticsearch github actions * Add suggested changes
Notion card
https://www.notion.so/saeloun/6afc9500b2cc42af86be55f37894fb09?v=185bd45b9dc24dfcad9c57c07d32a7c0&p=592b4791f2b14979890319b90a1198bf
Summary
Updated API which returns the list of reports to filter the results based on date range, clients, team members and status, if passed any.
Params looks like -
?date_range=last_month&client[]=10&client[]=1&status[]=non_billable&team_member[]=1I am working on specs. Will add them in next commit in the same PR.
Preview
Type of change
Please delete options that are not relevant.
not work as expected)
How Has This Been Tested?
Checklist: