Commit 84b88b5a authored by Hugo's avatar Hugo
Browse files

graph_ui: filter on type of opening hours; show daily stats in addition to hourly

parent c2e67da3
GEM
remote: http://rubygems.org/
specs:
activemodel (5.2.0)
activesupport (= 5.2.0)
activerecord (5.2.0)
activemodel (= 5.2.0)
activesupport (= 5.2.0)
activemodel (5.2.1)
activesupport (= 5.2.1)
activerecord (5.2.1)
activemodel (= 5.2.1)
activesupport (= 5.2.1)
arel (>= 9.0)
activesupport (5.2.0)
activesupport (5.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
backports (3.11.3)
backports (3.11.4)
coderay (1.1.2)
concurrent-ruby (1.0.5)
daemons (1.2.6)
eventmachine (1.2.7)
i18n (1.0.1)
i18n (1.1.1)
concurrent-ruby (~> 1.0)
method_source (0.9.0)
minitest (5.11.3)
multi_json (1.13.1)
mustermann (1.0.2)
mustermann (1.0.3)
mysql2 (0.5.2)
net-http-digest_auth (1.4.1)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rack (2.0.5)
rack-protection (2.0.3)
rack-protection (2.0.4)
rack
rake (12.3.1)
sinatra (2.0.3)
sinatra (2.0.4)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.3)
rack-protection (= 2.0.4)
tilt (~> 2.0)
sinatra-contrib (2.0.3)
sinatra-contrib (2.0.4)
activesupport (>= 4.0.0)
backports (>= 2.8.2)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.0.3)
sinatra (= 2.0.3)
rack-protection (= 2.0.4)
sinatra (= 2.0.4)
tilt (>= 1.3, < 3)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
......
......@@ -23,6 +23,7 @@ class GraphBuilder
set_period(params[:period_start], params[:period_end], params[:period_label])
set_included_hours(params[:start_hour], params[:end_hour])
set_included_days(params[:included_days])
set_period_type(params[:period_type])
set_stacking if params[:stacking].present?
set_split_by_days if params[:split_days].present?
......@@ -30,6 +31,7 @@ class GraphBuilder
set_aggregate_type(params[:aggregate_type])
set_graph_type(params[:type])
set_oh_type(params[:oh_type])
self
end
......@@ -67,6 +69,18 @@ class GraphBuilder
self
end
def set_oh_type(type)
@graph.oh_type = type.downcase
# error unless type == 'all' or type == "extended" or type == "regular"
self
end
def set_period_type(type)
@graph.period_type = type.downcase
# error unless type == 'all' or type == "extended" or type == "regular"
self
end
def set_period(date_start, date_end, period_label = nil)
@graph.period_start = Date.strptime(date_start, '%d-%m-%Y')
......@@ -111,9 +125,9 @@ end
class BG
attr_accessor :branch, :period_start, :period_end, :hour_start, :hour_end, :included_days,
:split_by_days, :split_by_weeks, :split_by_months, :aggregate_type, :graph_type, :stacking,
:total_no_of_visitors, :period_label
attr_accessor :branch, :period_start, :period_end, :period_type, :hour_start, :hour_end, :included_days,
:split_by_days, :split_by_weeks, :split_by_months, :aggregate_type,
:graph_type, :oh_type, :stacking, :total_no_of_visitors, :period_label
def initialize
@split_by_days, @split_by_weeks, @split_by_months = false
......@@ -141,18 +155,30 @@ class HourlyGraph < BG
end
def get_series
@counts = @branch.get_aggregated_counts_per_hour(@period_start, @period_end, @included_days)
if @period_type == 'hourly'
@counts = @branch.get_aggregated_counts_per_hour(@period_start, @period_end, @included_days, @oh_type)
@xcategories = (@hour_start..@hour_end).map {|i| "#{i}-#{i+1}"}
results = get_hourly_results
else
@counts = @branch.get_aggregated_counts_per_wday(@period_start, @period_end, @included_days, @oh_type)
@xcategories = ['søn','man', 'tir', 'ons', 'tor', 'fre', 'lør']
results = get_daily_results
end
results = get_hourly_results
visitors_count = results.map {|serie| serie[:in_series]}.flatten.select {|i| i.is_a? (Fixnum)}
@total_no_of_visitors = visitors_count.inject(0) {|sum, elem| sum + elem}
results.map {|serie| serie[:in_series]}.each {|serie| serie.each {|k,v| @total_no_of_visitors += v } }
@name = @branch.name
@title_string = "Besøkende inn for #{@name}"
@subtitle_string = "periode: #{@period_label} | antall: #{@total_no_of_visitors}"
@xcategories = (@hour_start..@hour_end).map {|i| "#{i}-#{i+1}"}
@title_string = case @oh_type
when "extended"
"Besøkende inn for #{@name} meråpent tid"
when "regular"
"Besøkende inn for #{@name} betjent tid"
else
"Besøkende inn for #{@name}"
end
get_hourly_visitors_graph(results)
end
......@@ -204,7 +230,6 @@ def get_hourly_results
end
results
end
......@@ -213,14 +238,17 @@ def create_hourly_visitors(day, split = false, no_of_days = nil)
days = [*day]
slots = {}
# the split parameter is actually used to discern between wdays and datetimes... do fix
@counts.each do |time, count|
next if !split and !days.include?(time.wday)
next if !split and !days.include?(time.wday) # likely also unncecessary, as result set already filtered on wdays
next if split and !days.include?(time.strftime('%d-%m-%Y'))
next if time.hour < @hour_start || time.hour > @hour_end
time_slot = count[:hour_slot]
# this is similar to the code in branch, is there a better way to filter out the unneeded hours?
# also, fix this
idx = @xcategories.find_index(count[:hour_slot])
time_slot = idx
slots[time_slot] = {visitors_in: 0, visitors_out: 0} if slots[time_slot].nil?
slots[time_slot][:visitors_in] += count[:visitors_in]
slots[time_slot][:visitors_out] += count[:visitors_out]
......@@ -241,8 +269,6 @@ def create_hourly_visitors(day, split = false, no_of_days = nil)
{in_series: in_series, no_of_days: no_of_days, average_series: average_series}
end
def get_hourly_visitors_graph(series)
options = {
series: series,
......@@ -276,32 +302,72 @@ def get_hourly_visitors_graph(series)
}
# remind me: why did i do this again?
# todo: not sure why this is needed, but it is
options.merge(categories: @xcategories)
end
# ---------------------
def get_daily_results
labels = ['søn','man', 'tir', 'ons', 'tor', 'fre', 'lør']
results = []
# -----------
stats = create_daily_visitors
names = @included_days.map {|d| labels[d]}
results << stats.merge({name: names})
# end class HourlyGraph
results.each do |result|
result[:data] = @aggregate_type == 'total' ? result[:in_series] : result[:average_series]
end
results
end
class PeriodicalGraph < BG
def initialize
super
# -------------------------
def create_daily_visitors(no_of_days: nil)
slots = {}
in_series = []
average_series = []
no_of_days_series = [0,0,0,0,0,0,0]
period_end = @period_end < Date.today ? @period_end : Date.today
[0,1,2,3,4,5,6].each do |wday|
no_of_days_series[wday] = (@period_start..period_end).select {|d| wday == d.wday}.size
no_of_days_series[wday] = 1 if no_of_days_series[wday] < 1
end
@counts.each do |day_slot, values|
in_series << [day_slot, values[:visitors_in]]
average_series << [day_slot, values[:visitors_out]/no_of_days_series[day_slot]]
end
# TODO fix sorting
# unsorted keys can lead to some issues with Highcharts - fixing it here:
in_series = in_series.sort_by{|k,v| k.to_s.split('-')[0].to_i}
average_series = average_series.sort_by{|k,v| k.to_s.split('-')[0].to_i}
{in_series: in_series, no_of_days: no_of_days, average_series: average_series}
end
# -----------
# end class HourlyGraph
end
class PeriodicalGraph < BG
def initialize
super
end
end
......@@ -406,8 +472,6 @@ class BetaGraph
next if (hour < @start_hour) || (hour == @start_hour && time.min == 0)
next if (hour > @end_hour) and not (hour == (@end_hour + 1) && time.min == 0)
#puts "#{hour}:#{time.min}"
in_sum += count[:in]
out_sum += count[:out]
......
......@@ -33,9 +33,16 @@ module BranchUtils
# Optional parameter included_days accepts an integer array where sunday = 0 and saturday = 6
# example: [2,3] means return hash will only contain counts for tuesdays and wednesdays
#
def get_aggregated_counts(start_date, end_date, included_days = [])
# Optional parameter oh_type is either 'all', 'regular' or 'extended'
# 'extended' means only counts with oh_codes 'M' or 'N' will be included
#
def get_aggregated_counts(start_date, end_date, included_days = [], oh_type = 'all' )
all_counts = counts.where('(date >= ? and date <= ?) or (date = ? and time = ?)', start_date, end_date, end_date + 1, '00:00:00' )
all_counts = all_counts.where('oh_code IS NULL OR oh_code = "R"') if oh_type == 'regular'
all_counts = all_counts.where('oh_code = "M" OR oh_code = "N"') if oh_type == 'extended'
counts = Hash.new {|hsh, key| hsh[key] = {visitors_in: 0, visitors_out: 0}}
for count in all_counts
......@@ -51,8 +58,8 @@ module BranchUtils
end
def get_aggregated_counts_per_hour(start_date, end_date, included_days = [])
counts = get_aggregated_counts(start_date, end_date, included_days)
def get_aggregated_counts_per_hour(start_date, end_date, included_days = [], oh_type = 'all')
counts = get_aggregated_counts(start_date, end_date, included_days, oh_type)
slots = {}
......@@ -67,10 +74,22 @@ module BranchUtils
slots
end
end
def get_aggregated_counts_per_wday(start_date, end_date, included_days = [], oh_type = 'all')
labels = ['søn','man', 'tir', 'ons', 'tor', 'fre', 'lør'] # part of fishy logic, check it
counts = get_aggregated_counts(start_date, end_date, included_days, oh_type)
slots = {}
counts.each do |time, count|
wday = time.wday
slots[wday] = {visitors_in: 0, visitors_out: 0, wday: time.wday, day_slot: "#{labels[wday]}"} if slots[wday].nil?
slots[wday][:visitors_in] += count[:visitors_in]
slots[wday][:visitors_out] += count[:visitors_out]
end
slots
end
end
class Branch < ActiveRecord::Base
include BranchUtils
......@@ -578,6 +597,9 @@ class Portal < ActiveRecord::Base
class Count < ActiveRecord::Base
belongs_to :counter
scope :extended_oh, -> { where(oh_code: 'M').or(oh_code: 'N') }
scope :regular_oh, -> { where(oh_code: 'R') }
after_save :set_dirty_bit
def set_dirty_bit
......@@ -610,7 +632,6 @@ class Portal < ActiveRecord::Base
end
class ActiveSchedule < ActiveRecord::Base
has_many :opening_hours
belongs_to :branch
......
$(function() {
function createHourlyParams() {
const includedDays = $('input[name="included_days"]:checked').
map(function() {return this.value}).
......@@ -15,11 +13,10 @@ function createHourlyParams() {
if (hours.length === 2 || hours[0] <= hours[1]) {
startHour = hours[0]
endHour = hours[1]
endHour = hours[1]
}
let params = $('.param, input[name="aggregate_type"]').serialize()
let params = $('.param, input[name="aggregate_type"], input[name="oh_type"], input[name="period_type"]').serialize()
params += '&included_days=' + includedDays
params += '&start_hour=' + startHour + '&end_hour=' + endHour
......@@ -99,8 +96,6 @@ $('#get_hourly_splinegraph_button').click(function() {
$.getJSON('/api/hourly_chart?' + createHourlyParams() + '&type=spline').done(ajaxSuccess).fail(ajaxFail).always(ajaxAlways)
})
$('#select_weekdays').click(function() {
$('input[name="included_days"]').prop('checked', false)
......
......@@ -62,19 +62,25 @@ Velg filial: <select id="branch_selector" name="branch_id" class="param">
<button id="select_weekdays">Hverdager</button>
<button id="select_all">Alle</button>
<button id="select_none">Ingen</button>
<input type="checkbox" name="included_days" value="1" />Mandag
<input type="checkbox" name="included_days" value="2" />Tirsdag
<input type="checkbox" name="included_days" value="3" />Onsdag
<input type="checkbox" name="included_days" value="4" />Torsdag
<input type="checkbox" name="included_days" value="5" />Fredag
<input type="checkbox" name="included_days" value="6" />Lørdag
<input type="checkbox" name="included_days" value="0" />Søndag
<input type="checkbox" name="included_days" value="1" checked />Mandag
<input type="checkbox" name="included_days" value="2" checked />Tirsdag
<input type="checkbox" name="included_days" value="3" checked />Onsdag
<input type="checkbox" name="included_days" value="4" checked />Torsdag
<input type="checkbox" name="included_days" value="5" checked />Fredag
<input type="checkbox" name="included_days" value="6" checked />Lørdag
<input type="checkbox" name="included_days" value="0" checked />Søndag
</p>
</div>
<div class="btn-group" role="group" data-toggle="buttons" style="padding-bottom: 10px">
<label>Tidsrom(7-23)</label>
<label>
<input type="radio" name="period_type" value="periodical" />Hele dager
</label>
<label>
<input type="radio" name="period_type" value="hourly" checked />Per time
</label>
<label class="hours_input">Tidsrom(7-23)</label>
<input type="text" size="6" pattern="([01]?[0-9]|2[0-3])-([01]?[0-9]|2[0-3])" id="hours_input">
<label>
<input type="radio" name="aggregate_type" value="total" checked/>Total
......@@ -86,6 +92,18 @@ Velg filial: <select id="branch_selector" name="branch_id" class="param">
<input type="checkbox" name="split_weeks" value="normal" class="param"/> Skill ut uker
</div>
<div class="btn-group" role="group" data-toggle="buttons" style="padding-bottom: 10px">
<label>
<input type="radio" name="oh_type" value="all" checked/>Heltid
</label>
<label>
<input type="radio" name="oh_type" value="extended"/>Meråpent
</label>
<label>
<input type="radio" name="oh_type" value="regular"/>Betjent tid
</label>
</div>
<button id="get_hourly_bargraph_button">Søylediagram</button>
<button id="get_hourly_splinegraph_button">Spline</button>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment