Skip to content

Commit

Permalink
Update attendance view service for performance improvement (#3465)
Browse files Browse the repository at this point in the history
* New attendance view query functionallity

* Attendance view new query finished

* fix frontend test

* move attendance info query logic from controller to a new service
  • Loading branch information
MartinM1312 committed Apr 23, 2024
1 parent 1e5b4a0 commit f43e139
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 8 deletions.
2 changes: 1 addition & 1 deletion app/blueprints/child_blueprint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ChildBlueprint < Blueprinter::Base
end

field :active_business do |child, _options|
business = child.child_businesses.find_by(currently_active: true).business
business = child.child_businesses.find_by(currently_active: true)&.business
{ id: business.id, name: business.name }
end

Expand Down
25 changes: 25 additions & 0 deletions app/controllers/api/v1/attendance_view_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

# rubocop: disable Metrics/AbcSize
# rubocop: disable Metrics/LineLength
module Api
module V1
# Service for dashboard table info
class AttendanceViewController < ApiController
def index
filter_date = params[:filter_date].to_date
current_date = Date.current
start_date = filter_date == current_date ? (current_date.at_beginning_of_week - 1.day).to_s : filter_date.to_s
end_date = filter_date == current_date ? current_date.at_end_of_week.to_s : (filter_date + 1.day).at_end_of_week.to_s

business_ids = params[:business_ids]

attendance_info = AttendanceInfoService.new(start_date, end_date, business_ids)
response = attendance_info.call
render json: response
end
end
end
end
# rubocop: enable Metrics/LineLength\
# rubocop: enable Metrics/AbcSize
103 changes: 103 additions & 0 deletions app/services/attendance_info_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true

# Service to retrieve attendance info for attendance view page

# rubocop: disable Metrics/AbcSize
# rubocop: disable Metrics/LineLength
# rubocop: disable Style/OpenStructUse
# rubocop: disable Lint/SymbolConversion
class AttendanceInfoService
def initialize(start_date, end_date, business_ids)
@start_date = start_date
@end_date = end_date
@business_ids = business_ids
end

def call
build_attendance_info
end

def build_attendance_info
business_condition = ''
business_condition = ' AND b.id IN (?) ' if @business_ids.present?

query_conditions = [attendances_query(business_condition), @end_date, @start_date, @start_date, @end_date]

query_conditions << @business_ids if @business_ids.present?

query_response = ActiveRecord::Base.connection.execute(ActiveRecord::Base.sanitize_sql_for_conditions(query_conditions))

build_data(query_response)
end

def build_data(query_response)
result = query_response.map { |data| data }
result.each do |item|
item['attendances'] = JSON.parse(item['attendances'])
service_day_info = OpenStruct.new({ total_time_in_care: item['total_time_in_care'].to_i.seconds, state: item['state'], 'absence?': item['absence_type'].present? })
tags_calculator = Nebraska::TagsCalculator.new(service_day: service_day_info)
tags = tags_calculator.call
item['tags'] = tags
item['child'] = JSON.parse(item['child'])
end
result
end

def attendances_query(business_condition = '')
<<-SQL.squish
SELECT
sd.id,
sd.absence_type,
sd.date,
sd.full_time,
sd.part_time,
b.state,
EXTRACT(EPOCH FROM sd.total_time_in_care) AS total_time_in_care,
COALESCE(json_agg(
json_build_object(
'id', a.id,
'check_in', a.check_in,
'check_out', a.check_out,
'child_approval_id', a.child_approval_id,
'time_in_care', a.time_in_care
) ORDER BY a.check_in
) FILTER (WHERE a.id IS NOT NULL), '[]') AS attendances,
json_build_object(
'id', c.id,
'active', COALESCE(c.active, false),
'active_business', json_build_object(
'id', b.id,
'name', b.name
),
'business_name', b.name,
'first_name', c.first_name,
'inactive_reason', c.inactive_reason,
'last_active_date', c.last_active_date,
'last_inactive_date', c.last_inactive_date,
'last_name', c.last_name,
'wonderschool_id', c.wonderschool_id
) AS child
FROM
service_days sd
LEFT JOIN attendances a ON sd.id = a.service_day_id
LEFT JOIN child_approvals ca ON sd.child_id = ca.child_id
JOIN approvals app ON ca.approval_id = app.id
AND app.effective_on <= ?
AND (app.expires_on IS NULL OR app.expires_on >= ?)
LEFT JOIN children c ON sd.child_id = c.id
LEFT JOIN child_businesses cb ON c.id = cb.child_id
LEFT JOIN businesses b ON cb.business_id = b.id AND b.active
WHERE
sd.date BETWEEN ? AND ?
#{business_condition}
GROUP BY
sd.id, c.id, b.id, b.state
ORDER BY
sd.date, c.last_name, c.first_name;
SQL
end
end
# rubocop: enable Metrics/AbcSize
# rubocop: enable Metrics/LineLength
# rubocop: enable Style/OpenStructUse
# rubocop: enable Lint/SymbolConversion
8 changes: 4 additions & 4 deletions client/src/AttendanceView/AttendanceView.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export function AttendanceView() {
render: (_, record) => {
const matchingServiceDay = record.serviceDays.find(serviceDay => {
return new RegExp(columnDate.format('YYYY-MM-DD')).test(
serviceDay.date
serviceDay.date.split('T')[0]
)
})

Expand Down Expand Up @@ -398,9 +398,9 @@ export function AttendanceView() {
dispatch(setLoading(true))
const response = await makeRequest({
type: 'get',
url: `/api/v1/service_days?filter_date=${dateSelected.format(
url: `/api/v1/attendance_view?filter_date=${dateSelected.format(
'YYYY-MM-DD'
)}&business=${businessIds.length > 0 ? businessIds.join(',') : ''}`,
)}&business_ids=${businessIds.length > 0 ? businessIds.join(',') : ''}`,
headers: {
Authorization: token
},
Expand All @@ -410,7 +410,7 @@ export function AttendanceView() {
if (response.ok) {
const parsedResponse = await parseResult(response)
const addServiceDay = (previousValue, currentValue) => {
const isInactive = () => !currentValue?.child.active
const isInactive = () => !currentValue?.child?.active

if (isInactive()) {
return previousValue
Expand Down
4 changes: 2 additions & 2 deletions client/src/AttendanceView/_tests_/AttendanceView.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ describe('<AttendanceView />', () => {
await waitFor(() => {
expect(window.fetch).toHaveBeenCalledTimes(1)
expect(window.fetch.mock.calls[0][0]).toBe(
'/api/v1/service_days?filter_date=' +
'/api/v1/attendance_view?filter_date=' +
dayjs().format('YYYY-MM-DD') +
'&business='
'&business_ids='
)
})
})
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
resources :attendance_batches, only: :create
resources :notifications
resources :dashboard_case, only: [:index]
resources :attendance_view, only: [:index]
get 'case_list_for_dashboard', to: 'users#case_list_for_dashboard'
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/services/illinois_attendance_risk_calculator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
business = create(:business)
child = create(:child_in_illinois)
create(:child_business, child:, business:)
date = Date.new(2023, 7, 20)
date = Date.new(2023, 8, 20)
eligible_days_in_week = 5
elapsed_weeks = 3
elapsed_eligible_days = eligible_days_in_week * elapsed_weeks
Expand Down

0 comments on commit f43e139

Please sign in to comment.