Class: AccountDailyActivityReport

Inherits:
Object
  • Object
show all
Defined in:
app/services/account_daily_activity_report.rb

Overview

Reporting window for the sysadmin email:

  • Production default: previous calendar day in America/Chicago.
  • Optional local/test: set ACCOUNT_ACTIVITY_REPORT_LOOKBACK_HOURS=48 for a rolling window
    ending at “now” in Chicago (e.g. dev DB snapshot testing).

Constant Summary collapse

TZ =

rubocop:disable Metrics/ClassLength

'America/Chicago'
ENV_LOOKBACK_HOURS =
'ACCOUNT_ACTIVITY_REPORT_LOOKBACK_HOURS'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(date: nil, range: nil, rolling_hours: nil) ⇒ AccountDailyActivityReport

Returns a new instance of AccountDailyActivityReport.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'app/services/account_daily_activity_report.rb', line 13

def initialize(date: nil, range: nil, rolling_hours: nil)
  tz = ActiveSupport::TimeZone[TZ]
  if range
    @window_start = range.begin.in_time_zone(tz)
    @window_end = range.end.in_time_zone(tz)
    @date = @window_start.to_date
    @rolling_hours = rolling_hours
  elsif date
    @date = date
    @window_start = tz.local(date.year, date.month, date.day).beginning_of_day
    @window_end = @window_start.end_of_day
    @rolling_hours = nil
  else
    raise ArgumentError, 'Provide date: or range:'
  end
end

Instance Attribute Details

#dateObject (readonly)

Returns the value of attribute date.



11
12
13
# File 'app/services/account_daily_activity_report.rb', line 11

def date
  @date
end

#rolling_hoursObject (readonly)

Returns the value of attribute rolling_hours.



11
12
13
# File 'app/services/account_daily_activity_report.rb', line 11

def rolling_hours
  @rolling_hours
end

#window_endObject (readonly)

Returns the value of attribute window_end.



11
12
13
# File 'app/services/account_daily_activity_report.rb', line 11

def window_end
  @window_end
end

#window_startObject (readonly)

Returns the value of attribute window_start.



11
12
13
# File 'app/services/account_daily_activity_report.rb', line 11

def window_start
  @window_start
end

Class Method Details

.calendar_yesterdayObject



45
46
47
48
# File 'app/services/account_daily_activity_report.rb', line 45

def self.calendar_yesterday
  tz = ActiveSupport::TimeZone[TZ]
  new(date: tz.now.to_date - 1)
end

.for_scheduled_runObject



30
31
32
33
34
35
36
37
# File 'app/services/account_daily_activity_report.rb', line 30

def self.for_scheduled_run
  hours = lookback_hours_from_env
  if hours&.positive?
    rolling_hours(hours)
  else
    calendar_yesterday
  end
end

.lookback_hours_from_envObject



50
51
52
53
54
55
56
57
# File 'app/services/account_daily_activity_report.rb', line 50

def self.lookback_hours_from_env
  v = ENV[ENV_LOOKBACK_HOURS].to_s.strip
  return nil if v.blank?

  Integer(v)
rescue ArgumentError, TypeError
  nil
end

.rolling_hours(hours) ⇒ Object



39
40
41
42
43
# File 'app/services/account_daily_activity_report.rb', line 39

def self.rolling_hours(hours)
  tz = ActiveSupport::TimeZone[TZ]
  now = tz.now
  new(range: (now - hours.hours)..now, rolling_hours: hours)
end

Instance Method Details

#accounts_createdObject



59
60
61
# File 'app/services/account_daily_activity_report.rb', line 59

def accounts_created
  Account.includes(:party).where(created_at: window_start..window_end).order(:id)
end

#accounts_created_by_groupObject

Split: WWW = customer site (Customer party), CRM = employee app (Employee party).



71
72
73
# File 'app/services/account_daily_activity_report.rb', line 71

def accounts_created_by_group
  split_by_www_crm(accounts_created)
end

#login_eventsObject

Per-event sign-in attempts (success + failure) recorded by AuthTrail
in login_activities. Replaces the previous Devise current_sign_in_at
snapshot, which collapsed multi-login days into a single row per account.



66
67
68
# File 'app/services/account_daily_activity_report.rb', line 66

def 
  LoginActivity.where(created_at: window_start..window_end).order(:created_at)
end

#login_events_by_groupObject

Bucket every LoginActivity row in the window by audience and outcome:

{
www: { success: [...], failure: [...] },
crm: { success: [...], failure: [...] },
other: { success: [...], failure: [...] }, # Account exists but party is neither Customer nor Employee
unmatched: { success: [...], failure: [...] }, # No Account row matched (typical for failed attempts)
}

Each event also carries a memoised :account (or nil) and :party
(or nil) on the row's instance_variable_get(:@report_*) shims so the
mailer view can render them without re-querying.



87
88
89
90
91
# File 'app/services/account_daily_activity_report.rb', line 87

def 
  events = .to_a
  grouped = bucket_events(events, preload_accounts(events))
  ensure_all_buckets(grouped)
end