Browse Source

Merge remote-tracking branch 'origin/main' into cldc-1118-export

pull/587/head
Stéphane Meny 3 years ago
parent
commit
fb20db3db2
No known key found for this signature in database
GPG Key ID: 9D0AFEA988527923
  1. 5
      app/controllers/case_logs_controller.rb
  2. 6
      app/frontend/styles/_filter-layout.scss
  3. 15
      app/frontend/styles/_filter.scss
  4. 8
      app/frontend/styles/application.scss
  5. 8
      app/helpers/filters_helper.rb
  6. 31
      app/models/case_log.rb
  7. 2
      app/models/organisation.rb
  8. 10
      app/models/user.rb
  9. 35
      app/services/exports/case_log_export_service.rb
  10. 23
      app/views/case_logs/_log_filters.erb
  11. 20
      app/views/filters/_radio_filter.html.erb
  12. 7
      app/views/filters/_select_filter.html.erb
  13. 18
      config/forms/2022_2023.json
  14. 5
      db/migrate/20220516111514_add_started_at.rb
  15. 3
      db/schema.rb
  16. 30
      spec/helpers/filters_helper_spec.rb
  17. 25
      spec/models/case_log_spec.rb
  18. 8
      spec/models/user_spec.rb
  19. 148
      spec/models/validations/tenancy_validations_spec.rb
  20. 50
      spec/requests/case_logs_controller_spec.rb
  21. 44
      spec/services/exports/case_log_export_service_spec.rb

5
app/controllers/case_logs_controller.rb

@ -126,7 +126,7 @@ private
if session[:case_logs_filters].present? if session[:case_logs_filters].present?
filters = JSON.parse(session[:case_logs_filters]) filters = JSON.parse(session[:case_logs_filters])
filters.each do |category, values| filters.each do |category, values|
next if values.reject(&:empty?).blank? next if Array(values).reject(&:empty?).blank?
query = query.public_send("filter_by_#{category}", values, current_user) query = query.public_send("filter_by_#{category}", values, current_user)
end end
@ -137,8 +137,7 @@ private
def set_session_filters def set_session_filters
new_filters = session[:case_logs_filters].present? ? JSON.parse(session[:case_logs_filters]) : {} new_filters = session[:case_logs_filters].present? ? JSON.parse(session[:case_logs_filters]) : {}
%i[status years].each { |filter| new_filters[filter] = params[filter] if params[filter].present? } current_user.case_logs_filters.each { |filter| new_filters[filter] = params[filter] if params[filter].present? }
new_filters[:user] = [params[:user]] if params[:user].present?
session[:case_logs_filters] = new_filters.to_json session[:case_logs_filters] = new_filters.to_json
end end

6
app/frontend/styles/_filter-layout.scss

@ -3,7 +3,7 @@
} }
.app-filter-layout__filter { .app-filter-layout__filter {
@include govuk-media-query(desktop) { @include govuk-media-query(wide) {
float: left; float: left;
min-width: govuk-grid-width("one-quarter"); min-width: govuk-grid-width("one-quarter");
} }
@ -12,7 +12,7 @@
.js-enabled .app-filter-layout__filter { .js-enabled .app-filter-layout__filter {
outline: 0 none; outline: 0 none;
@include govuk-media-query($until: desktop) { @include govuk-media-query($until: wide) {
background-color: govuk-colour("light-grey"); background-color: govuk-colour("light-grey");
bottom: govuk-spacing(1); bottom: govuk-spacing(1);
border: 1px solid govuk-colour("mid-grey"); border: 1px solid govuk-colour("mid-grey");
@ -32,7 +32,7 @@
} }
.app-filter-layout__content { .app-filter-layout__content {
@include govuk-media-query(desktop) { @include govuk-media-query(wide) {
float: right; float: right;
max-width: calc(#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)}); max-width: calc(#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)});
width: 100%; width: 100%;

15
app/frontend/styles/_filter.scss

@ -98,4 +98,19 @@
background-color: govuk-colour("white"); background-color: govuk-colour("white");
} }
} }
.autocomplete__input {
@include govuk-font(16);
background-color: govuk-colour("white");
}
.autocomplete__wrapper {
@include govuk-media-query(wide) {
max-width: 20ex;
}
}
.autocomplete__option {
@include govuk-font(16);
}
} }

8
app/frontend/styles/application.scss

@ -11,6 +11,14 @@ $govuk-image-url-function: frontend-image-url;
$govuk-global-styles: true; $govuk-global-styles: true;
$govuk-new-link-styles: true; $govuk-new-link-styles: true;
// Add additional breakpoint named `wide`
$govuk-breakpoints: (
mobile: 320px,
tablet: 641px,
desktop: 769px,
wide: 921px,
);
@import "govuk-frontend-styles"; @import "govuk-frontend-styles";
@import "govuk-prototype-styles"; @import "govuk-prototype-styles";

8
app/helpers/filters_helper.rb

@ -4,6 +4,8 @@ module FiltersHelper
selected_filters = JSON.parse(session[:case_logs_filters]) selected_filters = JSON.parse(session[:case_logs_filters])
return true if selected_filters.blank? && filter == "user" && value == :all return true if selected_filters.blank? && filter == "user" && value == :all
return true if selected_filters.blank? && filter == "organisation_select" && value == :all
return true if selected_filters["organisation"].present? && filter == "organisation_select" && value == :specific_org
return false if selected_filters[filter].blank? return false if selected_filters[filter].blank?
selected_filters[filter].include?(value.to_s) selected_filters[filter].include?(value.to_s)
@ -14,4 +16,10 @@ module FiltersHelper
CaseLog.statuses.keys.map { |status| statuses[status] = status.humanize } CaseLog.statuses.keys.map { |status| statuses[status] = status.humanize }
statuses statuses
end end
def selected_option(filter)
return false unless session[:case_logs_filters]
JSON.parse(session[:case_logs_filters])[filter]
end
end end

31
app/models/case_log.rb

@ -34,7 +34,7 @@ class CaseLog < ApplicationRecord
belongs_to :managing_organisation, class_name: "Organisation" belongs_to :managing_organisation, class_name: "Organisation"
belongs_to :created_by, class_name: "User" belongs_to :created_by, class_name: "User"
scope :for_organisation, ->(org) { where(owning_organisation: org).or(where(managing_organisation: org)) } scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org).or(where(managing_organisation: org)) }
scope :filter_by_status, ->(status, _user = nil) { where status: } scope :filter_by_status, ->(status, _user = nil) { where status: }
scope :filter_by_years, lambda { |years, _user = nil| scope :filter_by_years, lambda { |years, _user = nil|
first_year = years.shift first_year = years.shift
@ -191,9 +191,20 @@ class CaseLog < ApplicationRecord
tshortfall_known == 1 tshortfall_known == 1
end end
def is_fixed_term_tenancy?
[4, 6].include?(tenancy)
end
def is_secure_tenancy? def is_secure_tenancy?
return unless collection_start_year
# 1: Secure (including flexible) # 1: Secure (including flexible)
tenancy == 1 if collection_start_year < 2022
tenancy == 1
else
# 6: Secure - fixed term, 7: Secure - lifetime
[6, 7].include?(tenancy)
end
end end
def is_assured_shorthold_tenancy? def is_assured_shorthold_tenancy?
@ -461,9 +472,19 @@ private
end end
def dynamically_not_required def dynamically_not_required
previous_la_known_field = postcode_known? ? %w[previous_la_known] : [] not_required = []
tshortfall_field = tshortfall_unknown? ? %w[tshortfall] : [] not_required << "previous_la_known" if postcode_known?
previous_la_known_field + tshortfall_field not_required << "tshortfall" if tshortfall_unknown?
not_required << "tenancylength" if tenancylength_optional?
not_required
end
def tenancylength_optional?
return false unless collection_start_year
return true if collection_start_year < 2022
collection_start_year >= 2022 && !is_fixed_term_tenancy?
end end
def set_derived_fields! def set_derived_fields!

2
app/models/organisation.rb

@ -18,7 +18,7 @@ class Organisation < ApplicationRecord
validates :provider_type, presence: true validates :provider_type, presence: true
def case_logs def case_logs
CaseLog.for_organisation(self) CaseLog.filter_by_organisation(self)
end end
def completed_case_logs def completed_case_logs

10
app/models/user.rb

@ -36,7 +36,7 @@ class User < ApplicationRecord
if support? if support?
CaseLog.all CaseLog.all
else else
CaseLog.for_organisation(organisation) CaseLog.filter_by_organisation(organisation)
end end
end end
@ -88,4 +88,12 @@ class User < ApplicationRecord
ROLES.except(:support) ROLES.except(:support)
end end
def case_logs_filters
if support?
%i[status years user organisation]
else
%i[status years user]
end
end
end end

35
app/services/exports/case_log_export_service.rb

@ -15,15 +15,12 @@ module Exports
end end
def export_case_logs def export_case_logs
# Case log data is already ordered by startdate current_time = Time.zone.now
case_logs = retrieve_case_logs case_logs = retrieve_case_logs(current_time)
daily_run_number = get_next_run_number export = build_export_run(current_time)
write_master_manifest(daily_run_number) write_master_manifest(export.daily_run_number)
write_export_archive(case_logs) write_export_archive(case_logs)
export = LogsExport.new(daily_run_number:)
export.save! export.save!
export
end end
def is_omitted_field?(field_name) def is_omitted_field?(field_name)
@ -34,14 +31,15 @@ module Exports
private private
def get_next_run_number def build_export_run(current_time)
today = Time.zone.today today = Time.zone.today
last_daily_run_number = LogsExport.where(created_at: today.beginning_of_day..today.end_of_day).maximum(:daily_run_number) last_daily_run_number = LogsExport.where(created_at: today.beginning_of_day..today.end_of_day).maximum(:daily_run_number)
if last_daily_run_number.nil? last_daily_run_number = 0 if last_daily_run_number.nil?
1
else export = LogsExport.new
last_daily_run_number + 1 export.daily_run_number = last_daily_run_number + 1
end export.started_at = current_time
export
end end
def write_master_manifest(daily_run_number) def write_master_manifest(daily_run_number)
@ -86,8 +84,15 @@ module Exports
end end
end end
def retrieve_case_logs def retrieve_case_logs(current_time)
CaseLog.all recent_export = LogsExport.order("started_at").last
if recent_export
params = { from: recent_export.started_at, to: current_time }
CaseLog.where("updated_at >= :from and updated_at <= :to", params)
else
params = { to: current_time }
CaseLog.where("updated_at <= :to", params)
end
end end
def build_manifest_csv_io def build_manifest_csv_io

23
app/views/case_logs/_log_filters.erb

@ -6,12 +6,31 @@
<div class="app-filter__content"> <div class="app-filter__content">
<%= form_with url: "/logs", html: { method: :get } do |f| %> <%= form_with url: "/logs", html: { method: :get } do |f| %>
<% years = {"2021": "2021/22", "2022": "2022/23"} %> <% years = {"2021": "2021/22", "2022": "2022/23"} %>
<% all_or_yours = {"all": "All", "yours": "Yours"} %> <% all_or_yours = {"all": { label: "All" }, "yours": { label: "Yours" } } %>
<%= render partial: "filters/checkbox_filter", locals: { f: f, options: years, label: "Collection year", category: "years" } %> <%= render partial: "filters/checkbox_filter", locals: { f: f, options: years, label: "Collection year", category: "years" } %>
<%= render partial: "filters/checkbox_filter", locals: { f: f, options: status_filters, label: "Status", category: "status" } %> <%= render partial: "filters/checkbox_filter", locals: { f: f, options: status_filters, label: "Status", category: "status" } %>
<%= render partial: "filters/radio_filter", locals: { f: f, options: all_or_yours, label: "Logs", category: "user", } %> <%= render partial: "filters/radio_filter", locals: { f: f, options: all_or_yours, label: "Logs", category: "user", } %>
<% if @current_user.support? %>
<%= render partial: "filters/radio_filter", locals: {
f: f,
options: {
"all": { label: "All" },
"specific_org": {
label: "Specific organisation",
conditional_filter: {
type: "select",
label: "Organisation",
category: "organisation",
options: [OpenStruct.new(id: "", name: "Select an option")] + Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) }
}
}
},
label: "Organisation",
category: "organisation_select"
} %>
<% end %>
<%= f.govuk_submit "Apply filters", class: "govuk-!-margin-bottom-0" %> <%= f.govuk_submit "Apply filters", class: "govuk-!-margin-bottom-0" %>
<% end %> <% end %>
</div> </div>
</div> </div>
</div> </div>

20
app/views/filters/_radio_filter.html.erb

@ -1,8 +1,18 @@
<%= f.govuk_radio_buttons_fieldset category.to_sym, legend: { text: label, size: "s" }, small: true, form_group: { classes: "app-filter__group" } do %> <%= f.govuk_radio_buttons_fieldset category.to_sym, legend: { text: label, size: "s" }, small: true, form_group: { classes: "app-filter__group" } do %>
<% options.map do |key, option| %> <% options.map do |key, option| %>
<%= f.govuk_radio_button category, key.to_s, <%= f.govuk_radio_button category, key.to_s,
label: { text: option }, label: { text: option[:label] },
checked: filter_selected?(category, key), checked: filter_selected?(category, key),
size: "s" %> size: "s" do %>
<% if option[:conditional_filter] %>
<%= render partial: "filters/#{option[:conditional_filter][:type]}_filter", locals: {
f:,
collection: option[:conditional_filter][:options],
category: option[:conditional_filter][:category],
label: option[:conditional_filter][:label],
secondary: true,
} %>
<% end %>
<% end %> <% end %>
<% end %>
<% end %> <% end %>

7
app/views/filters/_select_filter.html.erb

@ -0,0 +1,7 @@
<%= f.govuk_collection_select category.to_sym,
collection,
:id,
:name,
label: { hidden: secondary },
options: { disabled: [""], selected: selected_option(category) },
"data-controller": "accessible-autocomplete" %>

18
config/forms/2022_2023.json

@ -951,7 +951,7 @@
"joint": { "joint": {
"check_answer_label": "Is this a joint tenancy?", "check_answer_label": "Is this a joint tenancy?",
"header": "Is this a joint tenancy?", "header": "Is this a joint tenancy?",
"hint_text": "For example, 27 3 2021.", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "1": {
@ -959,6 +959,9 @@
}, },
"2": { "2": {
"value": "No" "value": "No"
},
"3": {
"value": "Don’t know"
} }
} }
} }
@ -994,7 +997,7 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "4": {
"value": "Assured Shorthold Tenancy (AST) - Fixed term" "value": "Assured Shorthold Tenancy (AST) - Fixed term"
}, },
"6": { "6": {
@ -1041,7 +1044,7 @@
"hint_text": "This is also known as an ‘introductory period’.", "hint_text": "This is also known as an ‘introductory period’.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "4": {
"value": "Assured Shorthold Tenancy (AST) - Fixed term" "value": "Assured Shorthold Tenancy (AST) - Fixed term"
}, },
"6": { "6": {
@ -1095,10 +1098,13 @@
}, },
"depends_on": [ "depends_on": [
{ {
"tenancy": 1 "tenancy": 4
}, },
{ {
"tenancy": 6 "tenancy": 6
},
{
"tenancy": 3
} }
] ]
}, },
@ -6297,7 +6303,7 @@
"label": true, "label": true,
"i18n_template": "la" "i18n_template": "la"
}, },
{ {
"key": "soft_min_for_period", "key": "soft_min_for_period",
"label": false, "label": false,
"i18n_template": "soft_min_for_period" "i18n_template": "soft_min_for_period"
@ -6336,7 +6342,7 @@
"label": true, "label": true,
"i18n_template": "la" "i18n_template": "la"
}, },
{ {
"key": "soft_max_for_period", "key": "soft_max_for_period",
"label": false, "label": false,
"i18n_template": "soft_max_for_period" "i18n_template": "soft_max_for_period"

5
db/migrate/20220516111514_add_started_at.rb

@ -0,0 +1,5 @@
class AddStartedAt < ActiveRecord::Migration[7.0]
def change
add_column :logs_exports, :started_at, :datetime
end
end

3
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2022_05_13_123456) do ActiveRecord::Schema[7.0].define(version: 2022_05_16_111514) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -261,6 +261,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_05_13_123456) do
create_table "logs_exports", force: :cascade do |t| create_table "logs_exports", force: :cascade do |t|
t.integer "daily_run_number" t.integer "daily_run_number"
t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" } t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }
t.datetime "started_at"
end end
create_table "organisation_las", force: :cascade do |t| create_table "organisation_las", force: :cascade do |t|

30
spec/helpers/filters_helper_spec.rb

@ -16,8 +16,8 @@ RSpec.describe FiltersHelper do
context "when looking at the all value" do context "when looking at the all value" do
it "returns true if no filters have been set yet" do it "returns true if no filters have been set yet" do
expect(filter_selected?("user", :all)).to be_truthy expect(filter_selected?("user", :all)).to be true
expect(filter_selected?("user", :yours)).to be_falsey expect(filter_selected?("user", :yours)).to be false
end end
end end
end end
@ -28,11 +28,33 @@ RSpec.describe FiltersHelper do
end end
it "returns false for non selected filters" do it "returns false for non selected filters" do
expect(filter_selected?("status", "completed")).to be_falsey expect(filter_selected?("status", "completed")).to be false
end end
it "returns true for selected filter" do it "returns true for selected filter" do
expect(filter_selected?("status", "in_progress")).to be_truthy expect(filter_selected?("status", "in_progress")).to be true
end
end
context "when support user is using the organisation filter" do
before do
session[:case_logs_filters] = { "organisation": "1" }.to_json
end
it "returns true for the parent organisation_select filter" do
expect(filter_selected?("organisation_select", :specific_org)).to be true
expect(filter_selected?("organisation_select", :all)).to be false
end
end
context "when support user has not set the organisation_select filter" do
before do
session[:case_logs_filters] = {}.to_json
end
it "defaults to all organisations" do
expect(filter_selected?("organisation_select", :all)).to be true
expect(filter_selected?("organisation_select", :specific_org)).to be false
end end
end end
end end

25
spec/models/case_log_spec.rb

@ -1893,6 +1893,31 @@ RSpec.describe CaseLog do
end end
end end
context "when filtering by organisation" do
let(:organisation_1) { FactoryBot.create(:organisation) }
let(:organisation_2) { FactoryBot.create(:organisation) }
let(:organisation_3) { FactoryBot.create(:organisation) }
before do
FactoryBot.create(:case_log, :in_progress, owning_organisation: organisation_1, managing_organisation: organisation_1)
FactoryBot.create(:case_log, :completed, owning_organisation: organisation_1, managing_organisation: organisation_2)
FactoryBot.create(:case_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_1)
FactoryBot.create(:case_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2)
end
it "filters by given organisation id" do
expect(described_class.filter_by_organisation([organisation_1.id]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_1.id, organisation_2.id]).count).to eq(4)
expect(described_class.filter_by_organisation([organisation_3.id]).count).to eq(0)
end
it "filters by given organisation" do
expect(described_class.filter_by_organisation([organisation_1]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_1, organisation_2]).count).to eq(4)
expect(described_class.filter_by_organisation([organisation_3]).count).to eq(0)
end
end
context "when filtering on status" do context "when filtering on status" do
it "allows filtering on a single status" do it "allows filtering on a single status" do
expect(described_class.filter_by_status(%w[in_progress]).count).to eq(2) expect(described_class.filter_by_status(%w[in_progress]).count).to eq(2)

8
spec/models/user_spec.rb

@ -97,6 +97,10 @@ RSpec.describe User, type: :model do
data_coordinator: 2, data_coordinator: 2,
}) })
end end
it "can filter case logs by user, year and status" do
expect(user.case_logs_filters).to eq(%i[status years user])
end
end end
context "when the user is a Customer Support person" do context "when the user is a Customer Support person" do
@ -119,6 +123,10 @@ RSpec.describe User, type: :model do
support: 99, support: 99,
}) })
end end
it "can filter case logs by user, year, status and organisation" do
expect(user.case_logs_filters).to eq(%i[status years user organisation])
end
end end
end end

148
spec/models/validations/tenancy_validations_spec.rb

@ -4,7 +4,7 @@ RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new } subject(:tenancy_validator) { validator_class.new }
let(:validator_class) { Class.new { include Validations::TenancyValidations } } let(:validator_class) { Class.new { include Validations::TenancyValidations } }
let(:record) { FactoryBot.create(:case_log) } let(:record) { FactoryBot.create(:case_log, startdate: Time.zone.local(2021, 5, 1)) }
describe "fixed term tenancy validations" do describe "fixed term tenancy validations" do
context "when fixed term tenancy" do context "when fixed term tenancy" do
@ -62,44 +62,134 @@ RSpec.describe Validations::TenancyValidations do
end end
end end
context "when type of tenancy is secure" do context "when the collection start year is before 2022" do
let(:expected_error) { I18n.t("validations.tenancy.length.secure") } context "when type of tenancy is secure" do
let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
before { record.tenancy = 1 } before { record.tenancy = 1 }
context "when tenancy length is greater than 1" do context "when tenancy length is greater than 1" do
it "adds an error" do it "adds an error" do
record.tenancylength = 1 record.tenancylength = 1
tenancy_validator.validate_fixed_term_tenancy(record) tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error)) expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error)) expect(record.errors["tenancy"]).to include(match(expected_error))
end
end end
end
context "when tenancy length is less than 100" do context "when tenancy length is less than 100" do
it "adds an error" do it "adds an error" do
record.tenancylength = 100 record.tenancylength = 100
tenancy_validator.validate_fixed_term_tenancy(record) tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error)) expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error)) expect(record.errors["tenancy"]).to include(match(expected_error))
end
end
context "when tenancy length is between 2-99" do
it "does not add an error" do
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end
context "when tenancy length has not been answered" do
it "does not add an error" do
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end end
end end
end
context "when tenancy length is between 2-99" do context "when the collection start year is 2022 or later" do
it "does not add an error" do let(:record) { FactoryBot.create(:case_log, startdate: Time.zone.local(2022, 5, 1)) }
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record) context "when type of tenancy is Secure - fixed term" do
expect(record.errors["tenancylength"]).to be_empty let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
expect(record.errors["tenancy"]).to be_empty
before { record.tenancy = 6 }
context "when tenancy length is greater than 1" do
it "adds an error" do
record.tenancylength = 1
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end
end
context "when tenancy length is less than 100" do
it "adds an error" do
record.tenancylength = 100
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end
end
context "when tenancy length is between 2-99" do
it "does not add an error" do
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end
context "when tenancy length has not been answered" do
it "does not add an error" do
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end end
end end
context "when tenancy length has not been answered" do context "when type of tenancy is Secure - lifetime" do
it "does not add an error" do let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record) before { record.tenancy = 7 }
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty context "when tenancy length is greater than 1" do
it "adds an error" do
record.tenancylength = 1
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end
end
context "when tenancy length is less than 100" do
it "adds an error" do
record.tenancylength = 100
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to include(match(expected_error))
expect(record.errors["tenancy"]).to include(match(expected_error))
end
end
context "when tenancy length is between 2-99" do
it "does not add an error" do
record.tenancylength = 3
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end
context "when tenancy length has not been answered" do
it "does not add an error" do
record.tenancylength = nil
tenancy_validator.validate_fixed_term_tenancy(record)
expect(record.errors["tenancylength"]).to be_empty
expect(record.errors["tenancy"]).to be_empty
end
end end
end end
end end

50
spec/requests/case_logs_controller_spec.rb

@ -186,6 +186,7 @@ RSpec.describe CaseLogsController, type: :request do
context "when filtering" do context "when filtering" do
context "with status filter" do context "with status filter" do
let(:organisation_2) { FactoryBot.create(:organisation) }
let!(:in_progress_case_log) do let!(:in_progress_case_log) do
FactoryBot.create(:case_log, :in_progress, FactoryBot.create(:case_log, :in_progress,
owning_organisation: organisation, owning_organisation: organisation,
@ -193,7 +194,7 @@ RSpec.describe CaseLogsController, type: :request do
end end
let!(:completed_case_log) do let!(:completed_case_log) do
FactoryBot.create(:case_log, :completed, FactoryBot.create(:case_log, :completed,
owning_organisation: organisation, owning_organisation: organisation_2,
managing_organisation: organisation) managing_organisation: organisation)
end end
@ -209,6 +210,12 @@ RSpec.describe CaseLogsController, type: :request do
expect(page).not_to have_link(completed_case_log.id.to_s) expect(page).not_to have_link(completed_case_log.id.to_s)
end end
it "filters on organisation" do
get "/logs?organisation[]=#{organisation_2.id}", headers: headers, params: {}
expect(page).to have_link(completed_case_log.id.to_s)
expect(page).not_to have_link(in_progress_case_log.id.to_s)
end
it "does not reset the filters" do it "does not reset the filters" do
get "/logs?status[]=in_progress", headers: headers, params: {} get "/logs?status[]=in_progress", headers: headers, params: {}
expect(page).to have_link(in_progress_case_log.id.to_s) expect(page).to have_link(in_progress_case_log.id.to_s)
@ -232,6 +239,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation, owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1), mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1), startdate: Time.zone.local(2022, 12, 1),
tenancy: 6,
managing_organisation: organisation) managing_organisation: organisation)
end end
@ -260,6 +268,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation, owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1), mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1), startdate: Time.zone.local(2022, 12, 1),
tenancy: 6,
managing_organisation: organisation) managing_organisation: organisation)
end end
let!(:case_log_2022_in_progress) do let!(:case_log_2022_in_progress) do
@ -267,6 +276,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation, owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1), mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1), startdate: Time.zone.local(2022, 12, 1),
tenancy: 6,
managing_organisation: organisation) managing_organisation: organisation)
end end
@ -344,6 +354,44 @@ RSpec.describe CaseLogsController, type: :request do
it "shows the download csv link" do it "shows the download csv link" do
expect(page).to have_link("Download (CSV)", href: "/logs.csv") expect(page).to have_link("Download (CSV)", href: "/logs.csv")
end end
it "does not show the organisation filter" do
expect(page).not_to have_field("organisation-field")
end
end
context "when the user is a customer support user" do
let(:user) { FactoryBot.create(:user, :support) }
let(:org_1) { FactoryBot.create(:organisation) }
let(:org_2) { FactoryBot.create(:organisation) }
let(:tenant_code_1) { "TC5638" }
let(:tenant_code_2) { "TC8745" }
before do
FactoryBot.create(:case_log, :in_progress, owning_organisation: org_1, tenant_code: tenant_code_1)
FactoryBot.create(:case_log, :in_progress, owning_organisation: org_2, tenant_code: tenant_code_2)
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
end
it "does show the organisation filter" do
get "/logs", headers:, params: {}
expect(page).to have_field("organisation-field")
end
it "shows all logs by default" do
get "/logs", headers:, params: {}
expect(page).to have_content(tenant_code_1)
expect(page).to have_content(tenant_code_2)
end
context "when filtering by organisation" do
it "only show the selected organisations logs" do
get "/logs?organisation_select=specific_org&organisation=#{org_1.id}", headers:, params: {}
expect(page).to have_content(tenant_code_1)
expect(page).not_to have_content(tenant_code_2)
end
end
end end
context "when there are more than 20 logs" do context "when there are more than 20 logs" do

44
spec/services/exports/case_log_export_service_spec.rb

@ -46,6 +46,16 @@ RSpec.describe Exports::CaseLogExportService do
context "and one case log is available for export" do context "and one case log is available for export" do
let(:expected_data_filename) { "core_2021_2022_jan_mar_f0001_inc001.xml" } let(:expected_data_filename) { "core_2021_2022_jan_mar_f0001_inc001.xml" }
let(:time_now) { Time.zone.now }
before do
Timecop.freeze(time_now)
case_log
end
after do
LogsExport.destroy_all
end
it "generates a ZIP export file with the expected filename" do it "generates a ZIP export file with the expected filename" do
expect(storage_service).to receive(:write_file).with(expected_zip_filename, any_args) expect(storage_service).to receive(:write_file).with(expected_zip_filename, any_args)
@ -119,6 +129,30 @@ RSpec.describe Exports::CaseLogExportService do
export_service.export_case_logs export_service.export_case_logs
end end
it "creates a logs export record in a database with correct time" do
export_service.export_case_logs
records_from_db = ActiveRecord::Base.connection.execute("select started_at, id from logs_exports ").to_a
expect(records_from_db[0]["started_at"]).to eq(time_now)
expect(records_from_db.count).to eq(1)
end
it "gets the logs for correct timeframe" do
start_time = Time.zone.local(2022, 4, 13, 2, 2, 2)
export = LogsExport.new(started_at: start_time, daily_run_number: 1)
export.save!
params = { from: start_time, to: time_now }
allow(CaseLog).to receive(:where).with("updated_at >= :from and updated_at <= :to", params).once.and_return([])
export_service.export_case_logs
end
context "when this is the first export" do
it "gets the logs for the timeframe up until the current time" do
params = { to: time_now }
allow(CaseLog).to receive(:where).with("updated_at <= :to", params).once.and_return([])
export_service.export_case_logs
end
end
end end
context "and a previous export has run the same day" do context "and a previous export has run the same day" do
@ -133,5 +167,15 @@ RSpec.describe Exports::CaseLogExportService do
export_service.export_case_logs export_service.export_case_logs
end end
end end
context "when export has an error" do
it "does not save a record in the database" do
allow(storage_service).to receive(:write_file).and_raise(StandardError.new("This is an exception"))
export = LogsExport.new
allow(LogsExport).to receive(:new).and_return(export)
expect(export).not_to receive(:save!)
expect { export_service.export_case_logs }.to raise_error(StandardError)
end
end
end end
end end

Loading…
Cancel
Save