Skip to content

Commit

Permalink
Forecast improvements + cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
forsbergplustwo committed Sep 15, 2023
1 parent 53bffd8 commit f43d031
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 43 deletions.
2 changes: 1 addition & 1 deletion app/controllers/rename_apps_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def create
from: rename_app_params[:from],
to: rename_app_params[:to]
)
if app_renamer.rename!
if app_renamer.rename
redirect_to rename_apps_path, notice: "App renamed successfully"
else
flash.now[:error] = "App rename failed"
Expand Down
7 changes: 0 additions & 7 deletions app/helpers/home_helper.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
module HomeHelper
def nav_link(link_text, link_path)
class_name = current_page?(link_path) ? "active" : ""

content_tag(:li, class: class_name) do
link_to link_text, link_path
end
end
end
10 changes: 1 addition & 9 deletions app/helpers/metrics_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,6 @@ def period_word(period)
end
end

def select_chart(tiles, selected)
if selected.present?
tiles.find { |t| t.handle == selected }
else
tiles.first
end
end

def metric_chart_url(tile_type, date, period, app)
url_for(
action: action_name,
Expand All @@ -88,7 +80,7 @@ def metrics_chart_options
easing: "inAndOut"
},
lineWidth: 3,
colors: ["#5912D5", "#5912D5"],
colors: ["#5a24cd", "#7945e3"],
explorer: {
keepInBounds: true,
axis: "horizontal",
Expand Down
9 changes: 9 additions & 0 deletions app/javascript/controllers/datefield_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
static targets = ['input']

show() {
this.inputTarget.showPicker()
}
}
3 changes: 3 additions & 0 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { application } from "./application"
import ChartkickController from "./chartkick_controller"
application.register("chartkick", ChartkickController)

import DatefieldController from "./datefield_controller"
application.register("datefield", DatefieldController)

import FiltersController from "./filters_controller"
application.register("filters", FiltersController)

Expand Down
10 changes: 5 additions & 5 deletions app/models/app_renamer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ def initialize(user:, from:, to:)
@to = to
end

def rename!
def rename
return false unless valid?
rename_metrics!
rename_payments!
rename_metrics
rename_payments
true
end

private

def rename_metrics!
def rename_metrics
@user.metrics.where(app_title: @from).update_all(app_title: @to)
end

def rename_payments!
def rename_payments
@user.payments.where(app_title: @from).update_all(app_title: @to)
end

Expand Down
1 change: 0 additions & 1 deletion app/models/import/adaptor/csv_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ def stream_payments(main_enum)
main_enum.yield parsed_row
end
ensure
Rails.logger.info "Closing and unlinking temp files"
close_and_unlink_temp_files
end

Expand Down
5 changes: 4 additions & 1 deletion app/models/import/adaptor/shopify_payments_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ def throttle(start_time)
end

def handle_error(api_error)
@import.partner_api_credential.invalidate_with_message!(results.errors.messages.map { |k, v| "#{k}=#{v}" }.join("&"))
error_message = api_error.messages.map { |k, v| "#{k}=#{v}" }.join("&")
if error_message.include?("Unauthorized") || error_message.include?("Forbidden") || error_message.include?("permissions")
@import.partner_api_credential.invalidate_with_message!(error_message)
end
end
end
9 changes: 0 additions & 9 deletions app/models/metric.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require "prophet-rb"

class Metric < ApplicationRecord
belongs_to :user
belongs_to :import
Expand Down Expand Up @@ -52,13 +50,6 @@ def chart_data(date, period, calculation, column)
metrics.sort_by { |h| h[0].to_datetime }
end

def forecast_for_chart_data(chart_data)
Prophet.forecast(chart_data, count: 3)
rescue ArgumentError
# Forecasts require a minimum of 10 data points
[]
end

# Build a hash of dates containing date ranges,
# for each period between the first date and the date selected
def group_options(date, first_date, period)
Expand Down
50 changes: 50 additions & 0 deletions app/models/metric/forecast_charter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require "prophet-rb"
require "rover"

class Metric::ForecastCharter
FORECAST_PERIODS = 6
FREQUENCIES = {
monthly: "MS"
}.freeze

def initialize(chart_data:)
@chart_data = chart_data
end

def chart_data
return [] if insufficient_data?

dataframe = dataframe_from_chart_data
prophet = prophet_for(dataframe)
future_dataframe = future_dataframe_from(prophet)

generate_forecast_data(prophet, future_dataframe, @chart_data.keys.last)
end

private

def insufficient_data?
@chart_data.size < 10
end

def dataframe_from_chart_data
Rover::DataFrame.new({"ds" => @chart_data.keys, "y" => @chart_data.values})
end

def prophet_for(dataframe)
Prophet.new.fit(dataframe)
end

def future_dataframe_from(prophet)
prophet.make_future_dataframe(periods: FORECAST_PERIODS, freq: FREQUENCIES[:monthly])
end

def generate_forecast_data(prophet, future_dataframe, last_date)
forecast = prophet.predict(future_dataframe)
data = []
forecast["ds"].each_with_index do |date, index|
data << [date, forecast["yhat"][index]] if date > last_date
end
data
end
end
10 changes: 5 additions & 5 deletions app/models/metric/tile_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def period_ago_change(period_ago)
def chart_data
chart_data = basic_chart_data

if @filter.show_forecasts?
if @filter.show_forecasts? && @filter.period == 30
forecast_data = forecast_chart_data(chart_data)
return chart_data if forecast_data[:data].empty?
chart_data << forecast_data
Expand All @@ -55,17 +55,17 @@ def chart_data
private

def basic_chart_data
metrics_chart = fetch_metrics_chart
metrics_chart = metrics_chart_data
[{name: @display, data: metrics_chart}]
end

def forecast_chart_data(chart_data)
forecast_data = Metric.forecast_for_chart_data(fetch_metrics_chart)
forecast_data = Metric::ForecastCharter.new(chart_data: metrics_chart_data).chart_data
{name: "Forecast", data: forecast_data}
end

def fetch_metrics_chart
@fetch_metrics_chart ||= begin
def metrics_chart_data
@metrics_chart_data ||= begin
metrics = @filter.user_metrics_by_app.by_optional_charge_type(@charge_type)
metrics.chart_data(@filter.date, @filter.period, @calculation, @column).to_h
end
Expand Down
20 changes: 15 additions & 5 deletions app/views/metrics/_filter.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%= form_tag(
url_for(action: action_name, charge_type: filter.charge_type),
method: :get,
data: {controller: "filters daterangepicker", daterangepicker_target: "form", turbo_frame: :metrics, turbo_action: :advance},
data: {controller: "filters", turbo_frame: :metrics, turbo_action: :advance},
) do %>

<%= hidden_field_tag :chart, filter.chart %>
Expand Down Expand Up @@ -29,17 +29,27 @@
<% end %>
<% end %>

<% filters.with_item(label: filter.date.to_s, sectioned: false, style: "white-space: nowrap;") do %>
<% filters.with_item(
label: filter.date.to_s,
sectioned: false,
style: "white-space: nowrap;",
data: {
controller: "datefield",
action: "click->datefield#show"}
) do %>
<%= polaris_text_field(
name: :date,
value: filter.date,
type: :date,
label_hidden: true,
input_options: {
min: (filter.oldest_metric_date),
max: (filter.newest_metric_date_or_today)
},
data: {action: "input->filters#submit change->filters#submit"}
max: (filter.newest_metric_date_or_today),
data: {
datefield_target: "input",
action: "input->filters#submit change->filters#submit"
}
}
) %>
<% end %>

Expand Down

0 comments on commit f43d031

Please sign in to comment.