diff --git a/app/controllers/stat_created_plans_by_template_controller.rb b/app/controllers/stat_created_plans_by_template_controller.rb
new file mode 100644
index 0000000..f48d758
--- /dev/null
+++ b/app/controllers/stat_created_plans_by_template_controller.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class StatCreatedPlansByTemplateController < ApplicationController
+
+ def index
+ check_authorized!
+
+ data = StatCreatedPlan.monthly_range(index_filter).order(date: :desc)
+
+ if params[:format] == "csv"
+ data_csvified = StatCreatedPlan.to_csv(data, details: { by_template: true })
+ send_data(data_csvified, filename: "created_plan_by_template.csv")
+ else
+ render(json: data.as_json(only: [:date, :count], methods: :by_template))
+ end
+ end
+
+ private
+
+ def index_filter
+ {
+ org: current_user.org,
+ start_date: params[:start_date],
+ end_date: params[:end_date]
+ }
+ end
+
+ def check_authorized!
+ unless current_user.present? &&
+ current_user.can_org_admin?
+ raise Pundit::NotAuthorizedError
+ end
+ end
+
+end
diff --git a/app/controllers/usage_controller.rb b/app/controllers/usage_controller.rb
index cb186f7..3ba84b4 100644
--- a/app/controllers/usage_controller.rb
+++ b/app/controllers/usage_controller.rb
@@ -4,6 +4,7 @@
def index
check_authorized!
+
render("index",
locals: {
orgs: Org.all,
diff --git a/app/javascript/views/usage/index.js b/app/javascript/views/usage/index.js
index 9b7245a..e7ff4de 100644
--- a/app/javascript/views/usage/index.js
+++ b/app/javascript/views/usage/index.js
@@ -149,3 +149,77 @@
};
initialise();
});
+
+$(() => {
+ const jQuerySelectorSelect = $('select[name=monthly_plans_by_template]');
+ let drawnChart = null;
+ const randomRgb = () => {
+ const { round, random } = Math;
+ const max = 255;
+ const f = () => round(random() * max);
+ return `rgb(${f()},${f()},${f()})`;
+ };
+ const yAxisLabel = date => moment(date).format('MMM-YY');
+
+ const drawHorizontalBar = (canvasSelector, data) => {
+ const chart = new Chart(canvasSelector, { // eslint-disable-line no-new
+ type: 'horizontalBar',
+ data,
+ options: {
+ scales: {
+ xAxes: [{
+ ticks: { beginAtZero: true },
+ precision: 1,
+ }],
+ },
+ },
+ });
+ return chart;
+ };
+
+ const buildData = (data) => {
+ const labels = data.map(current => yAxisLabel(current.date));
+
+ const datasetsMap = data.reduce((acc, statCreatedPlan) => {
+ statCreatedPlan.by_template.forEach((template) => {
+ if (!acc[template.name]) {
+ acc[template.name] = { label: template.name, data: [], backgroundColor: randomRgb() };
+ }
+ acc[template.name].data.push({ x: template.count, y: yAxisLabel(statCreatedPlan.date) });
+ });
+ return acc;
+ }, {});
+
+ const datasets = Object.keys(datasetsMap).map(key => datasetsMap[key]);
+
+ return { labels, datasets };
+ };
+
+ const fetch = (lastDayOfMonth) => {
+ const baseUrl = $('select[name="monthly_plans_by_template"]').attr('data-url');
+ $.ajax({
+ url: `${baseUrl}?start_date=${lastDayOfMonth}`,
+ }).then((data) => {
+ const chartData = buildData(data);
+ const canvasSelector = '#monthly_plans_by_template_canvas';
+ if (drawnChart) {
+ drawnChart.destroy();
+ }
+ drawnChart = drawHorizontalBar($(canvasSelector), chartData);
+ });
+ };
+
+ const handler = () => {
+ const selectedMonth = jQuerySelectorSelect.val();
+ if (selectedMonth) {
+ fetch(selectedMonth);
+ }
+ };
+
+ jQuerySelectorSelect.on('change', (e) => {
+ e.preventDefault();
+ handler();
+ });
+
+ handler();
+});
diff --git a/app/models/stat.rb b/app/models/stat.rb
index acc61db..08b4f71 100644
--- a/app/models/stat.rb
+++ b/app/models/stat.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# == Schema Information
#
# Table name: stats
@@ -5,6 +7,7 @@
# id :integer not null, primary key
# count :integer default(0)
# date :date not null
+# details :text
# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
@@ -12,14 +15,22 @@
#
class Stat < ActiveRecord::Base
+
+ extend OrgDateRangeable
+
belongs_to :org
+ validates_uniqueness_of :type, scope: [:date, :org_id]
+
class << self
+
def to_csv(stats)
data = stats.map do |stat|
{ date: stat.date, count: stat.count }
end
Csvable.from_array_of_hashes(data)
end
+
end
+
end
diff --git a/app/models/stat_created_plan.rb b/app/models/stat_created_plan.rb
index 43a9f2a..0f0bd35 100644
--- a/app/models/stat_created_plan.rb
+++ b/app/models/stat_created_plan.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# == Schema Information
#
# Table name: stats
@@ -5,18 +7,64 @@
# id :integer not null, primary key
# count :integer default(0)
# date :date not null
+# details :text
# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# org_id :integer
#
+require "set"
+
class StatCreatedPlan < Stat
- extend OrgDateRangeable
+
+ serialize :details, JSON
+
+ def by_template
+ by_template = self.details["by_template"]
+ return [] unless by_template.present?
+ by_template
+ end
class << self
- def to_csv(created_plans)
- Stat.to_csv(created_plans)
+
+ def to_csv(created_plans, details: { by_template: false })
+ if details[:by_template]
+ to_csv_by_template(created_plans)
+ else
+ super(created_plans)
+ end
end
+
+ private
+
+ def to_csv_by_template(created_plans)
+ template_names = lambda do |created_plans|
+ unique = Set.new
+ created_plans.each do |created_plan|
+ created_plan.details&.fetch("by_template", [])&.each do |name_count|
+ unique.add(name_count.fetch("name"))
+ end
+ end
+ unique.to_a
+ end.call(created_plans)
+
+ data = created_plans.map do |created_plan|
+ tuple = { date: created_plan.date }
+ template_names.reduce(tuple) do |acc, name|
+ acc[name] = 0
+ acc
+ end
+ created_plan.details&.fetch("by_template", [])&.each do |name_count|
+ tuple[name_count.fetch("name")] = name_count.fetch("count")
+ end
+ tuple[:count] = created_plan.count
+ tuple
+ end
+
+ Csvable.from_array_of_hashes(data)
+ end
+
end
+
end
diff --git a/app/models/stat_created_plan/create_or_update.rb b/app/models/stat_created_plan/create_or_update.rb
new file mode 100644
index 0000000..d312499
--- /dev/null
+++ b/app/models/stat_created_plan/create_or_update.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+class StatCreatedPlan
+
+ class CreateOrUpdate
+
+ class << self
+
+ def do(start_date:, end_date:, org:)
+ count = count_plans(start_date: start_date, end_date: end_date, org: org)
+ by_template = by_template(start_date: start_date, end_date: end_date, org: org)
+ attrs = {
+ date: end_date.to_date,
+ org_id: org.id,
+ count: count,
+ details: { by_template: by_template }
+ }
+ stat_created_plan = StatCreatedPlan.find_by(
+ date: attrs[:date],
+ org_id: attrs[:org_id]
+ )
+
+ if stat_created_plan.present?
+ stat_created_plan.update(attrs)
+ else
+ StatCreatedPlan.create(attrs)
+ end
+ end
+
+ private
+
+ def users(org)
+ User.where(users: { org_id: org.id })
+ end
+
+ def plans(start_date:, end_date:)
+ Plan.where(plans: { created_at: start_date..end_date })
+ end
+
+ def creator_admin
+ Role.with_access_flags(:creator, :administrator)
+ end
+
+ def count_plans(start_date:, end_date:, org:)
+ users = users(org)
+ plans = plans(start_date: start_date, end_date: end_date)
+
+ Role.joins([:plan, :user])
+ .merge(creator_admin)
+ .merge(users)
+ .merge(plans)
+ .select(:plan_id)
+ .distinct
+ .count
+ end
+
+ def by_template(start_date:, end_date:, org:)
+ users = users(org)
+ plans = plans(start_date: start_date, end_date: end_date)
+ roleable_plan_ids = Role.joins([:plan, :user])
+ .merge(creator_admin)
+ .merge(users)
+ .merge(plans)
+ .select(:plan_id)
+ .distinct
+ template_counts = Plan.where(id: roleable_plan_ids).group(:template_id).count
+ template_names = Template.where(id: template_counts.keys).pluck(:id, :title)
+ template_names.map do |t|
+ { name: t[1], count: template_counts[t[0]] }
+ end
+ end
+
+ end
+
+ end
+
+end
diff --git a/app/models/stat_joined_user.rb b/app/models/stat_joined_user.rb
index ec9820b..62dd3b1 100644
--- a/app/models/stat_joined_user.rb
+++ b/app/models/stat_joined_user.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# == Schema Information
#
# Table name: stats
@@ -5,18 +7,21 @@
# id :integer not null, primary key
# count :integer default(0)
# date :date not null
+# details :text
# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# org_id :integer
#
-class StatJoinedUser < Stat
- extend OrgDateRangeable
+class StatJoinedUser < Stat
class << self
+
def to_csv(joined_users)
Stat.to_csv(joined_users)
end
+
end
+
end
diff --git a/app/models/stat_joined_user/create_or_update.rb b/app/models/stat_joined_user/create_or_update.rb
new file mode 100644
index 0000000..46117d8
--- /dev/null
+++ b/app/models/stat_joined_user/create_or_update.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class StatJoinedUser
+
+ class CreateOrUpdate
+
+ class << self
+
+ def do(start_date:, end_date:, org:)
+ count = count_users(start_date: start_date, end_date: end_date, org_id: org.id)
+ attrs = { date: end_date.to_date, count: count, org_id: org.id }
+
+ stat_joined_user = StatJoinedUser.find_by(
+ date: attrs[:date],
+ org_id: attrs[:org_id]
+ )
+
+ if stat_joined_user.present?
+ stat_joined_user.update(attrs)
+ else
+ StatJoinedUser.create(attrs)
+ end
+ end
+
+ private
+
+ def count_users(start_date:, end_date:, org_id:)
+ User.where(created_at: start_date..end_date, org_id: org_id).count
+ end
+
+ end
+
+ end
+
+end
diff --git a/app/services/org/create_created_plan_service.rb b/app/services/org/create_created_plan_service.rb
index 842382a..c668a77 100644
--- a/app/services/org/create_created_plan_service.rb
+++ b/app/services/org/create_created_plan_service.rb
@@ -1,30 +1,27 @@
+# frozen_string_literal: true
+
class Org
+
class CreateCreatedPlanService
+
class << self
+
def call(org = nil)
orgs = org.nil? ? Org.all : [org]
orgs.each do |org|
OrgDateRangeable.split_months_from_creation(org) do |start_date, end_date|
- create_count_for_date(start_date: start_date, end_date: end_date, org: org)
+ StatCreatedPlan::CreateOrUpdate.do(
+ start_date: start_date,
+ end_date: end_date,
+ org: org
+ )
end
end
end
- private
-
- def count_plans(start_date: , end_date: , org:)
- users = User.where('users.org_id = ?', org.id)
- plans = Plan.where('plans.created_at >= ? AND plans.created_at <= ?', start_date, end_date)
- creator_admon = Role.with_access_flags(:creator, :administrator)
-
- Role.joins([:plan, :user]).merge(creator_admon).merge(users).merge(plans).select(:plan_id).distinct.count
- end
-
- def create_count_for_date(start_date:, end_date:, org:)
- count = count_plans(start_date: start_date, end_date: end_date, org: org)
- StatCreatedPlan.create(date: end_date.to_date, count: count, org_id: org.id)
- end
end
+
end
+
end
diff --git a/app/services/org/create_joined_user_service.rb b/app/services/org/create_joined_user_service.rb
index 02dbbb2..e4842eb 100644
--- a/app/services/org/create_joined_user_service.rb
+++ b/app/services/org/create_joined_user_service.rb
@@ -1,25 +1,26 @@
+# frozen_string_literal: true
+
class Org
+
class CreateJoinedUserService
+
class << self
+
def call(org = nil)
- orgs = org.nil? ? ::Org.all : [org]
+ orgs = org.nil? ? Org.all : [org]
orgs.each do |org|
OrgDateRangeable.split_months_from_creation(org) do |start_date, end_date|
- create_count_for_date(start_date: start_date, end_date: end_date, org: org)
+ StatJoinedUser::CreateOrUpdate.do(
+ start_date: start_date,
+ end_date: end_date,
+ org: org
+ )
end
end
end
- private
-
- def count_users(start_date: , end_date: , org_id: )
- User.where('created_at >= ? AND created_at <= ? AND org_id = ?', start_date, end_date, org_id).count
- end
-
- def create_count_for_date(start_date:, end_date:, org:)
- count = count_users(start_date: start_date, end_date: end_date, org_id: org.id)
- ::StatJoinedUser.create(date: end_date.to_date, count: count, org_id: org.id)
- end
end
+
end
+
end
diff --git a/app/services/org/create_last_month_created_plan_service.rb b/app/services/org/create_last_month_created_plan_service.rb
index 3f42100..8093862 100644
--- a/app/services/org/create_last_month_created_plan_service.rb
+++ b/app/services/org/create_last_month_created_plan_service.rb
@@ -1,32 +1,29 @@
+# frozen_string_literal: true
+
class Org
+
class CreateLastMonthCreatedPlanService
+
class << self
+
def call(org = nil)
- orgs = org.nil? ? ::Org.all : [org]
+ orgs = org.nil? ? Org.all : [org]
orgs.each do |org|
months = OrgDateRangeable.split_months_from_creation(org)
last = months.last
if last.present?
- create_count_for_date(start_date: last[:start_date], end_date: last[:end_date], org: org)
+ StatCreatedPlan::CreateOrUpdate.do(
+ start_date: last[:start_date],
+ end_date: last[:end_date],
+ org: org
+ )
end
end
end
- private
-
- def count_plans(start_date: , end_date: , org:)
- users = User.where('users.org_id = ?', org.id)
- plans = Plan.where('plans.created_at >= ? AND plans.created_at <= ?', start_date, end_date)
- creator_admon = Role.with_access_flags(:creator, :administrator)
-
- Role.joins([:plan, :user]).merge(creator_admon).merge(users).merge(plans).select(:plan_id).distinct.count
- end
-
- def create_count_for_date(start_date:, end_date:, org:)
- count = count_plans(start_date: start_date, end_date: end_date, org: org)
- ::StatCreatedPlan.create(date: end_date.to_date, count: count, org_id: org.id)
- end
end
+
end
+
end
diff --git a/app/services/org/create_last_month_joined_user_service.rb b/app/services/org/create_last_month_joined_user_service.rb
index 58817d2..026dfd8 100644
--- a/app/services/org/create_last_month_joined_user_service.rb
+++ b/app/services/org/create_last_month_joined_user_service.rb
@@ -1,27 +1,28 @@
+# frozen_string_literal: true
+
class Org
+
class CreateLastMonthJoinedUserService
+
class << self
+
def call(org = nil)
orgs = org.nil? ? ::Org.all : [org]
orgs.each do |org|
months = OrgDateRangeable.split_months_from_creation(org)
last = months.last
if last.present?
- create_count_for_date(start_date: last[:start_date], end_date: last[:end_date], org: org)
+ StatJoinedUser::CreateOrUpdate.do(
+ start_date: last[:start_date],
+ end_date: last[:end_date],
+ org: org
+ )
end
end
end
- private
-
- def count_users(start_date: , end_date: , org_id: )
- User.where('created_at >= ? AND created_at <= ? AND org_id = ?', start_date, end_date, org_id).count
- end
-
- def create_count_for_date(start_date:, end_date:, org:)
- count = count_users(start_date: start_date, end_date: end_date, org_id: org.id)
- ::StatJoinedUser.create(date: end_date.to_date, count: count, org_id: org.id)
- end
end
+
end
+
end
diff --git a/app/services/org/total_count_created_plan_service.rb b/app/services/org/total_count_created_plan_service.rb
index 41d8a4e..b5f7720 100644
--- a/app/services/org/total_count_created_plan_service.rb
+++ b/app/services/org/total_count_created_plan_service.rb
@@ -1,6 +1,11 @@
+# frozen_string_literal: true
+
class Org
+
class TotalCountCreatedPlanService
+
class << self
+
def call(org = nil)
return for_orgs unless org.present?
for_org(org)
@@ -9,7 +14,11 @@
private
def for_orgs
- result = ::StatCreatedPlan.includes(:org).select(:"orgs.name", :count).group(:"orgs.name").sum(:count)
+ result = ::StatCreatedPlan
+ .includes(:org)
+ .select(:"orgs.name", :count)
+ .group(:"orgs.name")
+ .sum(:count)
result.each_pair.map do |pair|
build_model(org_name: pair[0], count: pair[1].to_i)
end
@@ -20,9 +29,12 @@
build_model(org_name: org.name, count: result)
end
- def build_model(org_name: , count: )
+ def build_model(org_name:, count:)
{ org_name: org_name, count: count }
end
+
end
+
end
+
end
diff --git a/app/services/org/total_count_joined_user_service.rb b/app/services/org/total_count_joined_user_service.rb
index 0f63d41..21efde4 100644
--- a/app/services/org/total_count_joined_user_service.rb
+++ b/app/services/org/total_count_joined_user_service.rb
@@ -1,6 +1,11 @@
+# frozen_string_literal: true
+
class Org
+
class TotalCountJoinedUserService
+
class << self
+
def call(org = nil)
return for_orgs unless org.present?
for_org(org)
@@ -9,7 +14,11 @@
private
def for_orgs
- result = ::StatJoinedUser.includes(:org).select(:"orgs.name", :count).group(:"orgs.name").sum(:count)
+ result = ::StatJoinedUser
+ .includes(:org)
+ .select(:"orgs.name", :count)
+ .group(:"orgs.name")
+ .sum(:count)
result.each_pair.map do |pair|
build_model(org_name: pair[0], count: pair[1].to_i)
end
@@ -20,9 +29,12 @@
build_model(org_name: org.name, count: result)
end
- def build_model(org_name: , count: )
+ def build_model(org_name:, count:)
{ org_name: org_name, count: count }
end
+
end
+
end
+
end
diff --git a/app/services/org/total_count_stat_service.rb b/app/services/org/total_count_stat_service.rb
index 064a466..4a3466b 100644
--- a/app/services/org/total_count_stat_service.rb
+++ b/app/services/org/total_count_stat_service.rb
@@ -1,6 +1,11 @@
+# frozen_string_literal: true
+
class Org
+
class TotalCountStatService
+
class << self
+
def call
total = build_from_joined_user
build_from_created_plan(total)
@@ -45,6 +50,9 @@
reducer_body(acc, count, :total_plans)
end
end
+
end
+
end
+
end
diff --git a/app/views/usage/index.html.erb b/app/views/usage/index.html.erb
index dd356b0..8152720 100644
--- a/app/views/usage/index.html.erb
+++ b/app/views/usage/index.html.erb
@@ -132,4 +132,38 @@
<%= _('There is no data available for plans yet.') %>
+
+
+
<%= _('No. plans by template') %>
+
+
+
diff --git a/config/routes.rb b/config/routes.rb
index b7eb668..d28e94a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -127,6 +127,8 @@
resources :usage_downloads, only: [:index]
+ resources :stat_created_plans_by_template, only: [:index]
+
resources :roles, only: [:create, :update, :destroy] do
member do
put :deactivate
diff --git a/db/migrate/20181025220743_add_details_to_stats.rb b/db/migrate/20181025220743_add_details_to_stats.rb
new file mode 100644
index 0000000..506161d
--- /dev/null
+++ b/db/migrate/20181025220743_add_details_to_stats.rb
@@ -0,0 +1,5 @@
+class AddDetailsToStats < ActiveRecord::Migration
+ def change
+ add_column :stats, :details, :text
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 96d379c..0b0529e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20181024120747) do
+ActiveRecord::Schema.define(version: 20181025220743) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -326,6 +326,7 @@
t.integer "org_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.text "details"
end
create_table "templates", force: :cascade do |t|
diff --git a/lib/csvable.rb b/lib/csvable.rb
index f9f5627..867a145 100644
--- a/lib/csvable.rb
+++ b/lib/csvable.rb
@@ -3,8 +3,8 @@
module Csvable
require "csv"
-
class << self
+
def from_array_of_hashes(data = [])
return "" unless data.first&.keys
headers = data.first.keys
@@ -17,6 +17,7 @@
end
end
end
+
end
end
diff --git a/lib/org_date_rangeable.rb b/lib/org_date_rangeable.rb
index 67c96e5..08739e1 100644
--- a/lib/org_date_rangeable.rb
+++ b/lib/org_date_rangeable.rb
@@ -1,13 +1,31 @@
+# frozen_string_literal: true
+
module OrgDateRangeable
- def monthly_range(org:, start_date: Date.today.end_of_month, end_date: Date.today.end_of_month)
- where("org_id = :org_id and date >= :start_date and date <= :end_date", org_id: org&.id, start_date: start_date, end_date: end_date)
+
+ def monthly_range(org:, start_date: nil, end_date: Date.today.end_of_month)
+ query_string = "org_id = :org_id"
+ query_hash = { org_id: org.id }
+
+ unless start_date.nil?
+ query_string += " and date >= :start_date"
+ query_hash[:start_date] = start_date
+ end
+
+ unless end_date.nil?
+ query_string += " and date <= :end_date"
+ query_hash[:end_date] = end_date
+ end
+ where(query_string, query_hash)
end
class << self
+
def split_months_from_creation(org, &block)
starts_at = org.created_at
ends_at = starts_at.end_of_month
- callable = block.nil? ? Proc.new {} : lambda{ | start_date, end_date| block.call(start_date, end_date) }
+ callable = block.nil? ?
+ Proc.new {} :
+ lambda { | start_date, end_date| block.call(start_date, end_date) }
enumerable = []
while !(starts_at.future? || ends_at.future?) do
@@ -19,5 +37,7 @@
enumerable
end
+
end
+
end
diff --git a/spec/models/stat_created_plan_spec.rb b/spec/models/stat_created_plan_spec.rb
index edf322e..d1a0a9c 100644
--- a/spec/models/stat_created_plan_spec.rb
+++ b/spec/models/stat_created_plan_spec.rb
@@ -11,20 +11,66 @@
end
context 'when instances' do
let(:org) { FactoryBot.create(:org) }
- it 'returns instances in a comma-separated row' do
- may = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 05, 31), org: org, count: 20)
- june = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 06, 30), org: org, count: 10)
- data = [may, june]
- csv = described_class.to_csv(data)
+ context 'when no details' do
+ it 'returns counts in a comma-separated row' do
+ may = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 05, 31), org: org, count: 20)
+ june = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 06, 30), org: org, count: 10)
+ data = [may, june]
- expected_csv = <<~HERE
+ csv = described_class.to_csv(data)
+
+ expected_csv = <<~HERE
Date,Count
2018-05-31,20
2018-06-30,10
- HERE
- expect(csv).to eq(expected_csv)
+ HERE
+ expect(csv).to eq(expected_csv)
+ end
end
+
+ context 'when details by template is true' do
+ it 'returns counts by_template in a comma-separated row' do
+ may = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 05, 31), org: org, count: 20, details: { by_template: [
+ { name: 'Template1', count: 5 },
+ { name: 'Template2', count: 15 }
+ ]})
+ june = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 06, 30), org: org, count: 10, details: { by_template: [
+ { name: 'Template1', count: 2 },
+ { name: 'Template3', count: 8 }
+ ]})
+ july = FactoryBot.create(:stat_created_plan, date: Date.new(2018, 07, 31), org: org, count: 0)
+ data = [may, june, july]
+
+ csv = described_class.to_csv(data, details: { by_template: true })
+
+ expected_csv = <<~HERE
+ Date,Template1,Template2,Template3,Count
+ 2018-05-31,5,15,0,20
+ 2018-06-30,2,0,8,10
+ 2018-07-31,0,0,0,0
+ HERE
+ expect(csv).to eq(expected_csv)
+ end
+ end
+ end
+ end
+
+ describe '.serialize' do
+ let(:org) { FactoryBot.create(:org, name: 'An Org', contact_email: 'foo@bar.com', contact_name: 'Foo') }
+ let(:details) do
+ { 'by_template' => [
+ { 'name' => 'Template 1', 'count' => 10 },
+ { 'name' => 'Template 2', 'count' => 10 }
+ ]}
+ end
+
+ it 'retrieves JSON details as a hash object' do
+ september = FactoryBot.create(:stat_created_plan, date: '2018-09-30', org: org, count: 20, details: details)
+
+ json_details = described_class.find_by_date('2018-09-30').details
+
+ expect(json_details).to eq(details)
end
end
end
diff --git a/spec/models/stat_joined_user_spec.rb b/spec/models/stat_joined_user_spec.rb
index 022358a..59b06c3 100644
--- a/spec/models/stat_joined_user_spec.rb
+++ b/spec/models/stat_joined_user_spec.rb
@@ -5,27 +5,6 @@
@org = FactoryBot.create(:org)
end
- describe '.monthly_range' do
- context 'when org is missing' do
- it 'raises ArgumentError' do
- expect do
- described_class.monthly_range
- end.to raise_error(ArgumentError)
- end
- end
- it 'returns matching instances' do
- start_date = Date.new(2018, 04, 30)
- end_date = Date.new(2018, 05, 31)
- june = FactoryBot.create(:stat_joined_user, date: Date.new(2018, 06, 30), org: @org)
- may = FactoryBot.create(:stat_joined_user, date: end_date, org: @org)
- april = FactoryBot.create(:stat_joined_user, date: start_date, org: @org)
-
- april_to_may = described_class.monthly_range(org: @org, start_date: start_date, end_date: end_date)
-
- expect(april_to_may).to include(april, may)
- end
- end
-
describe '.to_csv' do
context 'when no instances' do
it 'returns empty' do
diff --git a/spec/org_date_rangeable_spec.rb b/spec/org_date_rangeable_spec.rb
index 70c00ca..8d3e929 100644
--- a/spec/org_date_rangeable_spec.rb
+++ b/spec/org_date_rangeable_spec.rb
@@ -1,11 +1,57 @@
require 'rails_helper'
RSpec.describe OrgDateRangeable do
- describe '.split_months_from_creation' do
- let(:org) do
- FactoryBot.create(:org, created_at: DateTime.new(2018,05,28,0,0,0))
+ let(:org) do
+ FactoryBot.create(:org, created_at: DateTime.new(2018,05,28,0,0,0))
+ end
+
+ describe '.monthly_range' do
+ context 'when org keyword param is missing' do
+ it 'returns ArgumentError' do
+ expect do
+ StatJoinedUser.monthly_range
+ end.to raise_error(ArgumentError, /missing keyword: org/)
+ end
end
+ context 'when start_date is nil' do
+ it 'returns every record whose date <= end_date' do
+ FactoryBot.create(:stat_joined_user, date: '2018-06-30', org: org, count: 10)
+ FactoryBot.create(:stat_joined_user, date: '2018-07-31', org: org, count: 10)
+
+ result = StatJoinedUser.monthly_range(org: org, end_date: '2018-06-30')
+
+ expected_result = StatJoinedUser.where(org: org, date: '2018-06-30')
+ expect(result.map(&:attributes)).to eq(expected_result.map(&:attributes))
+ end
+ end
+
+ context 'when end_date is nil' do
+ it 'returns every record whose date >= start_date' do
+ FactoryBot.create(:stat_joined_user, date: '2018-06-30', org: org, count: 10)
+ FactoryBot.create(:stat_joined_user, date: '2018-07-31', org: org, count: 10)
+
+ result = StatJoinedUser.monthly_range(org: org, start_date: '2018-07-31')
+
+ expected_result = StatJoinedUser.where(org: org, date: '2018-07-31')
+ expect(result.map(&:attributes)).to eq(expected_result.map(&:attributes))
+ end
+ end
+
+ context 'when all keyword are passed' do
+ it 'returns every record within start_date and end_date' do
+ FactoryBot.create(:stat_joined_user, date: '2018-06-30', org: org, count: 10)
+ FactoryBot.create(:stat_joined_user, date: '2018-07-31', org: org, count: 10)
+
+ result = StatJoinedUser.monthly_range(org: org, start_date: '2018-06-30', end_date: '2018-07-31')
+
+ expected_result = StatJoinedUser.where('org_id = ? and date >= ? and date <= ?', org.id, '2018-06-30', '2018-07-31')
+ expect(result.map(&:attributes)).to eq(expected_result.map(&:attributes))
+ end
+ end
+ end
+
+ describe '.split_months_from_creation' do
it "starts at org's created_at" do
expected_date = DateTime.new(2018,05,28,0,0,0)
diff --git a/spec/requests/stat_created_plans_by_template_controller_spec.rb b/spec/requests/stat_created_plans_by_template_controller_spec.rb
new file mode 100644
index 0000000..e8d9ce4
--- /dev/null
+++ b/spec/requests/stat_created_plans_by_template_controller_spec.rb
@@ -0,0 +1,104 @@
+require 'rails_helper'
+
+RSpec.describe '/stat_created_plan_by_template', type: :request do
+ def parsed_response
+ JSON.parse(response.body, symbolize_names: true)
+ end
+
+ describe '#index' do
+ let(:path) { '/stat_created_plans_by_template' }
+
+ it 'redirects when non-authorized user' do
+ get path
+
+ expect(response).to have_http_status(:redirect)
+ end
+
+ context 'when org_admin user' do
+ let(:org) { create(:org) }
+ let(:org_admin) { create(:user, :org_admin, org: org) }
+ before(:each) do
+ sign_in(org_admin)
+ end
+
+ it 'returns 200 status' do
+ get path
+
+ expect(response.content_type).to eq('application/json')
+ expect(response).to have_http_status(:ok)
+ end
+
+ context 'when there are no stats' do
+ it 'returns empty' do
+ get path
+
+ expect(parsed_response).to eq([])
+ end
+
+ it 'returns empty csv file' do
+ get "#{path}.csv"
+
+ expect(response.content_type).to eq('text/csv')
+ expect(response.body).to eq('')
+ end
+ end
+
+ context "when there are stats" do
+ before do
+ create(:stat_created_plan, date: '2018-07-31', count: 5, org: org, details: { by_template: [{ name: 'Template1', count: 3 }, { name: 'Template2', count: 2 }]})
+ create(:stat_created_plan, date: '2018-08-31', count: 10, org: org, details: { by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]})
+ create(:stat_created_plan, date: '2018-09-30', count: 10, org: org, details: { by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]})
+ end
+
+ it "returns all stats" do
+ get path
+
+ expect(parsed_response).to eq([
+ { date: '2018-09-30', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ { date: '2018-08-31', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ { date: '2018-07-31', count: 5, by_template: [{ name: 'Template1', count: 3 }, { name: 'Template2', count: 2 }]}
+ ])
+ end
+
+ it 'returns all stats csv formatted' do
+ get "#{path}.csv"
+
+ expected_csv = <<~HERE
+ Date,Template1,Template2,Count
+ 2018-09-30,6,4,10
+ 2018-08-31,6,4,10
+ 2018-07-31,3,2,5
+ HERE
+ expect(response.body).to eq(expected_csv)
+ end
+
+ it 'returns stats for start_date and end_date passed' do
+ get path, { start_date: '2018-08-31', end_date: '2018-09-30' }
+
+ expect(parsed_response).to eq([
+ { date: '2018-09-30', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ { date: '2018-08-31', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]}
+ ])
+ end
+
+ it 'returns stats from start_date passed' do
+ get path, { start_date: '2018-08-31' }
+
+ expect(parsed_response).to eq([
+ { date: '2018-09-30', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ { date: '2018-08-31', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ ])
+ end
+
+ it 'returns stats until end_date passed' do
+ get path, { end_date: '2018-08-31' }
+
+ expect(parsed_response).to eq([
+ { date: '2018-08-31', count: 10, by_template: [{ name: 'Template1', count: 6 }, { name: 'Template2', count: 4 }]},
+ { date: '2018-07-31', count: 5, by_template: [{ name: 'Template1', count: 3 }, { name: 'Template2', count: 2 }]}
+ ])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/org/create_created_plan_service_spec.rb b/spec/services/org/create_created_plan_service_spec.rb
index 2f83bae..19a2199 100644
--- a/spec/services/org/create_created_plan_service_spec.rb
+++ b/spec/services/org/create_created_plan_service_spec.rb
@@ -7,6 +7,9 @@
let(:template) do
FactoryBot.create(:template, org: org)
end
+ let(:template2) do
+ FactoryBot.create(:template, org: org)
+ end
let(:user1) do
FactoryBot.create(:user, org: org)
end
@@ -15,56 +18,153 @@
end
let(:creator) { Role.access_values_for(:creator).first }
let(:administrator) { Role.access_values_for(:administrator).first }
+ before(:each) do
+ plan = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,04,01))
+ plan2 = FactoryBot.create(:plan, template: template2, created_at: DateTime.new(2018,04,03))
+ plan3 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,05,02))
+ plan4 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,06,02))
+ plan5 = FactoryBot.create(:plan, template: template2, created_at: DateTime.new(2018,06,03))
+ FactoryBot.create(:role, plan: plan, user: user1, access: creator)
+ FactoryBot.create(:role, plan: plan, user: user2, access: administrator)
+ FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
+ FactoryBot.create(:role, plan: plan3, user: user1, access: creator)
+ FactoryBot.create(:role, plan: plan4, user: user2, access: administrator)
+ FactoryBot.create(:role, plan: plan5, user: user2, access: administrator)
+ end
+
+ def find_by_dates(dates: , org_id:)
+ dates.map do |date|
+ StatCreatedPlan.find_by(date: date, org_id: org_id)
+ end
+ end
describe '.call' do
context 'when org is passed' do
- it "generates monthly aggregates since org's creation" do
- plan = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,04,01))
- plan2 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,04,03))
- plan3 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,05,02))
- plan4 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,06,02))
- plan5 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,06,03))
- FactoryBot.create(:role, plan: plan, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan, user: user2, access: administrator)
- FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan3, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan4, user: user2, access: administrator)
- FactoryBot.create(:role, plan: plan5, user: user2, access: administrator)
+ it "generates monthly counts since org's creation" do
+ described_class.call(org)
+
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
+ counts = [april, may, june, july].map(&:count)
+ expect(counts).to eq([2,1,2,0])
+ end
+
+ it "generates monthly counts by template since org's creation" do
+ described_class.call(org)
+
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
+ expect(april.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(may.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(june.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(july.details).to eq(
+ {
+ 'by_template' => []
+ }
+ )
+ end
+
+ it "monthly records are either created or updated" do
+ described_class.call(org)
+
+ april = StatCreatedPlan.where(date: '2018-04-30', org: org)
+ expect(april).to have(1).items
+ expect(april.first.count).to eq(2)
+
+ new_plan = FactoryBot.create(:plan, template: template2, created_at: DateTime.new(2018,04,03))
+ FactoryBot.create(:role, plan: new_plan, user: user1, access: creator)
described_class.call(org)
- april = StatCreatedPlan.find_by(date: '2018-04-30', org_id: org.id).count
- may = StatCreatedPlan.find_by(date: '2018-05-31', org_id: org.id).count
- june = StatCreatedPlan.find_by(date: '2018-06-30', org_id: org.id).count
- july = StatCreatedPlan.find_by(date: '2018-07-31', org_id: org.id).count
-
- expect([april, may, june, july]).to eq([2,1,2,0])
+ april = StatCreatedPlan.where(date: '2018-04-30', org: org)
+ expect(april).to have(1).items
+ expect(april.first.count).to eq(3)
end
end
context 'when no org is passed' do
- it 'generates monthly aggregates for each org since their creation' do
+ it 'generates monthly counts for each org since their creation' do
Org.stubs(:all).returns([org])
- plan = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,04,01))
- plan2 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,04,03))
- plan3 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,05,02))
- plan4 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,06,02))
- plan5 = FactoryBot.create(:plan, template: template, created_at: DateTime.new(2018,06,03))
- FactoryBot.create(:role, plan: plan, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan, user: user2, access: administrator)
- FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan3, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan4, user: user2, access: administrator)
- FactoryBot.create(:role, plan: plan5, user: user2, access: administrator)
described_class.call
- april = StatCreatedPlan.find_by(date: '2018-04-30', org_id: org.id).count
- may = StatCreatedPlan.find_by(date: '2018-05-31', org_id: org.id).count
- june = StatCreatedPlan.find_by(date: '2018-06-30', org_id: org.id).count
- july = StatCreatedPlan.find_by(date: '2018-07-31', org_id: org.id).count
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
- expect([april, may, june, july]).to eq([2,1,2,0])
+ counts = [april, may, june, july].map(&:count)
+ expect(counts).to eq([2,1,2,0])
+ end
+
+ it 'generates montly counts by template for each org since their creation' do
+ Org.stubs(:all).returns([org])
+
+ described_class.call
+
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
+ expect(april.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(may.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(june.details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 1 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ expect(july.details).to eq(
+ {
+ 'by_template' => []
+ }
+ )
+ end
+
+ it "monthly records are either created or updated" do
+ Org.stubs(:all).returns([org])
+
+ described_class.call
+
+ april = StatCreatedPlan.where(date: '2018-04-30', org: org)
+ expect(april).to have(1).items
+ expect(april.first.count).to eq(2)
+
+ new_plan = FactoryBot.create(:plan, template: template2, created_at: DateTime.new(2018,04,03))
+ FactoryBot.create(:role, plan: new_plan, user: user1, access: creator)
+
+ described_class.call
+
+ april = StatCreatedPlan.where(date: '2018-04-30', org: org)
+ expect(april).to have(1).items
+ expect(april.first.count).to eq(3)
end
end
end
diff --git a/spec/services/org/create_joined_user_service_spec.rb b/spec/services/org/create_joined_user_service_spec.rb
index 5f6611a..3faab7c 100644
--- a/spec/services/org/create_joined_user_service_spec.rb
+++ b/spec/services/org/create_joined_user_service_spec.rb
@@ -4,37 +4,65 @@
let(:org) do
FactoryBot.create(:org, created_at: DateTime.new(2018,04,01))
end
+ before(:each) do
+ FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,03,0,0,0))
+ FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,04,0,0,0))
+ FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,05,03,0,0,0))
+ FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,03,0,0,0))
+ FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,04,0,0,0))
+ end
+
+ def find_by_dates(dates: , org_id:)
+ dates.map do |date|
+ StatJoinedUser.find_by(date: date, org_id: org_id)
+ end
+ end
describe '.call' do
context 'when an org is passed' do
it "generates monthly aggregates since org's creation" do
- april = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,03,0,0,0)), FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,04,0,0,0))]
- may = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,05,03,0,0,0))]
- june = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,03,0,0,0)), FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,04,0,0,0))]
+ described_class.call(org)
+
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
+ counts = [april, may, june, july].map(&:count)
+ expect(counts).to eq([2,1,2,0])
+ end
+
+ it 'monthly records are either created or updated' do
+ described_class.call(org)
+
+ april_updated = FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,05,0,0,0))
described_class.call(org)
- april = StatJoinedUser.find_by(date: '2018-04-30', org_id: org.id).count
- may = StatJoinedUser.find_by(date: '2018-05-31', org_id: org.id).count
- june = StatJoinedUser.find_by(date: '2018-06-30', org_id: org.id).count
- july = StatJoinedUser.find_by(date: '2018-07-31', org_id: org.id).count
- expect([april, may, june, july]).to eq([2,1,2,0])
+ stat_joined_user = StatJoinedUser.where(date: '2018-04-30', org_id: org.id)
+ expect(stat_joined_user).to have(1).items
+ expect(stat_joined_user.first.count).to eq(3)
end
end
context 'when no org is passed' do
it "generates monthly aggregates for each org since their creation" do
- Org.expects(:all).returns([org])
- april = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,03,0,0,0)), FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,04,0,0,0))]
- may = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,05,03,0,0,0))]
- june = [FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,03,0,0,0)), FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,06,04,0,0,0))]
+ Org.stubs(:all).returns([org])
described_class.call
- april = StatJoinedUser.find_by(date: '2018-04-30', org_id: org.id).count
- may = StatJoinedUser.find_by(date: '2018-05-31', org_id: org.id).count
- june = StatJoinedUser.find_by(date: '2018-06-30', org_id: org.id).count
- july = StatJoinedUser.find_by(date: '2018-07-31', org_id: org.id).count
- expect([april, may, june, july]).to eq([2,1,2,0])
+ april, may, june, july = find_by_dates(dates: ['2018-04-30', '2018-05-31', '2018-06-30', '2018-07-31'], org_id: org.id)
+ counts = [april, may, june, july].map(&:count)
+ expect(counts).to eq([2,1,2,0])
+ end
+
+ it 'monthly records are either created or updated' do
+ Org.stubs(:all).returns([org])
+
+ described_class.call
+
+ april_updated = FactoryBot.create(:user, org: org, created_at: DateTime.new(2018,04,05,0,0,0))
+
+ described_class.call
+
+ stat_joined_user = StatJoinedUser.where(date: '2018-04-30', org_id: org.id)
+ expect(stat_joined_user).to have(1).items
+ expect(stat_joined_user.first.count).to eq(3)
end
end
end
diff --git a/spec/services/org/create_last_month_created_plan_service_spec.rb b/spec/services/org/create_last_month_created_plan_service_spec.rb
index f899680..59a7d68 100644
--- a/spec/services/org/create_last_month_created_plan_service_spec.rb
+++ b/spec/services/org/create_last_month_created_plan_service_spec.rb
@@ -4,6 +4,12 @@
let(:org) do
FactoryBot.create(:org, created_at: DateTime.new(2018,04,01))
end
+ let(:template) do
+ FactoryBot.create(:template, org: org)
+ end
+ let(:template2) do
+ FactoryBot.create(:template, org: org)
+ end
let(:user1) do
FactoryBot.create(:user, org: org)
end
@@ -12,40 +18,100 @@
end
let(:creator) { Role.access_values_for(:creator).first }
let(:administrator) { Role.access_values_for(:administrator).first }
+ before(:each) do
+ plan = FactoryBot.create(:plan, template: template, created_at: Date.today.last_month)
+ plan2 = FactoryBot.create(:plan, template: template, created_at: Date.today.last_month)
+ plan3 = FactoryBot.create(:plan, template: template2, created_at: Date.today.last_month)
+ FactoryBot.create(:role, plan: plan, user: user1, access: creator)
+ FactoryBot.create(:role, plan: plan, user: user1, access: administrator)
+ FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
+ FactoryBot.create(:role, plan: plan3, user: user2, access: creator)
+ end
describe '.call' do
context 'when org is passed' do
- it "returns aggregates from today's last month" do
- plan = FactoryBot.create(:plan, created_at: Date.today.last_month)
- plan2 = FactoryBot.create(:plan, created_at: Date.today.last_month)
- plan3 = FactoryBot.create(:plan, created_at: Date.today.last_month)
- FactoryBot.create(:role, plan: plan, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan, user: user1, access: administrator)
- FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan3, user: user2, access: creator)
+ it "generates counts from today's last month" do
+ described_class.call(org)
+
+ last_month_count = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
+ expect(last_month_count).to eq(3)
+ end
+
+ it "generates counts by template from today's last month" do
+ described_class.call(org)
+
+ last_month_details = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).details
+ expect(last_month_details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 2 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ end
+
+ it "monthly records are either created or updated" do
+ described_class.call(org)
+
+ last_month = StatCreatedPlan.where(date: Date.today.last_month.end_of_month, org_id: org.id)
+ expect(last_month).to have(1).items
+ expect(last_month.first.count).to eq(3)
+
+ new_plan = FactoryBot.create(:plan, template: template2, created_at: Date.today.last_month.end_of_month)
+ FactoryBot.create(:role, plan: new_plan, user: user1, access: creator)
described_class.call(org)
- last_month = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
- expect(last_month).to eq(3)
+ last_month = StatCreatedPlan.where(date: Date.today.last_month.end_of_month, org_id: org.id)
+ expect(last_month).to have(1).items
+ expect(last_month.first.count).to eq(4)
end
end
context 'when no org is passed' do
- it "returns aggregates from today's last month" do
+ it "generates counts from today's last month" do
Org.expects(:all).returns([org])
- plan = FactoryBot.create(:plan, created_at: Date.today.last_month)
- plan2 = FactoryBot.create(:plan, created_at: Date.today.last_month)
- plan3 = FactoryBot.create(:plan, created_at: Date.today.last_month)
- FactoryBot.create(:role, plan: plan, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan, user: user1, access: administrator)
- FactoryBot.create(:role, plan: plan2, user: user1, access: creator)
- FactoryBot.create(:role, plan: plan3, user: user2, access: creator)
described_class.call
- last_month = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
- expect(last_month).to eq(3)
+ last_month_count = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
+ expect(last_month_count).to eq(3)
+ end
+
+ it "generates counts by template from today's last month" do
+ Org.expects(:all).returns([org])
+
+ described_class.call
+
+ last_month_details = StatCreatedPlan.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).details
+ expect(last_month_details).to eq(
+ {
+ 'by_template' => [
+ { 'name' => template.title, 'count' => 2 },
+ { 'name' => template2.title, 'count' => 1 },
+ ]
+ }
+ )
+ end
+
+ it "monthly records are either created or updated" do
+ Org.stubs(:all).returns([org])
+
+ described_class.call
+
+ last_month = StatCreatedPlan.where(date: Date.today.last_month.end_of_month, org: org)
+ expect(last_month).to have(1).items
+ expect(last_month.first.count).to eq(3)
+
+ new_plan = FactoryBot.create(:plan, template: template2, created_at: Date.today.last_month.end_of_month)
+ FactoryBot.create(:role, plan: new_plan, user: user1, access: creator)
+
+ described_class.call
+
+ last_month = StatCreatedPlan.where(date: Date.today.last_month.end_of_month, org: org)
+ expect(last_month).to have(1).items
+ expect(last_month.first.count).to eq(4)
end
end
end
diff --git a/spec/services/org/create_last_month_joined_user_service_spec.rb b/spec/services/org/create_last_month_joined_user_service_spec.rb
index 126c650..3c8955a 100644
--- a/spec/services/org/create_last_month_joined_user_service_spec.rb
+++ b/spec/services/org/create_last_month_joined_user_service_spec.rb
@@ -4,32 +4,56 @@
let(:org) do
FactoryBot.create(:org, created_at: DateTime.new(2018,04,01))
end
+ before(:each) do
+ 5.times do
+ FactoryBot.create(:user, org: org, created_at: Date.today.last_month)
+ end
+ end
describe '.call' do
context 'when an org is passed' do
- it "generates aggregates from today's last month" do
- 5.times do
- FactoryBot.create(:user, org: org, created_at: Date.today.last_month)
- end
-
+ it "generates counts from today's last month" do
described_class.call(org)
last_month = StatJoinedUser.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
expect(last_month).to eq(5)
end
+
+ it "monthly records are either created or updated" do
+ described_class.call(org)
+
+ FactoryBot.create(:user, org: org, created_at: Date.today.last_month)
+
+ described_class.call(org)
+
+ last_month_updated = StatJoinedUser.where(date: Date.today.last_month.end_of_month, org: org.id)
+ expect(last_month_updated).to have(1).items
+ expect(last_month_updated.first.count).to eq(6)
+ end
end
context 'when no org is passed' do
- it "generates aggregates from today's last month" do
- Org.expects(:all).returns([org])
- 5.times do
- FactoryBot.create(:user, org: org, created_at: Date.today.last_month)
- end
+ it "generates counts from today's last month" do
+ Org.stubs(:all).returns([org])
described_class.call
last_month = StatJoinedUser.find_by(date: Date.today.last_month.end_of_month, org_id: org.id).count
expect(last_month).to eq(5)
end
+
+ it "generates counts by template from today's last month" do
+ Org.stubs(:all).returns([org])
+
+ described_class.call(org)
+
+ FactoryBot.create(:user, org: org, created_at: Date.today.last_month)
+
+ described_class.call(org)
+
+ last_month_updated = StatJoinedUser.where(date: Date.today.last_month.end_of_month, org: org.id)
+ expect(last_month_updated).to have(1).items
+ expect(last_month_updated.first.count).to eq(6)
+ end
end
end
end