diff --git a/app/controllers/case_logs_controller.rb b/app/controllers/case_logs_controller.rb
index fa33ad5df..24ecb1e06 100644
--- a/app/controllers/case_logs_controller.rb
+++ b/app/controllers/case_logs_controller.rb
@@ -126,7 +126,7 @@ private
if session[:case_logs_filters].present?
filters = JSON.parse(session[:case_logs_filters])
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)
end
@@ -137,8 +137,7 @@ private
def set_session_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? }
- new_filters[:user] = [params[:user]] if params[:user].present?
+ current_user.case_logs_filters.each { |filter| new_filters[filter] = params[filter] if params[filter].present? }
session[:case_logs_filters] = new_filters.to_json
end
diff --git a/app/frontend/styles/_filter-layout.scss b/app/frontend/styles/_filter-layout.scss
index 0dbd1f028..b9fb838ef 100644
--- a/app/frontend/styles/_filter-layout.scss
+++ b/app/frontend/styles/_filter-layout.scss
@@ -3,7 +3,7 @@
}
.app-filter-layout__filter {
- @include govuk-media-query(desktop) {
+ @include govuk-media-query(wide) {
float: left;
min-width: govuk-grid-width("one-quarter");
}
@@ -12,7 +12,7 @@
.js-enabled .app-filter-layout__filter {
outline: 0 none;
- @include govuk-media-query($until: desktop) {
+ @include govuk-media-query($until: wide) {
background-color: govuk-colour("light-grey");
bottom: govuk-spacing(1);
border: 1px solid govuk-colour("mid-grey");
@@ -32,7 +32,7 @@
}
.app-filter-layout__content {
- @include govuk-media-query(desktop) {
+ @include govuk-media-query(wide) {
float: right;
max-width: calc(#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)});
width: 100%;
diff --git a/app/frontend/styles/_filter.scss b/app/frontend/styles/_filter.scss
index 2b4f17953..42b7e2f6a 100644
--- a/app/frontend/styles/_filter.scss
+++ b/app/frontend/styles/_filter.scss
@@ -98,4 +98,19 @@
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);
+ }
}
diff --git a/app/frontend/styles/application.scss b/app/frontend/styles/application.scss
index abe376e99..b9de7492c 100644
--- a/app/frontend/styles/application.scss
+++ b/app/frontend/styles/application.scss
@@ -11,6 +11,14 @@ $govuk-image-url-function: frontend-image-url;
$govuk-global-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-prototype-styles";
diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb
index c142b6e6d..d39467b76 100644
--- a/app/helpers/filters_helper.rb
+++ b/app/helpers/filters_helper.rb
@@ -4,6 +4,8 @@ module FiltersHelper
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 == "organisation_select" && value == :all
+ return true if selected_filters["organisation"].present? && filter == "organisation_select" && value == :specific_org
return false if selected_filters[filter].blank?
selected_filters[filter].include?(value.to_s)
@@ -14,4 +16,10 @@ module FiltersHelper
CaseLog.statuses.keys.map { |status| statuses[status] = status.humanize }
statuses
end
+
+ def selected_option(filter)
+ return false unless session[:case_logs_filters]
+
+ JSON.parse(session[:case_logs_filters])[filter]
+ end
end
diff --git a/app/models/case_log.rb b/app/models/case_log.rb
index ff2a962c4..6796be006 100644
--- a/app/models/case_log.rb
+++ b/app/models/case_log.rb
@@ -34,7 +34,7 @@ class CaseLog < ApplicationRecord
belongs_to :managing_organisation, class_name: "Organisation"
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_years, lambda { |years, _user = nil|
first_year = years.shift
@@ -191,9 +191,20 @@ class CaseLog < ApplicationRecord
tshortfall_known == 1
end
+ def is_fixed_term_tenancy?
+ [4, 6].include?(tenancy)
+ end
+
def is_secure_tenancy?
+ return unless collection_start_year
+
# 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
def is_assured_shorthold_tenancy?
@@ -461,9 +472,19 @@ private
end
def dynamically_not_required
- previous_la_known_field = postcode_known? ? %w[previous_la_known] : []
- tshortfall_field = tshortfall_unknown? ? %w[tshortfall] : []
- previous_la_known_field + tshortfall_field
+ not_required = []
+ not_required << "previous_la_known" if postcode_known?
+ 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
def set_derived_fields!
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 8096c6be1..c52c3d922 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -18,7 +18,7 @@ class Organisation < ApplicationRecord
validates :provider_type, presence: true
def case_logs
- CaseLog.for_organisation(self)
+ CaseLog.filter_by_organisation(self)
end
def completed_case_logs
diff --git a/app/models/user.rb b/app/models/user.rb
index 27a884fa4..09fc93c3c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -36,7 +36,7 @@ class User < ApplicationRecord
if support?
CaseLog.all
else
- CaseLog.for_organisation(organisation)
+ CaseLog.filter_by_organisation(organisation)
end
end
@@ -88,4 +88,12 @@ class User < ApplicationRecord
ROLES.except(:support)
end
+
+ def case_logs_filters
+ if support?
+ %i[status years user organisation]
+ else
+ %i[status years user]
+ end
+ end
end
diff --git a/app/services/exports/case_log_export_service.rb b/app/services/exports/case_log_export_service.rb
index 46d105b61..fcabc1e8d 100644
--- a/app/services/exports/case_log_export_service.rb
+++ b/app/services/exports/case_log_export_service.rb
@@ -15,15 +15,12 @@ module Exports
end
def export_case_logs
- # Case log data is already ordered by startdate
- case_logs = retrieve_case_logs
- daily_run_number = get_next_run_number
- write_master_manifest(daily_run_number)
+ current_time = Time.zone.now
+ case_logs = retrieve_case_logs(current_time)
+ export = build_export_run(current_time)
+ write_master_manifest(export.daily_run_number)
write_export_archive(case_logs)
-
- export = LogsExport.new(daily_run_number:)
export.save!
- export
end
def is_omitted_field?(field_name)
@@ -34,14 +31,15 @@ module Exports
private
- def get_next_run_number
+ def build_export_run(current_time)
today = Time.zone.today
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?
- 1
- else
- last_daily_run_number + 1
- end
+ last_daily_run_number = 0 if last_daily_run_number.nil?
+
+ export = LogsExport.new
+ export.daily_run_number = last_daily_run_number + 1
+ export.started_at = current_time
+ export
end
def write_master_manifest(daily_run_number)
@@ -86,8 +84,15 @@ module Exports
end
end
- def retrieve_case_logs
- CaseLog.all
+ def retrieve_case_logs(current_time)
+ 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
def build_manifest_csv_io
diff --git a/app/views/case_logs/_log_filters.erb b/app/views/case_logs/_log_filters.erb
index 4e294c81e..45354fb40 100644
--- a/app/views/case_logs/_log_filters.erb
+++ b/app/views/case_logs/_log_filters.erb
@@ -6,12 +6,31 @@
<%= form_with url: "/logs", html: { method: :get } do |f| %>
<% 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: status_filters, label: "Status", category: "status" } %>
<%= 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" %>
<% end %>
-
\ No newline at end of file
+
diff --git a/app/views/filters/_radio_filter.html.erb b/app/views/filters/_radio_filter.html.erb
index aff0f6ed6..abb55eafe 100644
--- a/app/views/filters/_radio_filter.html.erb
+++ b/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 %>
- <% options.map do |key, option| %>
- <%= f.govuk_radio_button category, key.to_s,
- label: { text: option },
- checked: filter_selected?(category, key),
- size: "s" %>
+ <% options.map do |key, option| %>
+ <%= f.govuk_radio_button category, key.to_s,
+ label: { text: option[:label] },
+ checked: filter_selected?(category, key),
+ 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 %>
diff --git a/app/views/filters/_select_filter.html.erb b/app/views/filters/_select_filter.html.erb
new file mode 100644
index 000000000..e2c71988e
--- /dev/null
+++ b/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" %>
diff --git a/config/forms/2022_2023.json b/config/forms/2022_2023.json
index 7c7c2e66b..93177a301 100644
--- a/config/forms/2022_2023.json
+++ b/config/forms/2022_2023.json
@@ -951,7 +951,7 @@
"joint": {
"check_answer_label": "Is this a joint tenancy?",
"header": "Is this a joint tenancy?",
- "hint_text": "For example, 27 3 2021.",
+ "hint_text": "",
"type": "radio",
"answer_options": {
"1": {
@@ -959,6 +959,9 @@
},
"2": {
"value": "No"
+ },
+ "3": {
+ "value": "Don’t know"
}
}
}
@@ -994,7 +997,7 @@
"hint_text": "",
"type": "radio",
"answer_options": {
- "1": {
+ "4": {
"value": "Assured Shorthold Tenancy (AST) - Fixed term"
},
"6": {
@@ -1041,7 +1044,7 @@
"hint_text": "This is also known as an ‘introductory period’.",
"type": "radio",
"answer_options": {
- "1": {
+ "4": {
"value": "Assured Shorthold Tenancy (AST) - Fixed term"
},
"6": {
@@ -1095,10 +1098,13 @@
},
"depends_on": [
{
- "tenancy": 1
+ "tenancy": 4
},
{
"tenancy": 6
+ },
+ {
+ "tenancy": 3
}
]
},
@@ -6297,7 +6303,7 @@
"label": true,
"i18n_template": "la"
},
- {
+ {
"key": "soft_min_for_period",
"label": false,
"i18n_template": "soft_min_for_period"
@@ -6336,7 +6342,7 @@
"label": true,
"i18n_template": "la"
},
- {
+ {
"key": "soft_max_for_period",
"label": false,
"i18n_template": "soft_max_for_period"
diff --git a/db/migrate/20220516111514_add_started_at.rb b/db/migrate/20220516111514_add_started_at.rb
new file mode 100644
index 000000000..1eedcf22a
--- /dev/null
+++ b/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
diff --git a/db/schema.rb b/db/schema.rb
index 240e514df..be67fb5f8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# 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
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|
t.integer "daily_run_number"
t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" }
+ t.datetime "started_at"
end
create_table "organisation_las", force: :cascade do |t|
diff --git a/spec/helpers/filters_helper_spec.rb b/spec/helpers/filters_helper_spec.rb
index 296e336a4..e665e32a0 100644
--- a/spec/helpers/filters_helper_spec.rb
+++ b/spec/helpers/filters_helper_spec.rb
@@ -16,8 +16,8 @@ RSpec.describe FiltersHelper do
context "when looking at the all value" do
it "returns true if no filters have been set yet" do
- expect(filter_selected?("user", :all)).to be_truthy
- expect(filter_selected?("user", :yours)).to be_falsey
+ expect(filter_selected?("user", :all)).to be true
+ expect(filter_selected?("user", :yours)).to be false
end
end
end
@@ -28,11 +28,33 @@ RSpec.describe FiltersHelper do
end
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
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
diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb
index 4a8bc8677..005e8c057 100644
--- a/spec/models/case_log_spec.rb
+++ b/spec/models/case_log_spec.rb
@@ -1893,6 +1893,31 @@ RSpec.describe CaseLog do
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
it "allows filtering on a single status" do
expect(described_class.filter_by_status(%w[in_progress]).count).to eq(2)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 97b1fdaf1..4cbebcdae 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -97,6 +97,10 @@ RSpec.describe User, type: :model do
data_coordinator: 2,
})
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
context "when the user is a Customer Support person" do
@@ -119,6 +123,10 @@ RSpec.describe User, type: :model do
support: 99,
})
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
diff --git a/spec/models/validations/tenancy_validations_spec.rb b/spec/models/validations/tenancy_validations_spec.rb
index 09b3c5314..9e80fc2d1 100644
--- a/spec/models/validations/tenancy_validations_spec.rb
+++ b/spec/models/validations/tenancy_validations_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new }
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
context "when fixed term tenancy" do
@@ -62,44 +62,134 @@ RSpec.describe Validations::TenancyValidations do
end
end
- context "when type of tenancy is secure" do
- let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
+ context "when the collection start year is before 2022" do
+ 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
- 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))
+ 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
- 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))
+ 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
- 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
+ context "when the collection start year is 2022 or later" do
+ let(:record) { FactoryBot.create(:case_log, startdate: Time.zone.local(2022, 5, 1)) }
+
+ context "when type of tenancy is Secure - fixed term" do
+ let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
+
+ 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
- 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
+ context "when type of tenancy is Secure - lifetime" do
+ let(:expected_error) { I18n.t("validations.tenancy.length.secure") }
+
+ before { record.tenancy = 7 }
+
+ 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
diff --git a/spec/requests/case_logs_controller_spec.rb b/spec/requests/case_logs_controller_spec.rb
index 9a9dd60e1..3c91db3e4 100644
--- a/spec/requests/case_logs_controller_spec.rb
+++ b/spec/requests/case_logs_controller_spec.rb
@@ -186,6 +186,7 @@ RSpec.describe CaseLogsController, type: :request do
context "when filtering" do
context "with status filter" do
+ let(:organisation_2) { FactoryBot.create(:organisation) }
let!(:in_progress_case_log) do
FactoryBot.create(:case_log, :in_progress,
owning_organisation: organisation,
@@ -193,7 +194,7 @@ RSpec.describe CaseLogsController, type: :request do
end
let!(:completed_case_log) do
FactoryBot.create(:case_log, :completed,
- owning_organisation: organisation,
+ owning_organisation: organisation_2,
managing_organisation: organisation)
end
@@ -209,6 +210,12 @@ RSpec.describe CaseLogsController, type: :request do
expect(page).not_to have_link(completed_case_log.id.to_s)
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
get "/logs?status[]=in_progress", headers: headers, params: {}
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,
mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1),
+ tenancy: 6,
managing_organisation: organisation)
end
@@ -260,6 +268,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1),
+ tenancy: 6,
managing_organisation: organisation)
end
let!(:case_log_2022_in_progress) do
@@ -267,6 +276,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1),
+ tenancy: 6,
managing_organisation: organisation)
end
@@ -344,6 +354,44 @@ RSpec.describe CaseLogsController, type: :request do
it "shows the download csv link" do
expect(page).to have_link("Download (CSV)", href: "/logs.csv")
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
context "when there are more than 20 logs" do
diff --git a/spec/services/exports/case_log_export_service_spec.rb b/spec/services/exports/case_log_export_service_spec.rb
index b168c46d2..c517baeb7 100644
--- a/spec/services/exports/case_log_export_service_spec.rb
+++ b/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
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
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
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
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
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