Browse Source

Merge branch 'main' into move-privacy-notice-add-final-review

pull/469/head
Kat 3 years ago
parent
commit
255ff2c717
  1. 24
      .erb-lint.yml
  2. 1
      Gemfile
  3. 27
      Gemfile.lock
  4. 15
      app/components/document_list_component.html.erb
  5. 8
      app/components/document_list_component.rb
  6. 17
      app/components/primary_navigation_component.html.erb
  7. 8
      app/components/primary_navigation_component.rb
  8. 15
      app/components/tab_navigation_component.html.erb
  9. 14
      app/components/tab_navigation_component.rb
  10. 14
      app/controllers/organisations_controller.rb
  11. 6
      app/controllers/users_controller.rb
  12. 1
      app/frontend/controllers/accessible_autocomplete_controller.js
  13. 16
      app/frontend/controllers/filter_controller.js
  14. 26
      app/frontend/controllers/filter_layout_controller.js
  15. 4
      app/frontend/controllers/index.js
  16. 112
      app/frontend/modules/filter_toggle.js
  17. 7
      app/frontend/styles/_card.scss
  18. 66
      app/frontend/styles/_document-list.scss
  19. 42
      app/frontend/styles/_filter-layout.scss
  20. 66
      app/frontend/styles/_filter.scss
  21. 23
      app/frontend/styles/_header.scss
  22. 69
      app/frontend/styles/_primary-navigation.scss
  23. 76
      app/frontend/styles/_tab-navigation.scss
  24. 13
      app/frontend/styles/application.scss
  25. 26
      app/models/bulk_upload.rb
  26. 137
      app/models/case_log.rb
  27. 24
      app/models/form/question.rb
  28. 12
      app/models/validations/date_validations.rb
  29. 21
      app/models/validations/financial_validations.rb
  30. 10
      app/models/validations/household_validations.rb
  31. 2
      app/models/validations/property_validations.rb
  32. 6
      app/models/validations/setup_validations.rb
  33. 2
      app/models/validations/tenancy_validations.rb
  34. 392
      app/services/imports/case_logs_import_service.rb
  35. 15
      app/views/case_logs/_log_filters.erb
  36. 11
      app/views/case_logs/_log_list.html.erb
  37. 3
      app/views/case_logs/bulk_upload.html.erb
  38. 2
      app/views/case_logs/edit.html.erb
  39. 19
      app/views/case_logs/index.html.erb
  40. 3
      app/views/devise/confirmations/new.html.erb
  41. 8
      app/views/devise/passwords/edit.html.erb
  42. 5
      app/views/devise/passwords/new.html.erb
  43. 8
      app/views/devise/passwords/reset_password.html.erb
  44. 6
      app/views/devise/sessions/new.html.erb
  45. 12
      app/views/devise/shared/_links.html.erb
  46. 4
      app/views/devise/two_factor_authentication/resend.html.erb
  47. 5
      app/views/devise/two_factor_authentication/show.html.erb
  48. 3
      app/views/devise/unlocks/new.html.erb
  49. 6
      app/views/filters/_checkbox_filter.html.erb
  50. 6
      app/views/form/_check_answers_table.html.erb
  51. 7
      app/views/form/_checkbox_question.html.erb
  52. 3
      app/views/form/_date_question.html.erb
  53. 11
      app/views/form/_interruption_screen_question.html.erb
  54. 2
      app/views/form/_numeric_output_question.html.erb
  55. 6
      app/views/form/_numeric_question.html.erb
  56. 19
      app/views/form/_radio_question.html.erb
  57. 9
      app/views/form/_select_question.html.erb
  58. 5
      app/views/form/_text_question.html.erb
  59. 5
      app/views/form/_textarea_question.html.erb
  60. 14
      app/views/form/check_answers.html.erb
  61. 2
      app/views/form/guidance/_what_counts_as_income.html.erb
  62. 18
      app/views/form/page.html.erb
  63. 16
      app/views/layouts/_collection_resources.html.erb
  64. 83
      app/views/layouts/application.html.erb
  65. 2
      app/views/layouts/mailer.html.erb
  66. 2
      app/views/layouts/organisations.html.erb
  67. 17
      app/views/organisations/edit.html.erb
  68. 0
      app/views/organisations/index.html.erb
  69. 28
      app/views/organisations/show.html.erb
  70. 20
      app/views/organisations/users.html.erb
  71. 8
      app/views/pagy/_nav.html.erb
  72. 35
      app/views/start/index.html.erb
  73. 23
      app/views/users/edit.html.erb
  74. 0
      app/views/users/index.html.erb
  75. 24
      app/views/users/new.html.erb
  76. 40
      app/views/users/show.html.erb
  77. 350
      config/forms/2021_2022.json
  78. 44
      config/locales/en.yml
  79. 0
      db/migrate/20220207112310_additional_user_fields2.rb
  80. 13
      db/migrate/20220411092231_update_case_logs_fields.rb
  81. 30
      db/schema.rb
  82. 2
      docs/api/DLUHC-CORE-Data.v1.json
  83. 19
      spec/components/document_list_component_spec.rb
  84. 27
      spec/components/primary_navigation_component_spec.rb
  85. 27
      spec/components/tab_navigation_component_spec.rb
  86. 4
      spec/controllers/admin/admin_users_controller_spec.rb
  87. 4
      spec/controllers/admin/case_logs_controller_spec.rb
  88. 4
      spec/controllers/admin/organisations_controller_spec.rb
  89. 4
      spec/controllers/admin/users_controller_spec.rb
  90. 42
      spec/factories/case_log.rb
  91. 16
      spec/features/form/check_answers_page_spec.rb
  92. 6
      spec/features/form/conditional_questions_spec.rb
  93. 4
      spec/features/form/form_navigation_spec.rb
  94. 6
      spec/features/form/page_routing_spec.rb
  95. 2
      spec/features/form/saving_data_spec.rb
  96. 4
      spec/features/form/validations_spec.rb
  97. 9
      spec/features/organisation_spec.rb
  98. 8
      spec/features/reset_password.html.erb
  99. 30
      spec/fixtures/complete_case_log.json
  100. 41
      spec/fixtures/exports/case_logs.xml
  101. Some files were not shown because too many files have changed in this diff Show More

24
.erb-lint.yml

@ -0,0 +1,24 @@
---
EnableDefaultLinters: true
linters:
Rubocop:
enabled: true
rubocop_config:
inherit_from:
- .rubocop.yml
Layout/ArgumentAlignment:
Enabled: false
Layout/CommentIndentation:
Enabled: false
Layout/FirstArgumentIndentation:
Enabled: false
Layout/FirstArrayElementIndentation:
Enabled: false
Layout/FirstHashElementIndentation:
Enabled: false
Layout/InitialIndentation:
Enabled: false
Layout/TrailingEmptyLines:
Enabled: false
Lint/UselessAssignment:
Enabled: false

1
Gemfile

@ -78,6 +78,7 @@ group :development do
gem "web-console", ">= 4.1.0" gem "web-console", ">= 4.1.0"
# Display performance information such as SQL time and flame graphs for each request in your browser. # Display performance information such as SQL time and flame graphs for each request in your browser.
# Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
gem "erb_lint", require: false
gem "rack-mini-profiler", "~> 2.0" gem "rack-mini-profiler", "~> 2.0"
gem "rubocop-govuk", require: false gem "rubocop-govuk", require: false
gem "rubocop-performance", require: false gem "rubocop-performance", require: false

27
Gemfile.lock

@ -69,7 +69,7 @@ GEM
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0)
activeadmin (2.11.1) activeadmin (2.11.2)
arbre (~> 1.2, >= 1.2.1) arbre (~> 1.2, >= 1.2.1)
formtastic (>= 3.1, < 5.0) formtastic (>= 3.1, < 5.0)
formtastic_i18n (~> 0.4) formtastic_i18n (~> 0.4)
@ -105,8 +105,8 @@ GEM
ruby2_keywords (>= 0.0.2, < 1.0) ruby2_keywords (>= 0.0.2, < 1.0)
ast (2.4.2) ast (2.4.2)
aws-eventstream (1.2.0) aws-eventstream (1.2.0)
aws-partitions (1.575.0) aws-partitions (1.576.0)
aws-sdk-core (3.130.0) aws-sdk-core (3.130.1)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0) aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
@ -121,6 +121,14 @@ GEM
aws-sigv4 (1.4.0) aws-sigv4 (1.4.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.17) bcrypt (3.1.17)
better_html (1.0.16)
actionview (>= 4.0)
activesupport (>= 4.0)
ast (~> 2.0)
erubi (~> 1.4)
html_tokenizer (~> 0.0.6)
parser (>= 2.4)
smart_properties
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.11.1) bootsnap (1.11.1)
msgpack (~> 1.2) msgpack (~> 1.2)
@ -159,6 +167,14 @@ GEM
dotenv (= 2.7.6) dotenv (= 2.7.6)
railties (>= 3.2) railties (>= 3.2)
encryptor (3.0.0) encryptor (3.0.0)
erb_lint (0.1.1)
activesupport
better_html (~> 1.0.7)
html_tokenizer
parser (>= 2.7.1.4)
rainbow
rubocop
smart_properties
erubi (1.10.0) erubi (1.10.0)
excon (0.92.2) excon (0.92.2)
factory_bot (6.2.1) factory_bot (6.2.1)
@ -188,6 +204,7 @@ GEM
actionpack (>= 5.2) actionpack (>= 5.2)
activesupport (>= 5.2) activesupport (>= 5.2)
hashdiff (1.0.1) hashdiff (1.0.1)
html_tokenizer (0.0.7)
i18n (1.10.0) i18n (1.10.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
inherited_resources (1.13.1) inherited_resources (1.13.1)
@ -269,7 +286,7 @@ GEM
globalid globalid
paper_trail (>= 3.0.0) paper_trail (>= 3.0.0)
parallel (1.22.1) parallel (1.22.1)
parser (3.1.1.0) parser (3.1.2.0)
ast (~> 2.4.1) ast (~> 2.4.1)
pg (1.3.5) pg (1.3.5)
postcodes_io (0.4.0) postcodes_io (0.4.0)
@ -420,6 +437,7 @@ GEM
simplecov_json_formatter (~> 0.1) simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3) simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4) simplecov_json_formatter (0.1.4)
smart_properties (1.17.0)
stimulus-rails (1.0.4) stimulus-rails (1.0.4)
railties (>= 6.0.0) railties (>= 6.0.0)
strscan (3.0.1) strscan (3.0.1)
@ -469,6 +487,7 @@ DEPENDENCIES
chartkick chartkick
devise! devise!
dotenv-rails dotenv-rails
erb_lint
factory_bot_rails factory_bot_rails
govuk-components govuk-components
govuk_design_system_formbuilder govuk_design_system_formbuilder

15
app/components/document_list_component.html.erb

@ -0,0 +1,15 @@
<ul class="app-document-list">
<% items.each do |item| %>
<li class="app-document-list__item">
<h3 class="app-document-list__item-title">
<%= govuk_link_to item[:name], item[:href] %>
</h3>
<% if item[:description] %>
<p class="app-document-list__item-description"><%= item[:description] %></p>
<% end %>
<% if item[:metadata] %>
<p class="app-document-list__item-metadata"><%= item[:metadata] %></p>
<% end %>
</li>
<% end %>
</ul>

8
app/components/document_list_component.rb

@ -0,0 +1,8 @@
class DocumentListComponent < ViewComponent::Base
attr_reader :items
def initialize(items:)
@items = items
super
end
end

17
app/components/primary_navigation_component.html.erb

@ -0,0 +1,17 @@
<nav class="app-primary-navigation" aria-label="primary">
<div class="govuk-width-container">
<ul class="app-primary-navigation__list">
<% items.each do |item| %>
<% if item.fetch(:current, false) || current_page?(item.fetch(:url)) || current_page?("#{item.fetch(:url)}/details") %>
<li class="app-primary-navigation__item app-primary-navigation__item--current">
<%= govuk_link_to item[:name], item[:url], class: "app-primary-navigation__link", aria: { current: "page" } %>
</li>
<% else %>
<li class="app-primary-navigation__item">
<%= govuk_link_to item[:name], item[:url], class: "app-primary-navigation__link" %>
</li>
<% end %>
<% end %>
</ul>
</div>
</nav>

8
app/components/primary_navigation_component.rb

@ -0,0 +1,8 @@
class PrimaryNavigationComponent < ViewComponent::Base
attr_reader :items
def initialize(items:)
@items = items
super
end
end

15
app/components/tab_navigation_component.html.erb

@ -1,15 +0,0 @@
<nav class="app-tab-navigation" aria-label="sub menu">
<ul class="app-tab-navigation__list">
<% items.each do |item| %>
<% if item.fetch(:current, false) || current_page?(strip_query(item.fetch(:url))) %>
<li class="app-tab-navigation__item app-tab-navigation__item--current">
<%= govuk_link_to item[:name], item[:url], class: 'app-tab-navigation__link', aria: { current: 'page' } %>
</li>
<% else %>
<li class="app-tab-navigation__item">
<%= govuk_link_to item[:name], item[:url], class: 'app-tab-navigation__link' %>
</li>
<% end %>
<% end %>
</ul>
</nav>

14
app/components/tab_navigation_component.rb

@ -1,14 +0,0 @@
class TabNavigationComponent < ViewComponent::Base
attr_reader :items
def initialize(items:)
@items = items
super
end
def strip_query(url)
url = Addressable::URI.parse(url)
url.query_values = nil
url.to_s
end
end

14
app/controllers/organisations_controller.rb

@ -1,8 +1,14 @@
class OrganisationsController < ApplicationController class OrganisationsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!, except: [:index]
before_action :find_resource before_action :find_resource, except: [:index]
before_action :authenticate_scope! before_action :authenticate_scope!
def index
unless current_user.support?
redirect_to user_path(current_user)
end
end
def show def show
redirect_to details_organisation_path(@organisation) redirect_to details_organisation_path(@organisation)
end end
@ -41,10 +47,12 @@ private
end end
def authenticate_scope! def authenticate_scope!
render_not_found if current_user.organisation != @organisation render_not_found if current_user.organisation != @organisation && !current_user.support?
end end
def find_resource def find_resource
return if current_user.support?
@organisation = Organisation.find(params[:id]) @organisation = Organisation.find(params[:id])
end end
end end

6
app/controllers/users_controller.rb

@ -5,6 +5,12 @@ class UsersController < ApplicationController
before_action :find_resource, except: %i[new create] before_action :find_resource, except: %i[new create]
before_action :authenticate_scope!, except: %i[new] before_action :authenticate_scope!, except: %i[new]
def index
unless current_user.support?
redirect_to user_path(@user)
end
end
def update def update
if @user.update(user_params) if @user.update(user_params)
if @user == current_user if @user == current_user

1
app/frontend/controllers/accessible_autocomplete_controller.js

@ -3,7 +3,6 @@ import accessibleAutocomplete from "accessible-autocomplete"
import 'accessible-autocomplete/dist/accessible-autocomplete.min.css' import 'accessible-autocomplete/dist/accessible-autocomplete.min.css'
export default class extends Controller { export default class extends Controller {
connect() { connect() {
accessibleAutocomplete.enhanceSelectElement({ accessibleAutocomplete.enhanceSelectElement({
defaultValue: '', defaultValue: '',

16
app/frontend/controllers/filter_controller.js

@ -1,16 +0,0 @@
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
toggleFilter() {
let filter_panel = document.getElementById("filter-panel");
let toggle_filter_button = document.getElementById("toggle-filter-button");
if (filter_panel.style.display === "none" || !filter_panel.style.display) {
filter_panel.style.display = "block";
toggle_filter_button.innerText = "Hide filters";
} else {
filter_panel.style.display = "none";
toggle_filter_button.innerText = "Show filters";
}
}
}

26
app/frontend/controllers/filter_layout_controller.js

@ -0,0 +1,26 @@
import { Controller } from "@hotwired/stimulus";
import { FilterToggle } from "../modules/filter_toggle.js"
export default class extends Controller {
connect() {
const filterToggle = new FilterToggle({
bigModeMediaQuery: '(min-width: 48.0625em)',
closeButton: {
container: this.element.querySelector('.app-filter__header'),
text: 'Close'
},
filter: {
container: this.element.querySelector('.app-filter-layout__filter')
},
startHidden: false,
toggleButton: {
container: this.element.querySelector('.app-filter-toggle'),
showText: 'Show filters',
hideText: 'Hide filters',
classes: 'govuk-button--secondary'
}
})
filterToggle.init()
}
}

4
app/frontend/controllers/index.js

@ -15,5 +15,5 @@ application.register("govukfrontend", GovukfrontendController)
import NumericQuestionController from "./numeric_question_controller.js" import NumericQuestionController from "./numeric_question_controller.js"
application.register("numeric-question", NumericQuestionController) application.register("numeric-question", NumericQuestionController)
import FilterController from "./filter_controller.js" import FilterLayoutController from "./filter_layout_controller.js"
application.register("filter", FilterController) application.register("filter-layout", FilterLayoutController)

112
app/frontend/modules/filter_toggle.js

@ -0,0 +1,112 @@
export class FilterToggle {
constructor (options) {
this.options = options
this.container = this.options.toggleButton.container
}
setupResponsiveChecks () {
this.mq = window.matchMedia(this.options.bigModeMediaQuery)
this.mq.addListener(this.checkMode.bind(this))
this.checkMode(this.mq)
}
checkMode (mq) {
if (mq.matches) {
this.enableBigMode()
} else {
this.enableSmallMode()
}
}
enableBigMode () {
this.showMenu()
this.removeMenuButton()
this.removeCloseButton()
}
enableSmallMode () {
this.options.filter.container.setAttribute("tabindex", "-1")
this.hideMenu()
this.addMenuButton()
this.addCloseButton()
}
addCloseButton () {
if (this.options.closeButton) {
this.closeButton = document.createElement("button")
this.closeButton.classList.add("app-filter__close")
this.closeButton.innerText = this.options.closeButton.text
this.closeButton.type = 'button'
this.closeButton.addEventListener('click', this.onCloseClick.bind(this))
this.options.closeButton.container.append(this.closeButton)
}
}
onCloseClick () {
this.hideMenu()
this.menuButton.focus()
}
removeCloseButton () {
if (this.closeButton) {
this.closeButton.remove()
this.closeButton = null
}
}
addMenuButton () {
this.menuButton = document.createElement("button")
this.menuButton.setAttribute("aria-expanded", "false")
this.menuButton.setAttribute("aria-has-popup", "true")
this.menuButton.classList.add("govuk-button", this.options.toggleButton.classes, "app-filter-toggle__button")
this.menuButton.innerText = this.options.toggleButton.showText
this.menuButton.type = "button"
this.menuButton.addEventListener("click", this.onMenuButtonClick.bind(this))
this.options.toggleButton.container.prepend(this.menuButton)
}
removeMenuButton () {
if (this.menuButton) {
this.menuButton.remove()
this.menuButton = null
}
}
hideMenu () {
if (this.menuButton) {
this.menuButton.setAttribute("aria-expanded", "false")
this.menuButton.innerText = this.options.toggleButton.showText
}
this.options.filter.container.setAttribute("hidden", true)
}
showMenu () {
if (this.menuButton) {
this.menuButton.setAttribute("aria-expanded", "true")
this.menuButton.innerText = this.options.toggleButton.hideText
}
this.options.filter.container.removeAttribute("hidden")
}
onMenuButtonClick () {
this.toggle()
}
toggle () {
if (this.options.filter.container.hidden) {
this.showMenu()
this.options.filter.container.focus()
} else {
this.hideMenu()
}
}
init () {
this.setupResponsiveChecks()
if (this.options.startHidden) {
this.hideMenu()
}
}
}

7
app/frontend/styles/_card.scss

@ -0,0 +1,7 @@
.app-card {
@include govuk-responsive-padding(4);
@include govuk-font($size: 19);
background-color: govuk-colour("light-grey");
display: block;
position: relative;
}

66
app/frontend/styles/_document-list.scss

@ -0,0 +1,66 @@
.app-document-list {
list-style: none;
padding: 0;
}
.app-document-list__item {
margin-bottom: govuk-spacing(4);
&:last-child {
border-bottom: 0;
margin-bottom: 0;
padding-bottom: 0;
}
}
.app-document-list__item-title {
@include govuk-font($size: 16, $weight: "bold");
margin: 0 0 govuk-spacing(1);
}
.app-document-list__item-metadata {
padding: 0;
margin: 0;
}
.app-document-list__item-description {
@include govuk-font($size: 16);
margin: govuk-spacing(1) 0;
}
.app-document-list__item-metadata {
@include govuk-font($size: 16);
color: $govuk-secondary-text-colour;
margin: 0;
}
.app-document-list {
list-style: none;
padding: 0;
}
.app-document-list__item {
margin-bottom: govuk-spacing(4);
&:last-child {
border-bottom: 0;
margin-bottom: 0;
padding-bottom: 0;
}
}
.app-document-list__item-title {
@include govuk-font($size: 16, $weight: "bold");
margin: 0 0 govuk-spacing(1);
}
.app-document-list__item-description {
@include govuk-font($size: 16);
margin: govuk-spacing(1) 0;
}
.app-document-list__item-metadata {
@include govuk-font($size: 16);
color: $govuk-secondary-text-colour;
padding: 0;
margin: 0;
}

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

@ -0,0 +1,42 @@
.app-filter-layout {
@include govuk-clearfix;
}
.app-filter-layout__filter {
@include govuk-media-query(desktop) {
float: left;
min-width: govuk-grid-width("one-quarter");
}
}
.js-enabled .app-filter-layout__filter {
outline: 0 none;
@include govuk-media-query($until: desktop) {
background-color: govuk-colour("light-grey");
bottom: govuk-spacing(1);
border: 1px solid govuk-colour("mid-grey");
max-width: 310px;
min-width: 260px;
width: 100%;
overflow-y: scroll;
position: fixed;
right: govuk-spacing(1);
top: govuk-spacing(1);
z-index: 100;
&:focus {
outline: $govuk-focus-width solid $govuk-focus-colour;
}
}
}
.app-filter-layout__content {
@include govuk-media-query(desktop) {
float: right;
max-width: calc(
#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)}
);
width: 100%;
}
}

66
app/frontend/styles/_filter.scss

@ -61,63 +61,41 @@
vertical-align: middle; vertical-align: middle;
width: 14px; width: 14px;
} }
@include govuk-media-query(desktop) {
display: none;
}
}
.app-filter-layout {
@include govuk-clearfix;
} }
.app-filter-toggle__button { .app-filter-toggle__button {
min-width: 128px; min-width: 128px;
@include govuk-media-query(desktop) {
display: none !important;
}
} }
.app-filter-layout__filter { .app-filter__group {
@include govuk-media-query(desktop) { border-bottom: 1px solid $govuk-border-colour;
float: left; margin-bottom: govuk-spacing(3);
min-width: govuk-grid-width("one-quarter"); padding-bottom: govuk-spacing(2);
}
display: none;
@include govuk-media-query(desktop) { &:last-child {
display: block; border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
} }
}
.js-enabled .app-filter-layout__filter { .govuk-fieldset__legend {
outline: 0 none; margin-bottom: govuk-spacing(1);
}
@include govuk-media-query($until: desktop) { .govuk-form-group {
background-color: govuk-colour("light-grey"); margin-bottom: 0;
bottom: govuk-spacing(1);
border: 1px solid govuk-colour("mid-grey");
max-width: 310px;
min-width: 260px;
width: 100%;
overflow-y: scroll;
position: fixed;
right: govuk-spacing(1);
top: govuk-spacing(1);
z-index: 100;
&:focus { &:last-child {
outline: $govuk-focus-width solid $govuk-focus-colour; margin-bottom: 0;
} }
} }
}
.app-filter-layout__content { .govuk-checkboxes__label,
@include govuk-media-query(desktop) { .govuk-radios__label {
float: right; @include govuk-font(16);
max-width: calc(
#{govuk-grid-width("three-quarters")} - #{govuk-spacing(6)} &::before {
); background-color: govuk-colour("white");
width: 100%; }
} }
} }

23
app/frontend/styles/_header.scss

@ -0,0 +1,23 @@
.app-header {
border-bottom: govuk-spacing(2) solid $govuk-brand-colour;
.govuk-header__logo {
@include govuk-media-query($from: desktop) {
width: 60%;
}
@include govuk-media-query($from: 860px) {
width: 75%;
}
}
.govuk-header__content {
@include govuk-media-query($from: desktop) {
width: 40%;
}
@include govuk-media-query($from: 860px) {
width: 25%;
}
}
}

69
app/frontend/styles/_primary-navigation.scss

@ -0,0 +1,69 @@
.app-primary-navigation {
@include govuk-font(19, $weight: bold);
background-color: govuk-colour("light-grey");
border-bottom: 1px solid $govuk-border-colour;
}
.govuk-phase-banner + .app-primary-navigation {
margin-top: -1px;
}
.app-primary-navigation__list {
@include govuk-clearfix;
left: govuk-spacing(-3);
list-style: none;
margin: 0;
padding: 0;
position: relative;
right: govuk-spacing(-3);
width: calc(100% + #{govuk-spacing(6)});
}
.app-primary-navigation__item {
box-sizing: border-box;
display: block;
float: left;
line-height: 50px;
height: 50px;
padding: 0 govuk-spacing(3);
position: relative;
}
.app-primary-navigation__item--current {
border-bottom: $govuk-border-width-narrow solid $govuk-link-colour;
&:hover {
border-bottom-color: $govuk-link-hover-colour;
}
&:active {
border-bottom-color: $govuk-link-active-colour;
}
}
.app-primary-navigation__item--align-right {
@include govuk-media-query($from: tablet) {
float: right;
}
}
.app-primary-navigation__link {
@include govuk-link-common;
@include govuk-link-style-no-visited-state;
@include govuk-link-style-no-underline;
@include govuk-typography-weight-bold;
// Extend the touch area of the link to the list
&:after {
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
}
.app-primary-navigation__item--current .app-primary-navigation__link:hover {
text-decoration: none;
}

76
app/frontend/styles/_tab-navigation.scss

@ -1,76 +0,0 @@
.app-tab-navigation {
@include govuk-font(19, $weight: bold);
@include govuk-responsive-margin(6, "bottom");
}
.app-tab-navigation__list {
@include govuk-clearfix;
left: govuk-spacing(-3);
list-style: none;
margin: 0;
padding: 0;
position: relative;
right: govuk-spacing(-3);
width: calc(100% + #{govuk-spacing(6)});
@include govuk-media-query($from: tablet) {
box-shadow: inset 0 -1px 0 $govuk-border-colour;
}
}
.app-tab-navigation__item {
box-sizing: border-box;
display: block;
line-height: 40px;
height: 40px;
padding: 0 govuk-spacing(3);
@include govuk-media-query($from: tablet) {
box-shadow: none;
display: block;
float: left;
line-height: 50px;
height: 50px;
padding: 0 govuk-spacing(3);
position: relative;
}
}
.app-tab-navigation__item--current {
@include govuk-media-query($until: tablet) {
border-left: 4px solid $govuk-link-colour;
padding-left: 11px;
}
@include govuk-media-query($from: tablet) {
border-bottom: 4px solid $govuk-link-colour;
padding-left: govuk-spacing(3);
}
}
.app-tab-navigation__link {
@include govuk-link-common;
@include govuk-link-style-no-visited-state;
@include govuk-link-style-no-underline;
@include govuk-typography-weight-bold;
&:not(:focus):hover {
color: $govuk-link-colour;
}
// Extend the touch area of the link to the list
&:after {
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
}
.app-tab-navigation__item--current .app-tab-navigation__link {
&:hover {
text-decoration: none;
}
}

13
app/frontend/styles/application.scss

@ -1,31 +1,36 @@
@function frontend-font-url($filename) { @function frontend-font-url($filename) {
@return url("~assets/fonts/"+$filename); @return url("~assets/fonts/" + $filename);
} }
@function frontend-image-url($filename) { @function frontend-image-url($filename) {
@return url("~assets/images/"+$filename); @return url("~assets/images/" + $filename);
} }
$govuk-font-url-function: frontend-font-url; $govuk-font-url-function: frontend-font-url;
$govuk-image-url-function: frontend-image-url; $govuk-image-url-function: frontend-image-url;
$govuk-global-styles: true; $govuk-global-styles: true;
$govuk-new-link-styles: true;
@import "govuk-frontend-styles"; @import "govuk-frontend-styles";
@import "govuk-prototype-styles"; @import "govuk-prototype-styles";
@import "accessible-autocomplete"; @import "accessible-autocomplete";
@import "button"; @import "button";
@import "card";
@import "document-list";
@import "figure"; @import "figure";
@import "filter";
@import "filter-layout";
@import "header";
@import "input"; @import "input";
@import "related-navigation"; @import "related-navigation";
@import "section-skip-link"; @import "section-skip-link";
@import "tab-navigation";
@import "table-group"; @import "table-group";
@import "task-list"; @import "task-list";
@import "template"; @import "template";
@import "pagination"; @import "pagination";
@import "panel"; @import "panel";
@import "filter"; @import "primary-navigation";
// App utilities // App utilities
.app-\!-colour-muted { .app-\!-colour-muted {

26
app/models/bulk_upload.rb

@ -57,7 +57,6 @@ class BulkUpload
def map_row(row) def map_row(row)
{ {
lettype: row[1], lettype: row[1],
landlord: row[2],
# reg_num_la_core_code: row[3], # reg_num_la_core_code: row[3],
# managementgroup: row[4], # managementgroup: row[4],
# schemecode: row[5], # schemecode: row[5],
@ -67,8 +66,7 @@ class BulkUpload
tenancy: row[9], tenancy: row[9],
tenancyother: row[10], tenancyother: row[10],
# tenancyduration: row[11], # tenancyduration: row[11],
other_hhmemb: other_hhmemb(row), hhmemb: hhmemb(row),
hhmemb: other_hhmemb(row) + 1,
age1: row[12], age1: row[12],
age2: row[13], age2: row[13],
age3: row[14], age3: row[14],
@ -111,7 +109,7 @@ class BulkUpload
earnings: row[50], earnings: row[50],
# increfused: row[51], # increfused: row[51],
reason: row[52], reason: row[52],
other_reason_for_leaving_last_settled_home: row[53], reasonother: row[53],
underoccupation_benefitcap: row[54], underoccupation_benefitcap: row[54],
housingneeds_a: row[55], housingneeds_a: row[55],
housingneeds_b: row[56], housingneeds_b: row[56],
@ -121,11 +119,9 @@ class BulkUpload
housingneeds_h: row[60], housingneeds_h: row[60],
prevten: row[61], prevten: row[61],
prevloc: row[62], prevloc: row[62],
# ppostc1: row[63],
# ppostc2: row[64],
# prevpco_unknown: row[65], # prevpco_unknown: row[65],
layear: row[66], layear: row[66],
lawaitlist: row[67], waityear: row[67],
homeless: row[68], homeless: row[68],
reasonpref: row[69], reasonpref: row[69],
rp_homeless: row[70], rp_homeless: row[70],
@ -147,15 +143,9 @@ class BulkUpload
# no_rent_or_charge: row[86], # no_rent_or_charge: row[86],
hbrentshortfall: row[87], hbrentshortfall: row[87],
tshortfall: row[88], tshortfall: row[88],
property_void_date: row[89].to_s + row[90].to_s + row[91].to_s, voiddate: row[89].to_s + row[90].to_s + row[91].to_s,
# property_void_date_day: row[89],
# property_void_date_month: row[90],
# property_void_date_year: row[91],
majorrepairs: row[92].present? ? "1" : nil, majorrepairs: row[92].present? ? "1" : nil,
mrcdate: row[92].to_s + row[93].to_s + row[94].to_s, mrcdate: row[92].to_s + row[93].to_s + row[94].to_s,
mrcday: row[92],
mrcmonth: row[93],
mrcyear: row[94],
# supported_scheme: row[95], # supported_scheme: row[95],
startdate: date_time(row[98], row[97], row[96]), startdate: date_time(row[98], row[97], row[96]),
# startdate_day: row[96], # startdate_day: row[96],
@ -170,8 +160,6 @@ class BulkUpload
property_relet: row[105], property_relet: row[105],
rsnvac: row[106], rsnvac: row[106],
la: row[107], la: row[107],
# postcode: row[108],
# postcod2: row[109],
# row[110] removed # row[110] removed
# row[111] is owning organisation used above # row[111] is owning organisation used above
# username: row[112], # username: row[112],
@ -193,7 +181,7 @@ class BulkUpload
illness_type_10: row[128], illness_type_10: row[128],
# london_affordable: row[129], # london_affordable: row[129],
rent_type: row[130], rent_type: row[130],
intermediate_rent_product_name: row[131], irproduct_other: row[131],
# data_protection: row[132], # data_protection: row[132],
sale_or_letting: "letting", sale_or_letting: "letting",
declaration: 1, declaration: 1,
@ -206,7 +194,7 @@ class BulkUpload
Time.zone.local("20#{year}", month.to_s, day.to_s) Time.zone.local("20#{year}", month.to_s, day.to_s)
end end
def other_hhmemb(row) def hhmemb(row)
[13, 14, 15, 16, 17, 18, 19].count { |idx| row[idx].present? } [14, 15, 16, 17, 18, 19, 20].count { |idx| row[idx].present? }
end end
end end

137
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"
scope :for_organisation, ->(org) { where(owning_organisation: org).or(where(managing_organisation: org)) } scope :for_organisation, ->(org) { where(owning_organisation: org).or(where(managing_organisation: org)) }
scope :filter_by_status, ->(status, _user = nil) { where status: 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
query = filter_by_year(first_year) query = filter_by_year(first_year)
@ -100,7 +100,7 @@ class CaseLog < ApplicationRecord
elsif net_income_is_monthly? elsif net_income_is_monthly?
((earnings * 12) / 52.0).round(0) ((earnings * 12) / 52.0).round(0)
elsif net_income_is_yearly? elsif net_income_is_yearly?
(earnings / 12.0).round(0) (earnings / 52.0).round(0)
end end
end end
@ -122,19 +122,23 @@ class CaseLog < ApplicationRecord
end end
def net_income_refused? def net_income_refused?
# 2: Tenant prefers not to say
net_income_known == 2 net_income_known == 2
end end
def net_income_is_weekly? def net_income_is_weekly?
!!(incfreq && incfreq.zero?) # 1: Weekly
!!(incfreq && incfreq == 1)
end end
def net_income_is_monthly? def net_income_is_monthly?
incfreq == 1 # 2: Monthly
incfreq == 2
end end
def net_income_is_yearly? def net_income_is_yearly?
incfreq == 2 # 3: Yearly
incfreq == 3
end end
def net_income_soft_validation_triggered? def net_income_soft_validation_triggered?
@ -142,138 +146,181 @@ class CaseLog < ApplicationRecord
end end
def given_reasonable_preference? def given_reasonable_preference?
# 1: Yes
reasonpref == 1 reasonpref == 1
end end
def is_renewal? def is_renewal?
# 1: Yes
renewal == 1 renewal == 1
end end
def is_general_needs? def is_general_needs?
# 1: General Needs
needstype == 1 needstype == 1
end end
def is_supported_housing? def is_supported_housing?
!!(needstype && needstype.zero?) # 2: Supported Housing
needstype == 2
end end
def has_hbrentshortfall? def has_hbrentshortfall?
!!(hbrentshortfall && hbrentshortfall.zero?) # 0: Yes
!!hbrentshortfall&.zero?
end end
def postcode_known? def postcode_known?
# 1: Yes
postcode_known == 1 postcode_known == 1
end end
def previous_postcode_known? def previous_postcode_known?
# 1: Yes
previous_postcode_known == 1 previous_postcode_known == 1
end end
def la_known? def la_known?
# 1: Yes
la_known == 1 la_known == 1
end end
def previous_la_known? def previous_la_known?
# 1: Yes
previous_la_known == 1 previous_la_known == 1
end end
def is_secure_tenancy? def is_secure_tenancy?
tenancy == 3 # 1: Secure (including flexible)
tenancy == 1
end end
def is_assured_shorthold_tenancy? def is_assured_shorthold_tenancy?
tenancy == 1 # 4: Assured Shorthold
tenancy == 4
end end
def is_internal_transfer? def is_internal_transfer?
# 1: Internal Transfer
referral == 1 referral == 1
end end
def is_relet_to_temp_tenant? def is_relet_to_temp_tenant?
rsnvac == 2 # 9: Re-let to tenant who occupied same property as temporary accommodation
rsnvac == 9
end end
def is_bedsit? def is_bedsit?
unittype_gn == 1 # 2: Bedsit
unittype_gn == 2
end end
def is_shared_housing? def is_shared_housing?
[4, 5, 6].include?(unittype_gn) # 4: Shared flat or maisonette
# 9: Shared house
# 10: Shared bungalow
[4, 9, 10].include?(unittype_gn)
end end
def has_first_let_vacancy_reason? def has_first_let_vacancy_reason?
# 15: First let of new-build property
# 16: First let of conversion, rehabilitation or acquired property
# 17: First let of leased property
[15, 16, 17].include?(rsnvac) [15, 16, 17].include?(rsnvac)
end end
def previous_tenancy_was_temporary? def previous_tenancy_was_temporary?
![4, 5, 16, 21, 22].include?(prevten) # 4: Tied housing or renting with job
# 6: Supported housing
# 8: Sheltered accomodation
# 24: Housed by National Asylum Support Service (prev Home Office)
# 25: Other
![4, 6, 8, 24, 25].include?(prevten)
end end
def armed_forces_regular? def armed_forces_regular?
!!(armedforces && armedforces.zero?) # 1: Yes – the person is a current or former regular
!!(armedforces && armedforces == 1)
end end
def armed_forces_no? def armed_forces_no?
armedforces == 3 # 2: No
armedforces == 2
end end
def armed_forces_refused? def armed_forces_refused?
armedforces == 4 # 3: Person prefers not to say / Refused
armedforces == 3
end end
def has_pregnancy? def has_pregnancy?
!!(preg_occ && preg_occ.zero?) # 1: Yes
!!(preg_occ && preg_occ == 1)
end end
def pregnancy_refused? def pregnancy_refused?
preg_occ == 2 # 3: Tenant prefers not to say / Refused
preg_occ == 3
end end
def is_assessed_homeless? def is_assessed_homeless?
# 11: Assessed as homeless (or threatened with homelessness within 56 days) by a local authority and owed a homelessness duty
homeless == 11 homeless == 11
end end
def is_other_homeless? def is_other_homeless?
# 7: Other homeless – not found statutorily homeless but considered homeless by landlord
homeless == 7 homeless == 7
end end
def is_not_homeless? def is_not_homeless?
# 1: No
homeless == 1 homeless == 1
end end
def is_london_rent? def is_london_rent?
# 2: London Affordable Rent
# 4: London Living Rent
rent_type == 2 || rent_type == 4 rent_type == 2 || rent_type == 4
end end
def previous_tenancy_was_foster_care? def previous_tenancy_was_foster_care?
# 13: Children's home or foster care
prevten == 13 prevten == 13
end end
def previous_tenancy_was_refuge? def previous_tenancy_was_refuge?
# 21: Refuge
prevten == 21 prevten == 21
end end
def is_reason_permanently_decanted? def is_reason_permanently_decanted?
# 1: Permanently decanted from another property owned by this landlord
reason == 1 reason == 1
end end
def receives_housing_benefit_only? def receives_housing_benefit_only?
# 1: Housing benefit
hb == 1 hb == 1
end end
def receives_housing_benefit_and_universal_credit? def receives_housing_benefit_and_universal_credit?
# 8: Housing benefit and Universal Credit (without housing element)
hb == 8 hb == 8
end end
def receives_uc_with_housing_element_excl_housing_benefit? def receives_uc_with_housing_element_excl_housing_benefit?
# 6: Universal Credit with housing element (excluding housing benefit)
hb == 6 hb == 6
end end
def receives_no_benefits? def receives_no_benefits?
# 9: None
hb == 9 hb == 9
end end
def receives_universal_credit_but_no_housing_benefit? def receives_universal_credit_but_no_housing_benefit?
# 7: Universal Credit (without housing element)
hb == 7 hb == 7
end end
@ -283,22 +330,18 @@ class CaseLog < ApplicationRecord
end end
def benefits_unknown? def benefits_unknown?
# 3: Don’t know
hb == 3 hb == 3
end end
def this_landlord?
landlord == 1
end
def other_landlord?
landlord == 2
end
def local_housing_referral? def local_housing_referral?
# 3: PRP lettings only - Nominated by local housing authority
referral == 3 referral == 3
end end
def is_prevten_la_general_needs? def is_prevten_la_general_needs?
# 30: Fixed term Local Authority General Needs tenancy
# 31: Lifetime Local Authority General Needs tenancy
[30, 31].any?(prevten) [30, 31].any?(prevten)
end end
@ -379,30 +422,10 @@ private
end end
def set_derived_fields! def set_derived_fields!
if ppostcode_full.present?
self.ppostc1 = UKPostcode.parse(ppostcode_full).outcode
self.ppostc2 = UKPostcode.parse(ppostcode_full).incode
end
if mrcdate.present?
self.mrcday = mrcdate.day
self.mrcmonth = mrcdate.month
self.mrcyear = mrcdate.year
end
if startdate.present?
self.day = startdate.day
self.month = startdate.month
self.year = startdate.year
end
if property_void_date.present?
self.vday = property_void_date.day
self.vmonth = property_void_date.month
self.vyear = property_void_date.year
end
if rsnvac.present? if rsnvac.present?
self.newprop = has_first_let_vacancy_reason? ? 1 : 2 self.newprop = has_first_let_vacancy_reason? ? 1 : 2
end end
self.incref = 1 if net_income_refused? self.incref = 1 if net_income_refused?
self.other_hhmemb = hhmemb - 1 if hhmemb.present?
self.renttype = RENT_TYPE_MAPPING[rent_type] self.renttype = RENT_TYPE_MAPPING[rent_type]
self.lettype = get_lettype self.lettype = get_lettype
self.totchild = get_totchild self.totchild = get_totchild
@ -431,14 +454,14 @@ private
weekly_value(tshortfall) weekly_value(tshortfall)
end end
self.nocharge = household_charge&.zero? ? 1 : 0 self.nocharge = household_charge&.zero? ? 1 : 0
self.underoccupation_benefitcap = 3 if renewal == 1 && year == 2021
self.housingneeds = get_housingneeds self.housingneeds = get_housingneeds
if is_renewal? if is_renewal?
self.underoccupation_benefitcap = 2 if year == 2021 self.underoccupation_benefitcap = 2 if collection_start_year == 2021
self.homeless = 2 self.homeless = 2
self.referral = 0 self.referral = 0
self.layear = 1 self.layear = 1
if is_general_needs? if is_general_needs?
# fixed term
self.prevten = 32 if managing_organisation.provider_type == "PRP" self.prevten = 32 if managing_organisation.provider_type == "PRP"
self.prevten = 30 if managing_organisation.provider_type == "LA" self.prevten = 30 if managing_organisation.provider_type == "LA"
end end
@ -450,47 +473,41 @@ private
self["ecstat#{idx}"] = nil self["ecstat#{idx}"] = nil
end end
end end
self.landlord = 1 if owning_organisation.provider_type == "LA"
self.landlord = 2 if owning_organisation.provider_type == "PRP"
end end
def process_postcode_changes! def process_postcode_changes!
self.postcode_full = postcode_full.present? ? postcode_full.upcase.gsub(/\s+/, "") : postcode_full self.postcode_full = postcode_full.present? ? postcode_full.upcase.gsub(/\s+/, "") : postcode_full
process_postcode(postcode_full, "postcode_known", "is_la_inferred", "la", "postcode", "postcod2") process_postcode(postcode_full, "postcode_known", "is_la_inferred", "la")
end end
def process_previous_postcode_changes! def process_previous_postcode_changes!
self.ppostcode_full = ppostcode_full.present? ? ppostcode_full.upcase.gsub(/\s+/, "") : ppostcode_full self.ppostcode_full = ppostcode_full.present? ? ppostcode_full.upcase.gsub(/\s+/, "") : ppostcode_full
process_postcode(ppostcode_full, "previous_postcode_known", "is_previous_la_inferred", "prevloc", "ppostc1", "ppostc2") process_postcode(ppostcode_full, "previous_postcode_known", "is_previous_la_inferred", "prevloc")
end end
def process_postcode(postcode, postcode_known_key, la_inferred_key, la_key, outcode_key, incode_key) def process_postcode(postcode, postcode_known_key, la_inferred_key, la_key)
return if postcode.blank? return if postcode.blank?
self[postcode_known_key] = 1 self[postcode_known_key] = 1
inferred_la = get_inferred_la(postcode) inferred_la = get_inferred_la(postcode)
self[la_inferred_key] = inferred_la.present? self[la_inferred_key] = inferred_la.present?
self[la_key] = inferred_la if inferred_la.present? self[la_key] = inferred_la if inferred_la.present?
self[outcode_key] = UKPostcode.parse(postcode).outcode
self[incode_key] = UKPostcode.parse(postcode).incode
end end
def reset_location_fields! def reset_location_fields!
reset_location(is_la_inferred, "la", "is_la_inferred", "postcode_full", "postcode", "postcod2", la_known) reset_location(is_la_inferred, "la", "is_la_inferred", "postcode_full", la_known)
end end
def reset_previous_location_fields! def reset_previous_location_fields!
reset_location(is_previous_la_inferred, "prevloc", "is_previous_la_inferred", "ppostcode_full", "ppostc1", "ppostc2", previous_la_known) reset_location(is_previous_la_inferred, "prevloc", "is_previous_la_inferred", "ppostcode_full", previous_la_known)
end end
def reset_location(is_inferred, la_key, is_inferred_key, postcode_key, incode_key, outcode_key, is_la_known) def reset_location(is_inferred, la_key, is_inferred_key, postcode_key, is_la_known)
if is_inferred || is_la_known != 1 if is_inferred || is_la_known != 1
self[la_key] = nil self[la_key] = nil
end end
self[is_inferred_key] = false self[is_inferred_key] = false
self[postcode_key] = nil self[postcode_key] = nil
self[incode_key] = nil
self[outcode_key] = nil
end end
def get_totelder def get_totelder

24
app/models/form/question.rb

@ -226,9 +226,9 @@ private
end end
ANSWER_SUFFIX_LABELS = { ANSWER_SUFFIX_LABELS = {
0 => " every week", 1 => " every week",
1 => " every month", 2 => " every month",
2 => " every year", 3 => " every year",
}.freeze }.freeze
RADIO_YES_VALUE = { RADIO_YES_VALUE = {
@ -242,11 +242,11 @@ private
majorrepairs: [1], majorrepairs: [1],
startertenancy: [0], startertenancy: [0],
letting_in_sheltered_accommodation: [0, 1], letting_in_sheltered_accommodation: [0, 1],
armedforces: [0, 1, 2], armedforces: [1, 4, 5],
leftreg: [0], leftreg: [0],
reservist: [0], reservist: [0],
preg_occ: [0], preg_occ: [1],
illness: [0], illness: [1],
underoccupation_benefitcap: [4, 5, 6], underoccupation_benefitcap: [4, 5, 6],
reasonpref: [1], reasonpref: [1],
net_income_known: [0], net_income_known: [0],
@ -267,11 +267,11 @@ private
majorrepairs: [0], majorrepairs: [0],
startertenancy: [1], startertenancy: [1],
letting_in_sheltered_accommodation: [2], letting_in_sheltered_accommodation: [2],
armedforces: [3], armedforces: [2],
leftreg: [1], leftreg: [1],
reservist: [1], reservist: [1],
preg_occ: [1], preg_occ: [2],
illness: [1], illness: [2],
underoccupation_benefitcap: [2], underoccupation_benefitcap: [2],
reasonpref: [2], reasonpref: [2],
net_income_known: [1], net_income_known: [1],
@ -291,6 +291,7 @@ private
hb: [5], hb: [5],
benefits: [3], benefits: [3],
unitletas: [3], unitletas: [3],
illness: [3],
}.freeze }.freeze
RADIO_REFUSED_VALUE = { RADIO_REFUSED_VALUE = {
@ -318,11 +319,10 @@ private
ecstat7: [10], ecstat7: [10],
ecstat8: [10], ecstat8: [10],
letting_in_sheltered_accommodation: [3], letting_in_sheltered_accommodation: [3],
armedforces: [4], armedforces: [3],
leftreg: [3], leftreg: [3],
reservist: [2], reservist: [2],
preg_occ: [2], preg_occ: [3],
illness: [2],
hb: [6], hb: [6],
}.freeze }.freeze
end end

12
app/models/validations/date_validations.rb

@ -15,16 +15,16 @@ module Validations::DateValidations
end end
def validate_property_void_date(record) def validate_property_void_date(record)
if record["property_void_date"].present? && record["startdate"].present? && record["startdate"].to_date - record["property_void_date"].to_date > 3650 if record["voiddate"].present? && record["startdate"].present? && record["startdate"].to_date - record["voiddate"].to_date > 3650
record.errors.add :property_void_date, I18n.t("validations.property.void_date.ten_years_before_tenancy_start") record.errors.add :voiddate, I18n.t("validations.property.void_date.ten_years_before_tenancy_start")
end end
if record["property_void_date"].present? && record["startdate"].present? && record["startdate"].to_date < record["property_void_date"].to_date if record["voiddate"].present? && record["startdate"].present? && record["startdate"].to_date < record["voiddate"].to_date
record.errors.add :property_void_date, I18n.t("validations.property.void_date.before_tenancy_start") record.errors.add :voiddate, I18n.t("validations.property.void_date.before_tenancy_start")
end end
if record["property_void_date"].present? && record["mrcdate"].present? && record["mrcdate"].to_date < record["property_void_date"].to_date if record["voiddate"].present? && record["mrcdate"].present? && record["mrcdate"].to_date < record["voiddate"].to_date
record.errors.add :property_void_date, I18n.t("validations.property.void_date.after_mrcdate") record.errors.add :voiddate, I18n.t("validations.property.void_date.after_mrcdate")
end end
end end

21
app/models/validations/financial_validations.rb

@ -84,46 +84,47 @@ private
CHARGE_MAXIMUMS = { CHARGE_MAXIMUMS = {
scharge: { scharge: {
this_landlord: { private_registered_provider: {
general_needs: 55, general_needs: 55,
supported_housing: 280, supported_housing: 280,
}, },
other_landlord: { local_authority: {
general_needs: 45, general_needs: 45,
supported_housing: 165, supported_housing: 165,
}, },
}, },
pscharge: { pscharge: {
this_landlord: { private_registered_provider: {
general_needs: 30, general_needs: 30,
supported_housing: 200, supported_housing: 200,
}, },
other_landlord: { local_authority: {
general_needs: 35, general_needs: 35,
supported_housing: 75, supported_housing: 75,
}, },
}, },
supcharg: { supcharg: {
this_landlord: { private_registered_provider: {
general_needs: 40, general_needs: 40,
supported_housing: 465, supported_housing: 465,
}, },
other_landlord: { local_authority: {
general_needs: 60, general_needs: 60,
supported_housing: 120, supported_housing: 120,
}, },
}, },
}.freeze }.freeze
LANDLORD_VALUES = { 1 => :this_landlord, 2 => :other_landlord }.freeze PROVIDER_TYPE = { 1 => :local_authority, 2 => :private_registered_provider }.freeze
NEEDSTYPE_VALUES = { 0 => :supported_housing, 1 => :general_needs }.freeze NEEDSTYPE_VALUES = { 2 => :supported_housing, 1 => :general_needs }.freeze
def validate_charges(record) def validate_charges(record)
provider_type = record.owning_organisation.provider_type_before_type_cast
%i[scharge pscharge supcharg].each do |charge| %i[scharge pscharge supcharg].each do |charge|
maximum = CHARGE_MAXIMUMS.dig(charge, LANDLORD_VALUES[record.landlord], NEEDSTYPE_VALUES[record.needstype]) maximum = CHARGE_MAXIMUMS.dig(charge, PROVIDER_TYPE[provider_type], NEEDSTYPE_VALUES[record.needstype])
if maximum.present? && record[:period].present? && record[charge].present? && !weekly_value_in_range(record, charge, 0.0, maximum) if maximum.present? && record[:period].present? && record[charge].present? && !weekly_value_in_range(record, charge, 0.0, maximum)
record.errors.add charge, I18n.t("validations.financial.rent.#{charge}.#{LANDLORD_VALUES[record.landlord]}.#{NEEDSTYPE_VALUES[record.needstype]}") record.errors.add charge, I18n.t("validations.financial.rent.#{charge}.#{PROVIDER_TYPE[provider_type]}.#{NEEDSTYPE_VALUES[record.needstype]}")
end end
end end
end end

10
app/models/validations/household_validations.rb

@ -18,7 +18,7 @@ module Validations::HouseholdValidations
record.errors.add :underoccupation_benefitcap, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required") record.errors.add :underoccupation_benefitcap, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required")
record.errors.add :reason, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required") record.errors.add :reason, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required")
end end
validate_other_field(record, 31, :reason, :other_reason_for_leaving_last_settled_home) validate_other_field(record, 31, :reason, :reasonother)
if record.is_reason_permanently_decanted? && record.referral.present? && !record.is_internal_transfer? if record.is_reason_permanently_decanted? && record.referral.present? && !record.is_internal_transfer?
record.errors.add :referral, I18n.t("validations.household.referral.reason_permanently_decanted") record.errors.add :referral, I18n.t("validations.household.referral.reason_permanently_decanted")
@ -56,7 +56,7 @@ module Validations::HouseholdValidations
end end
def validate_accessibility_requirements(record) def validate_accessibility_requirements(record)
all_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c, record.housingneeds_f, record.housingneeds_g, record.housingneeds_h, record.accessibility_requirements_prefer_not_to_say] all_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c, record.housingneeds_f, record.housingneeds_g, record.housingneeds_h]
if all_options.count(1) > 1 if all_options.count(1) > 1
mobility_accessibility_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c] mobility_accessibility_options = [record.housingneeds_a, record.housingneeds_b, record.housingneeds_c]
unless all_options.count(1) == 2 && record.housingneeds_f == 1 && mobility_accessibility_options.any? { |x| x == 1 } unless all_options.count(1) == 2 && record.housingneeds_f == 1 && mobility_accessibility_options.any? { |x| x == 1 }
@ -105,12 +105,12 @@ module Validations::HouseholdValidations
record.errors.add :homeless, I18n.t("validations.household.homeless.other.internal_transfer") record.errors.add :homeless, I18n.t("validations.household.homeless.other.internal_transfer")
end end
if record.is_internal_transfer? && record.this_landlord? && record.is_prevten_la_general_needs? if record.is_internal_transfer? && record.owning_organisation.provider_type == "PRP" && record.is_prevten_la_general_needs?
record.errors.add :referral, I18n.t("validations.household.referral.la_general_needs.internal_transfer") record.errors.add :referral, I18n.t("validations.household.referral.la_general_needs.internal_transfer")
record.errors.add :prevten, I18n.t("validations.household.prevten.la_general_needs.internal_transfer") record.errors.add :prevten, I18n.t("validations.household.prevten.la_general_needs.internal_transfer")
end end
if record.other_landlord? && record.local_housing_referral? if record.owning_organisation.provider_type == "LA" && record.local_housing_referral?
record.errors.add :referral, I18n.t("validations.household.referral.prp.local_housing_referral") record.errors.add :referral, I18n.t("validations.household.referral.prp.local_housing_referral")
end end
end end
@ -124,7 +124,7 @@ module Validations::HouseholdValidations
private private
def household_no_illness?(record) def household_no_illness?(record)
record.illness != 0 record.illness != 1
end end
def women_of_child_bearing_age_in_household(record) def women_of_child_bearing_age_in_household(record)

2
app/models/validations/property_validations.rb

@ -112,7 +112,7 @@ module Validations::PropertyValidations
record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit") record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit")
end end
if record.other_hhmemb&.zero? && record.is_shared_housing? && if record.hhmemb == 1 && record.is_shared_housing? &&
!record.beds.to_i.between?(1, 3) && record.beds.present? !record.beds.to_i.between?(1, 3) && record.beds.present?
record.errors.add :unittype_gn, I18n.t("validations.property.unittype_gn.one_three_bedroom_single_tenant_shared") record.errors.add :unittype_gn, I18n.t("validations.property.unittype_gn.one_three_bedroom_single_tenant_shared")
record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_three_bedroom_single_tenant_shared") record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_three_bedroom_single_tenant_shared")

6
app/models/validations/setup_validations.rb

@ -1,7 +1,7 @@
module Validations::SetupValidations module Validations::SetupValidations
def validate_intermediate_rent_product_name(record) def validate_irproduct_other(record)
if intermediate_product_rent_type?(record) && record.intermediate_rent_product_name.blank? if intermediate_product_rent_type?(record) && record.irproduct_other.blank?
record.errors.add :intermediate_rent_product_name, I18n.t("validations.setup.intermediate_rent_product_name.blank") record.errors.add :irproduct_other, I18n.t("validations.setup.intermediate_rent_product_name.blank")
end end
end end

2
app/models/validations/tenancy_validations.rb

@ -30,6 +30,6 @@ module Validations::TenancyValidations
end end
def validate_other_tenancy_type(record) def validate_other_tenancy_type(record)
validate_other_field(record, 4, :tenancy, :tenancyother) validate_other_field(record, 3, :tenancy, :tenancyother)
end end
end end

392
app/services/imports/case_logs_import_service.rb

@ -0,0 +1,392 @@
module Imports
class CaseLogsImportService < ImportService
def create_logs(folder)
import_from(folder, :create_log)
end
private
GN_SH = {
general_needs: 1,
supported_housing: 2,
}.freeze
SR_AR_IR = {
social_rent: 1,
affordable_rent: 2,
intermediate_rent: 3,
}.freeze
# For providertype, values are reversed!!!
PRP_LA = {
private_registered_provider: 1,
local_authority: 2,
}.freeze
IRPRODUCT = {
rent_to_buy: 1,
london_living_rent: 2,
other_intermediate_rent_product: 3,
}.freeze
# These must match our form
RENT_TYPE = {
social_rent: 0,
affordable_rent: 1,
london_affordable_rent: 2,
rent_to_buy: 3,
london_living_rent: 4,
other_intermediate_rent_product: 5,
}.freeze
def create_log(xml_doc)
attributes = {}
# Required fields for status complete or logic to work
# Note: order matters when we derive from previous values (attributes parameter)
attributes["startdate"] = compose_date(xml_doc, "DAY", "MONTH", "YEAR")
attributes["owning_organisation_id"] = find_organisation_id(xml_doc, "OWNINGORGID", "OWNINGORGNAME", "HCNUM")
attributes["managing_organisation_id"] = find_organisation_id(xml_doc, "MANINGORGID", "MANINGORGNAME", "MANHCNUM")
attributes["startertenancy"] = unsafe_string_as_integer(xml_doc, "_2a")
attributes["tenancy"] = unsafe_string_as_integer(xml_doc, "Q2b")
attributes["tenancyother"] = string_or_nil(xml_doc, "Q2ba")
attributes["tenancylength"] = safe_string_as_integer(xml_doc, "_2cYears")
attributes["needstype"] = needs_type(xml_doc)
attributes["lar"] = london_affordable_rent(xml_doc)
attributes["irproduct"] = unsafe_string_as_integer(xml_doc, "IRProduct")
attributes["irproduct_other"] = string_or_nil(xml_doc, "IRProductOther")
attributes["rent_type"] = rent_type(xml_doc, attributes["lar"], attributes["irproduct"])
attributes["hhmemb"] = safe_string_as_integer(xml_doc, "HHMEMB")
(1..8).each do |index|
attributes["age#{index}"] = safe_string_as_integer(xml_doc, "P#{index}Age")
attributes["age#{index}_known"] = age_known(xml_doc, index, attributes["hhmemb"])
attributes["sex#{index}"] = sex(xml_doc, index)
attributes["ecstat#{index}"] = unsafe_string_as_integer(xml_doc, "P#{index}Eco")
end
(2..8).each do |index|
attributes["relat#{index}"] = relat(xml_doc, index)
end
attributes["ethnic"] = unsafe_string_as_integer(xml_doc, "P1Eth")
attributes["ethnic_group"] = ethnic_group(attributes["ethnic"])
attributes["national"] = unsafe_string_as_integer(xml_doc, "P1Nat")
attributes["preg_occ"] = unsafe_string_as_integer(xml_doc, "Preg")
attributes["armedforces"] = unsafe_string_as_integer(xml_doc, "ArmedF")
attributes["leftreg"] = unsafe_string_as_integer(xml_doc, "LeftAF")
attributes["reservist"] = unsafe_string_as_integer(xml_doc, "Inj")
attributes["hb"] = unsafe_string_as_integer(xml_doc, "Q6Ben")
attributes["benefits"] = unsafe_string_as_integer(xml_doc, "Q7Ben")
attributes["earnings"] = safe_string_as_decimal(xml_doc, "Q8Money")
attributes["net_income_known"] = net_income_known(xml_doc, attributes["earnings"])
attributes["incfreq"] = unsafe_string_as_integer(xml_doc, "Q8a")
attributes["reason"] = unsafe_string_as_integer(xml_doc, "Q9a")
attributes["reasonother"] = string_or_nil(xml_doc, "Q9aa")
attributes["underoccupation_benefitcap"] = unsafe_string_as_integer(xml_doc, "_9b")
%w[a b c f g h].each do |letter|
attributes["housingneeds_#{letter}"] = housing_needs(xml_doc, letter)
end
attributes["illness"] = unsafe_string_as_integer(xml_doc, "Q10ia")
(1..10).each do |index|
attributes["illness_type_#{index}"] = illness_type(xml_doc, index)
end
attributes["prevten"] = unsafe_string_as_integer(xml_doc, "Q11")
attributes["prevloc"] = string_or_nil(xml_doc, "Q12aONS")
attributes["previous_postcode_known"] = previous_postcode_known(xml_doc)
attributes["ppostcode_full"] = compose_postcode(xml_doc, "PPOSTC1", "PPOSTC2")
attributes["layear"] = unsafe_string_as_integer(xml_doc, "Q12c")
attributes["waityear"] = unsafe_string_as_integer(xml_doc, "Q12d")
attributes["homeless"] = unsafe_string_as_integer(xml_doc, "Q13")
attributes["reasonpref"] = unsafe_string_as_integer(xml_doc, "Q14a")
attributes["rp_homeless"] = unsafe_string_as_integer(xml_doc, "Q14b1")
attributes["rp_insan_unsat"] = unsafe_string_as_integer(xml_doc, "Q14b2")
attributes["rp_medwel"] = unsafe_string_as_integer(xml_doc, "Q14b3")
attributes["rp_hardship"] = unsafe_string_as_integer(xml_doc, "Q14b4")
attributes["rp_dontknow"] = unsafe_string_as_integer(xml_doc, "Q14b5")
attributes["cbl"] = unsafe_string_as_integer(xml_doc, "Q15CBL")
attributes["chr"] = unsafe_string_as_integer(xml_doc, "Q15CHR")
attributes["cap"] = unsafe_string_as_integer(xml_doc, "Q15CAP")
attributes["referral"] = unsafe_string_as_integer(xml_doc, "Q16")
attributes["period"] = unsafe_string_as_integer(xml_doc, "Q17")
attributes["brent"] = safe_string_as_decimal(xml_doc, "Q18ai")
attributes["scharge"] = safe_string_as_decimal(xml_doc, "Q18aii")
attributes["pscharge"] = safe_string_as_decimal(xml_doc, "Q18aiii")
attributes["supcharg"] = safe_string_as_decimal(xml_doc, "Q18aiv")
attributes["tcharge"] = safe_string_as_decimal(xml_doc, "Q18av")
attributes["hbrentshortfall"] = unsafe_string_as_integer(xml_doc, "Q18d")
attributes["voiddate"] = compose_date(xml_doc, "VDAY", "VMONTH", "VYEAR")
attributes["mrcdate"] = compose_date(xml_doc, "MRCDAY", "MRCMONTH", "MRCYEAR")
attributes["offered"] = safe_string_as_integer(xml_doc, "Q20")
attributes["propcode"] = string_or_nil(xml_doc, "Q21a")
attributes["beds"] = safe_string_as_integer(xml_doc, "Q22")
attributes["unittype_gn"] = unsafe_string_as_integer(xml_doc, "Q23")
attributes["builtype"] = unsafe_string_as_integer(xml_doc, "Q24")
attributes["wchair"] = unsafe_string_as_integer(xml_doc, "Q25")
attributes["unitletas"] = unsafe_string_as_integer(xml_doc, "Q26")
attributes["rsnvac"] = unsafe_string_as_integer(xml_doc, "Q27")
attributes["renewal"] = renewal(attributes["rsnvac"])
attributes["la"] = string_or_nil(xml_doc, "Q28ONS")
attributes["postcode_full"] = compose_postcode(xml_doc, "POSTCODE", "POSTCOD2")
attributes["postcode_known"] = attributes["postcode_full"].nil? ? 0 : 1
# Not specific to our form but required for CDS and can't be inferred
attributes["old_form_id"] = Integer(field_value(xml_doc, "xmlns", "FORM"))
# Specific to us
attributes["previous_la_known"] = 1 # Defaulting to Yes (Required)
attributes["la_known"] = 1 # Defaulting to Yes (Required)
attributes["created_at"] = Date.parse(field_value(xml_doc, "meta", "created-date"))
attributes["updated_at"] = Date.parse(field_value(xml_doc, "meta", "modified-date"))
case_log = CaseLog.new(attributes)
case_log.save!
end
# Safe: A string that represents only an integer (or empty/nil)
def safe_string_as_integer(xml_doc, attribute)
str = field_value(xml_doc, "xmlns", attribute)
Integer(str, exception: false)
end
# Safe: A string that represents only a decimal (or empty/nil)
def safe_string_as_decimal(xml_doc, attribute)
str = field_value(xml_doc, "xmlns", attribute)
BigDecimal(str, exception: false)
end
# Unsafe: A string that has more than just the integer value
def unsafe_string_as_integer(xml_doc, attribute)
str = field_value(xml_doc, "xmlns", attribute)
if str.blank?
nil
else
str.to_i
end
end
def compose_date(xml_doc, day_str, month_str, year_str)
day = Integer(field_value(xml_doc, "xmlns", day_str), exception: false)
month = Integer(field_value(xml_doc, "xmlns", month_str), exception: false)
year = Integer(field_value(xml_doc, "xmlns", year_str), exception: false)
if day.nil? || month.nil? || year.nil?
nil
else
Date.new(year, month, day)
end
end
def get_form_name_component(xml_doc, index)
form_name = field_value(xml_doc, "meta", "form-name")
form_type_components = form_name.split("-")
form_type_components[index]
end
def needs_type(xml_doc)
gn_sh = get_form_name_component(xml_doc, -1)
case gn_sh
when "GN"
GN_SH[:general_needs]
when "SH"
GN_SH[:supported_housing]
else
raise "Unknown needstype value: #{gn_sh}"
end
end
# This does not match renttype (CDS) which is derived by case log logic
def rent_type(xml_doc, lar, irproduct)
sr_ar_ir = get_form_name_component(xml_doc, -2)
case sr_ar_ir
when "SR"
RENT_TYPE[:social_rent]
when "AR"
if lar == 1
RENT_TYPE[:london_affordable_rent]
else
RENT_TYPE[:affordable_rent]
end
when "IR"
if irproduct == IRPRODUCT[:rent_to_buy]
RENT_TYPE[:rent_to_buy]
elsif irproduct == IRPRODUCT[:london_living_rent]
RENT_TYPE[:london_living_rent]
elsif irproduct == IRPRODUCT[:other_intermediate_rent_product]
RENT_TYPE[:other_intermediate_rent_product]
end
else
raise "Could not infer rent type with '#{sr_ar_ir}'"
end
end
def find_organisation_id(xml_doc, id_field, name_field, reg_field)
old_visible_id = unsafe_string_as_integer(xml_doc, id_field)
organisation = Organisation.find_by(old_visible_id:)
# Quick hack: should be removed when all organisations are imported
# Will fail in the future if the organisation is missing
if organisation.nil?
organisation = Organisation.new
organisation.old_visible_id = old_visible_id
let_type = unsafe_string_as_integer(xml_doc, "landlord")
organisation.provider_type = if let_type == PRP_LA[:local_authority]
1
else
2
end
organisation.name = string_or_nil(xml_doc, name_field)
organisation.housing_registration_no = string_or_nil(xml_doc, reg_field)
organisation.save!
end
organisation.id
end
def sex(xml_doc, index)
sex = field_value(xml_doc, "xmlns", "P#{index}Sex")
case sex
when "Male"
"M"
when "Female"
"F"
when "Other", "Non-binary"
"X"
when "Refused"
"R"
end
end
def relat(xml_doc, index)
relat = field_value(xml_doc, "xmlns", "P#{index}Rel")
case relat
when "Child"
"C"
when "Partner"
"P"
when "Other", "Non-binary"
"X"
when "Refused"
"R"
end
end
def age_known(xml_doc, index, hhmemb)
return nil if index > hhmemb
age_refused = field_value(xml_doc, "xmlns", "P#{index}AR")
if age_refused == "AGE_REFUSED"
1 # No
else
0 # Yes
end
end
def previous_postcode_known(xml_doc)
previous_postcode_known = field_value(xml_doc, "xmlns", "Q12bnot")
if previous_postcode_known == "Temporary or Unknown"
0
else
1
end
end
def compose_postcode(xml_doc, outcode, incode)
outcode_value = field_value(xml_doc, "xmlns", outcode)
incode_value = field_value(xml_doc, "xmlns", incode)
if outcode_value.blank? || incode_value.blank?
nil
else
"#{outcode_value} #{incode_value}"
end
end
def london_affordable_rent(xml_doc)
lar = unsafe_string_as_integer(xml_doc, "LAR")
if lar == 1
1
else
# We default to No for any other values (nil, not known)
2
end
end
def renewal(rsnvac)
# Relet – renewal of fixed-term tenancy
if rsnvac == 14
1
else
0
end
end
def string_or_nil(xml_doc, attribute)
str = field_value(xml_doc, "xmlns", attribute)
str.presence
end
def ethnic_group(ethnic)
case ethnic
when 1, 2, 3, 18
# White
0
when 4, 5, 6, 7
# Mixed
1
when 8, 9, 10, 11, 15
# Asian
2
when 12, 13, 14
# Black
3
when 16, 19
# Others
4
when 17
# Refused
5
end
end
# Letters should be lowercase to match case
def housing_needs(xml_doc, letter)
housing_need = field_value(xml_doc, "xmlns", "Q10-#{letter}")
if housing_need == "Yes"
1
else
0
end
end
def net_income_known(xml_doc, earnings)
incref = field_value(xml_doc, "xmlns", "Q8Refused")
if incref == "Refused"
# Tenant prefers not to say
2
elsif earnings.nil?
# No
1
else
# Yes
0
end
end
def illness_type(xml_doc, index)
illness_type = string_or_nil(xml_doc, "Q10ib-#{index}")
if illness_type == "Yes"
1
else
0
end
end
end
end

15
app/views/case_logs/_log_filters.erb

@ -1,25 +1,16 @@
<div class="app-filter-layout__filter" tabindex="-1" id="filter-panel"> <div class="app-filter-layout__filter">
<div class="app-filter" > <div class="app-filter">
<div class="app-filter__header"> <div class="app-filter__header">
<h2 class="govuk-heading-m">Filters</h2> <h2 class="govuk-heading-m">Filters</h2>
<button
class="app-filter__close"
type="button"
data-controller="filter"
data-action="click->filter#toggleFilter">
Close
</button>
</div> </div>
<div class="app-filter__content"> <div class="app-filter__content">
<div class="govuk-form-group app-filter__group">
<%= 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"} %>
<%= 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/checkbox_filter", locals: { f: f, options: {"all": "All", "yours": "Yours"}, label: "Logs", category: "user" } %> <%= render partial: "filters/checkbox_filter", locals: { f: f, options: {"all": "All", "yours": "Yours"}, label: "Logs", category: "user" } %>
<%= f.govuk_submit "Apply filters", class: "govuk-!-margin-top-4" %> <%= f.govuk_submit "Apply filters", class: "govuk-!-margin-bottom-0" %>
<% end %> <% end %>
</div> </div>
</div> </div>
</div>
</div> </div>

11
app/views/case_logs/_log_list.html.erb

@ -28,21 +28,21 @@
<%= govuk_link_to log.id, case_log_path(log) %> <%= govuk_link_to log.id, case_log_path(log) %>
</th> </th>
<td class="govuk-table__cell app-!-font-tabular"> <td class="govuk-table__cell app-!-font-tabular">
<%= log.tenant_code? ? log.tenant_code : '–' %> <%= log.tenant_code? ? log.tenant_code : "–" %>
</td> </td>
<td class="govuk-table__cell app-!-font-tabular"> <td class="govuk-table__cell app-!-font-tabular">
<%= log.propcode? ? log.propcode : '–' %> <%= log.propcode? ? log.propcode : "–" %>
</td> </td>
<td class="govuk-table__cell"> <td class="govuk-table__cell">
<%= log.startdate.present? ? log.startdate.to_formatted_s(:govuk_date) : '–' %> <%= log.startdate.present? ? log.startdate.to_formatted_s(:govuk_date) : "–" %>
</td> </td>
<td class="govuk-table__cell"> <td class="govuk-table__cell">
<%= log.created_at.to_formatted_s(:govuk_date) %> <%= log.created_at.to_formatted_s(:govuk_date) %>
</td> </td>
<td class="govuk-table__cell"> <td class="govuk-table__cell">
<%= govuk_tag( <%= govuk_tag(
colour: log.status == 'completed' ? 'blue' : 'grey', colour: log.status == "completed" ? "blue" : "grey",
text: log.status.humanize text: log.status.humanize,
) %> ) %>
</td> </td>
<% if current_user.support? %> <% if current_user.support? %>
@ -59,4 +59,3 @@
</table> </table>
</section> </section>
</figure> </figure>

3
app/views/case_logs/bulk_upload.html.erb

@ -5,8 +5,7 @@
<%= f.govuk_file_field :case_log_bulk_upload, <%= f.govuk_file_field :case_log_bulk_upload,
label: { text: content_for(:title), size: "l" }, label: { text: content_for(:title), size: "l" },
hint: { text: "Upload a spreadsheet using the template" } hint: { text: "Upload a spreadsheet using the template" } %>
%>
<%= f.govuk_submit "Upload" %> <%= f.govuk_submit "Upload" %>
<% end %> <% end %>

2
app/views/case_logs/edit.html.erb

@ -1,7 +1,7 @@
<% content_for :title, "Log #{@case_log.id}" %> <% content_for :title, "Log #{@case_log.id}" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Logs" => "/logs", "Logs" => "/logs",
content_for(:title) => "" content_for(:title) => "",
}) %> }) %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">

19
app/views/case_logs/index.html.erb

@ -3,28 +3,17 @@
<h1 class="govuk-heading-l"> <h1 class="govuk-heading-l">
<%= content_for(:title) %> <%= content_for(:title) %>
</h1> </h1>
<div class="app-filter-layout" data-module="filter-layout" data-module-started="true"> <div class="app-filter-layout" data-controller="filter-layout">
<div class="govuk-button-group"> <div class="govuk-button-group app-filter-toggle">
<button
aria-expanded="true"
aria-has-popup="true"
class="govuk-button govuk-button--secondary app-filter-toggle__button"
type="button"
id="toggle-filter-button"
data-controller="filter"
data-action="click->filter#toggleFilter"
>Show filters
</button>
<%= govuk_button_to "Create a new lettings log", case_logs_path %> <%= govuk_button_to "Create a new lettings log", case_logs_path %>
<%#= govuk_link_to "Upload logs", bulk_upload_case_logs_path %> <%#= govuk_link_to "Upload logs", bulk_upload_case_logs_path %>
</div> </div>
<%= render partial: "log_filters"%> <%= render partial: "log_filters" %>
<% if @case_logs.present? %> <% if @case_logs.present? %>
<div class="app-filter-layout__content"> <div class="app-filter-layout__content">
<%= render partial: "log_list", locals: { case_logs: @case_logs, title: "Logs", pagy: @pagy } %> <%= render partial: "log_list", locals: { case_logs: @case_logs, title: "Logs", pagy: @pagy } %>
<%== render partial: 'pagy/nav', locals: { pagy: @pagy, item_name: "logs" } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "logs" } %>
</div> </div>
<% end %> <% end %>
</div> </div>

3
app/views/devise/confirmations/new.html.erb

@ -7,8 +7,7 @@
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false", spellcheck: "false",
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
%>
<%= f.govuk_submit "Resend confirmation instructions" %> <%= f.govuk_submit "Resend confirmation instructions" %>
<% end %> <% end %>

8
app/views/devise/passwords/edit.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -19,12 +19,10 @@
<%= f.govuk_password_field :password, <%= f.govuk_password_field :password,
label: { text: "New password" }, label: { text: "New password" },
hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil, hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil,
autocomplete: "new-password" autocomplete: "new-password" %>
%>
<%= f.govuk_password_field :password_confirmation, <%= f.govuk_password_field :password_confirmation,
label: { text: "Confirm new password" } label: { text: "Confirm new password" } %>
%>
<%= f.govuk_submit "Update" %> <%= f.govuk_submit "Update" %>
</div> </div>

5
app/views/devise/passwords/new.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -22,8 +22,7 @@
<%= f.govuk_email_field :email, <%= f.govuk_email_field :email,
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false" spellcheck: "false" %>
%>
<%= f.govuk_submit "Send email" %> <%= f.govuk_submit "Send email" %>
</div> </div>

8
app/views/devise/passwords/reset_password.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -20,12 +20,10 @@
<%= f.govuk_password_field :password, <%= f.govuk_password_field :password,
label: { text: "New password" }, label: { text: "New password" },
hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil, hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil,
autocomplete: "new-password" autocomplete: "new-password" %>
%>
<%= f.govuk_password_field :password_confirmation, <%= f.govuk_password_field :password_confirmation,
label: { text: "Confirm new password" } label: { text: "Confirm new password" } %>
%>
<%= f.govuk_submit "Update" %> <%= f.govuk_submit "Update" %>
</div> </div>

6
app/views/devise/sessions/new.html.erb

@ -19,12 +19,10 @@
<%= f.govuk_email_field :email, <%= f.govuk_email_field :email,
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false" spellcheck: "false" %>
%>
<%= f.govuk_password_field :password, <%= f.govuk_password_field :password,
autocomplete: "current-password" autocomplete: "current-password" %>
%>
<%= f.hidden_field :start, value: request["start"] %> <%= f.hidden_field :start, value: request["start"] %>
<%= f.govuk_submit "Sign in" %> <%= f.govuk_submit "Sign in" %>

12
app/views/devise/shared/_links.html.erb

@ -1,25 +1,25 @@
<%- if controller_name != 'sessions' %> <%- if controller_name != 'sessions' %>
<p class="govuk-body">Already have an account? <%= govuk_link_to "Sign in", new_session_path(resource_name) %>.</p><br /> <p class="govuk-body">Already have an account? <%= govuk_link_to "Sign in", new_session_path(resource_name) %>.</p>
<% end %> <% end %>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= govuk_link_to "Sign up", new_registration_path(resource_name) %><br /> <%= govuk_link_to "Sign up", new_registration_path(resource_name) %><br>
<% end %> <% end %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<p class="govuk-body"> You can <%= govuk_link_to "reset your password", new_password_path(resource_name) %> if you’ve forgotten it.<p><br /> <p class="govuk-body">You can <%= govuk_link_to "reset your password", new_password_path(resource_name) %> if you’ve forgotten it.</p>
<% end %> <% end %>
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
<%= govuk_link_to "Didn’t receive confirmation instructions?", new_confirmation_path(resource_name) %><br /> <%= govuk_link_to "Didn’t receive confirmation instructions?", new_confirmation_path(resource_name) %><br>
<% end %> <% end %>
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
<%= govuk_link_to "Didn’t receive unlock instructions?", new_unlock_path(resource_name) %><br /> <%= govuk_link_to "Didn’t receive unlock instructions?", new_unlock_path(resource_name) %><br>
<% end %> <% end %>
<%- if devise_mapping.omniauthable? %> <%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %> <%- resource_class.omniauth_providers.each do |provider| %>
<%= govuk_link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br /> <%= govuk_link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %><br>
<% end %> <% end %>
<% end %> <% end %>

4
app/views/devise/two_factor_authentication/resend.html.erb

@ -2,8 +2,8 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: 'javascript:history.back()', href: "javascript:history.back()",
) %> ) %>
<% end %> <% end %>

5
app/views/devise/two_factor_authentication/show.html.erb

@ -15,9 +15,8 @@
<%= f.govuk_number_field :code, <%= f.govuk_number_field :code,
label: { text: "Security code", size: "m" }, label: { text: "Security code", size: "m" },
width: 5, width: 5,
autocomplete: 'one-time-code', autocomplete: "one-time-code",
autofocus: true autofocus: true %>
%>
<%= f.govuk_submit "Submit" %> <%= f.govuk_submit "Submit" %>
</div> </div>

3
app/views/devise/unlocks/new.html.erb

@ -6,8 +6,7 @@
<%= f.govuk_email_field :email, <%= f.govuk_email_field :email,
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false" spellcheck: "false" %>
%>
<%= f.govuk_submit "Resend unlock instructions" %> <%= f.govuk_submit "Resend unlock instructions" %>
<% end %> <% end %>

6
app/views/filters/_checkbox_filter.html.erb

@ -1,10 +1,8 @@
<%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s"} do %> <%= f.govuk_check_boxes_fieldset category.to_sym, legend: { text: label, size: "s" }, small: true, form_group: { classes: "app-filter__group" } do %>
<div class="govuk-checkboxes govuk-checkboxes--small" data-module="govuk-checkboxes">
<% options.map do |key, option| %> <% options.map do |key, option| %>
<%= f.govuk_check_box category, "#{key}", <%= f.govuk_check_box category, key.to_s,
label: { text: option }, label: { text: option },
checked: filter_selected?(category, key), checked: filter_selected?(category, key),
size: "s" %> size: "s" %>
<% end %> <% end %>
</div>
<% end %> <% end %>

6
app/views/form/_check_answers_table.html.erb

@ -1,11 +1,11 @@
<div class="govuk-summary-list__row"> <div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key"> <dt class="govuk-summary-list__key">
<%= question.check_answer_label.to_s.present? ? question.check_answer_label.to_s : question.header.to_s %> <%= question.check_answer_label.to_s.presence || question.header.to_s %>
</dt> </dt>
<dd class="govuk-summary-list__value"> <dd class="govuk-summary-list__value">
<%= get_answer_label(question, @case_log) %><br/> <%= get_answer_label(question, @case_log) %><br>
<% question.get_inferred_answers(@case_log).each do |inferred_answer| %> <% question.get_inferred_answers(@case_log).each do |inferred_answer| %>
<span class="govuk-!-font-weight-regular app-!-colour-muted"><%= inferred_answer %></span><br/> <span class="govuk-!-font-weight-regular app-!-colour-muted"><%= inferred_answer %></span><br>
<% end %> <% end %>
</dd> </dd>
<dd class="govuk-summary-list__actions"> <dd class="govuk-summary-list__actions">

7
app/views/form/_checkbox_question.html.erb

@ -12,12 +12,11 @@
<%= f.govuk_check_box_divider %> <%= f.govuk_check_box_divider %>
<% else %> <% else %>
<%= f.govuk_check_box question.id, key, <%= f.govuk_check_box question.id, key,
label: { text: options['value'] }, label: { text: options["value"] },
hint: { text: options['hint'] }, hint: { text: options["hint"] },
checked: @case_log[key] == 1, checked: @case_log[key] == 1,
exclusive: after_divider, exclusive: after_divider,
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>

3
app/views/form/_date_question.html.erb

@ -5,5 +5,4 @@
legend: legend(question, page_header, conditional), legend: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe }, hint: { text: question.hint_text&.html_safe },
width: 20, width: 20,
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>

11
app/views/form/_interruption_screen_question.html.erb

@ -1,6 +1,6 @@
<%= govuk_panel( <%= govuk_panel(
title_text: title_text, title_text:,
classes: 'app-panel--interruption', classes: "app-panel--interruption",
) do %> ) do %>
<%= display_informative_text(informative_text, case_log) %> <%= display_informative_text(informative_text, case_log) %>
<%= f.govuk_radio_buttons_fieldset question.id.to_sym, <%= f.govuk_radio_buttons_fieldset question.id.to_sym,
@ -12,10 +12,9 @@
<% else %> <% else %>
<%= f.govuk_radio_button question.id, <%= f.govuk_radio_button question.id,
key, key,
label: { text: options['value'] }, label: { text: options["value"] },
hint: { text: options['hint'] }, hint: { text: options["hint"] },
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>

2
app/views/form/_numeric_output_question.html.erb

@ -15,7 +15,7 @@
step="<%= question.step %>" step="<%= question.step %>"
type="number" type="number"
name="case_log[tcharge]" name="case_log[tcharge]"
for="<%= question.fields_added.present? ? question.fields_added.map { |x| "case-log-#{x}-field"}.join(" ") : "" %>"> for="<%= question.fields_added.present? ? question.fields_added.map { |x| "case-log-#{x}-field" }.join(" ") : "" %>">
<%= case_log[question.id] %></output> <%= case_log[question.id] %></output>
<span class="govuk-input__suffix"><%= question.suffix %></span> <span class="govuk-input__suffix"><%= question.suffix %></span>
</div> </div>

6
app/views/form/_numeric_question.html.erb

@ -5,8 +5,8 @@
label: legend(question, page_header, conditional), label: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe }, hint: { text: question.hint_text&.html_safe },
min: question.min, max: question.max, step: question.step, min: question.min, max: question.max, step: question.step,
width: question.width, :readonly => question.read_only?, width: question.width,
readonly: question.read_only?,
prefix_text: question.prefix.to_s, prefix_text: question.prefix.to_s,
suffix_text: question.suffix.is_a?(String) ? question.suffix : nil, suffix_text: question.suffix.is_a?(String) ? question.suffix : nil,
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>

19
app/views/form/_radio_question.html.erb

@ -13,22 +13,21 @@
<% if conditional_question.nil? %> <% if conditional_question.nil? %>
<%= f.govuk_radio_button question.id, <%= f.govuk_radio_button question.id,
key, key,
label: { text: options['value'] }, label: { text: options["value"] },
hint: { text: options['hint'] }, hint: { text: options["hint"] },
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>
<% else %> <% else %>
<%= f.govuk_radio_button question.id, <%= f.govuk_radio_button question.id,
key, key,
label: { text: options['value'] }, label: { text: options["value"] },
hint: { text: options['hint'] }, hint: { text: options["hint"] },
**stimulus_html_attributes(question) do %> **stimulus_html_attributes(question) do %>
<%= render partial: "#{conditional_question.type}_question", locals: { <%= render partial: "#{conditional_question.type}_question", locals: {
question: conditional_question, question: conditional_question,
caption_text: caption_text, caption_text:,
page_header: page_header, page_header:,
f: f, f:,
conditional: true conditional: true,
} %> } %>
<% end %> <% end %>
<% end %> <% end %>

9
app/views/form/_select_question.html.erb

@ -1,14 +1,13 @@
<%= render partial: "form/guidance/#{question.guidance_partial}" if question.guidance_partial %> <%= render partial: "form/guidance/#{question.guidance_partial}" if question.guidance_partial %>
<% selected = @case_log.public_send(question.id) || "" %> <% selected = @case_log.public_send(question.id) || "" %>
<%= answers = question.displayed_answer_options.map { |key, value| OpenStruct.new(id: key, name: value) } <% answers = question.displayed_answer_options.map { |key, value| OpenStruct.new(id: key, name: value) } %>
f.govuk_collection_select question.id.to_sym, <%= f.govuk_collection_select question.id.to_sym,
answers, answers,
:id, :id,
:name, :name,
caption: caption(caption_text, page_header, conditional), caption: caption(caption_text, page_header, conditional),
label: legend(question, page_header, conditional), label: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe }, hint: { text: question.hint_text&.html_safe },
options: { disabled: [""], selected: selected }, options: { disabled: [""], selected: },
"data-controller": "accessible-autocomplete" "data-controller": "accessible-autocomplete" %>
%>

5
app/views/form/_text_question.html.erb

@ -4,6 +4,5 @@
caption: caption(caption_text, page_header, conditional), caption: caption(caption_text, page_header, conditional),
label: legend(question, page_header, conditional), label: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe }, hint: { text: question.hint_text&.html_safe },
width: question.width ? question.width : nil, width: question.width || nil,
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>

5
app/views/form/_textarea_question.html.erb

@ -4,6 +4,5 @@
caption: caption(caption_text, page_header, conditional), caption: caption(caption_text, page_header, conditional),
label: legend(question, page_header, conditional), label: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe }, hint: { text: question.hint_text&.html_safe },
width: question.width ? question.width : nil, width: question.width || nil,
**stimulus_html_attributes(question) **stimulus_html_attributes(question) %>
%>

14
app/views/form/check_answers.html.erb

@ -1,8 +1,8 @@
<% content_for :title, "#{subsection.id.humanize} - Check your answers" %> <% content_for :title, "#{subsection.id.humanize} - Check your answers" %>
<% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: {
"Logs" => "/logs", "Logs" => "/logs",
"Log #{@case_log.id.to_s}" => "/logs/" + @case_log.id.to_s, "Log #{@case_log.id}" => "/logs/#{@case_log.id}",
subsection.label => "" subsection.label => "",
}) %> }) %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
@ -16,17 +16,17 @@
<dl class="govuk-summary-list"> <dl class="govuk-summary-list">
<% subsection.applicable_questions(@case_log).each do |question| %> <% subsection.applicable_questions(@case_log).each do |question| %>
<%= render partial: 'form/check_answers_table', locals: { question: question, case_log: @case_log } %> <%= render partial: "form/check_answers_table", locals: { question:, case_log: @case_log } %>
<% end %> <% end %>
</dl> </dl>
<%= form_with model: @case_log, method: "get" do |f| %> <%= form_with model: @case_log, method: "get" do |f| %>
<%= f.govuk_submit 'Save and return to log' do %> <%= f.govuk_submit "Save and return to log" do %>
<% if @case_log.status == "in_progress" && @case_log.status == "completed" || @case_log.form.all_subsections_except_declaration_completed?(@case_log) == false %> <% if @case_log.status == "in_progress" && @case_log.status == "completed" || @case_log.form.all_subsections_except_declaration_completed?(@case_log) == false %>
<%= govuk_button_link_to 'Save and go to next incomplete section', "/logs/#{@case_log.id}/#{@case_log.form.next_incomplete_section_redirect_path(subsection, @case_log)}", secondary: true %> <%= govuk_button_link_to "Save and go to next incomplete section", "/logs/#{@case_log.id}/#{@case_log.form.next_incomplete_section_redirect_path(subsection, @case_log)}", secondary: true %>
<% elsif @case_log.status == "completed" || @case_log.form.all_subsections_except_declaration_completed?(@case_log) %> <% elsif @case_log.status == "completed" || @case_log.form.all_subsections_except_declaration_completed?(@case_log) %>
<%= govuk_button_link_to 'Save and go to submit', "/logs/#{@case_log.id}/#{@case_log.form.next_incomplete_section_redirect_path(subsection, @case_log)}", secondary: true %> <%= govuk_button_link_to "Save and go to submit", "/logs/#{@case_log.id}/#{@case_log.form.next_incomplete_section_redirect_path(subsection, @case_log)}", secondary: true %>
<% end%> <% end %>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>

2
app/views/form/guidance/_what_counts_as_income.html.erb

@ -1,4 +1,4 @@
<%= govuk_details(summary_text: 'What counts as income?') do %> <%= govuk_details(summary_text: "What counts as income?") do %>
<p class="govuk-body">You should include any income after tax from:</p> <p class="govuk-body">You should include any income after tax from:</p>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>employment</li> <li>employment</li>

18
app/views/form/page.html.erb

@ -1,9 +1,9 @@
<% content_for :title, @page.header.present? ? @page.header : @page.questions.first().header.html_safe %> <% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: 'javascript:history.back()', href: "javascript:history.back()",
) %> ) %>
<% end %> <% end %>
@ -11,7 +11,7 @@
<%= form_with model: @case_log, url: form_case_log_path(@case_log), method: "post", local: true do |f| %> <%= form_with model: @case_log, url: form_case_log_path(@case_log), method: "post", local: true do |f| %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class=<%= @page.questions[0].type == "interruption_screen" ? "govuk-grid-column-full-from-desktop" : "govuk-grid-column-two-thirds-from-desktop"%>> <div class="govuk-grid-column-<%= @page.questions[0].type == "interruption_screen" ? "full-from-desktop" : "two-thirds-from-desktop" %>">
<% remove_other_page_errors(@case_log, @page) %> <% remove_other_page_errors(@case_log, @page) %>
<%= f.govuk_error_summary %> <%= f.govuk_error_summary %>
@ -29,14 +29,14 @@
<% end %> <% end %>
<% @page.non_conditional_questions.map do |question| %> <% @page.non_conditional_questions.map do |question| %>
<div id=<%= question.id + "_div " %><%= display_question_key_div(@page, question) %> > <div id="<%= question.id %>_div" <%= display_question_key_div(@page, question) %>>
<% if question.read_only? %> <% if question.read_only? %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m"> <hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m">
<% end %> <% end %>
<% if question.type == "interruption_screen" %> <% if question.type == "interruption_screen" %>
<%= render partial: "form/#{question.type}_question", locals: { question: question, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, title_text: @page.title_text, informative_text: @page.informative_text, form: @form, f: f, conditional: false } %> <%= render partial: "form/#{question.type}_question", locals: { question:, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, title_text: @page.title_text, informative_text: @page.informative_text, form: @form, f:, conditional: false } %>
<% else %> <% else %>
<%= render partial: "form/#{question.type}_question", locals: { question: question, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, f: f, conditional: false } %> <%= render partial: "form/#{question.type}_question", locals: { question:, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, f:, conditional: false } %>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>
@ -44,11 +44,11 @@
<%= f.hidden_field :page, value: @page.id %> <%= f.hidden_field :page, value: @page.id %>
<% if @case_log.form.is_last_question?(@page, @subsection, @case_log) %> <% if @case_log.form.is_last_question?(@page, @subsection, @case_log) %>
<%= f.govuk_submit "Submit lettings log", accesskey: "s" %> <%= f.govuk_submit "Submit lettings log", accesskey: "s" %>
<%else %> <% else %>
<% if !@page.id.include?("value_check") %> <% if !@page.id.include?("value_check") %>
<%= f.govuk_submit "Save and continue", accesskey: "s" %> <%= f.govuk_submit "Save and continue", accesskey: "s" %>
<% end %> <% end %>
<%end %> <% end %>
</div> </div>
</div> </div>
<% end %> <% end %>

16
app/views/layouts/_collection_resources.html.erb

@ -0,0 +1,16 @@
<div class="app-card">
<h2 class="govuk-heading-s">Collection resources</h2>
<%= render DocumentListComponent.new(items: [
{
name: "Lettings log for tenants (2022/23)",
href: "https://core.communities.gov.uk/public/download/guides-and-manuals/2022-23%20Lettings%20paper%20form.pdf?download-format=pdf",
metadata: "PDF, 654 KB, 4 pages",
},
{
name: "Lettings log for tenants (2021/22)",
href: "https://core.communities.gov.uk/public/download/guides-and-manuals/2021_22%20Lettings%20Log.pdf?download-format=pdf",
metadata: "PDF, 302 KB, 3 pages",
},
]) %>
</div>

83
app/views/layouts/application.html.erb

@ -4,21 +4,21 @@
<title><%= browser_title(yield(:title), @pagy, @admin_user, @user, @organisation, @case_log, @resource) %></title> <title><%= browser_title(yield(:title), @pagy, @admin_user, @user, @organisation, @case_log, @resource) %></title>
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
<%= tag :meta, name: 'viewport', content: 'width=device-width, initial-scale=1' %> <%= tag.meta name: "viewport", content: "width=device-width, initial-scale=1" %>
<%= tag :meta, property: 'og:image', content: asset_path('images/govuk-opengraph-image.png') %> <%= tag.meta property: "og:image", content: asset_path("images/govuk-opengraph-image.png") %>
<%= tag :meta, name: 'theme-color', content: '#0b0c0c' %> <%= tag.meta name: "theme-color", content: "#0b0c0c" %>
<%= favicon_link_tag asset_path('images/favicon.ico') %> <%= favicon_link_tag asset_path("images/favicon.ico") %>
<%= favicon_link_tag asset_path('images/govuk-mask-icon.svg'), rel: 'mask-icon', type: 'image/svg', color: "#0b0c0c" %> <%= favicon_link_tag asset_path("images/govuk-mask-icon.svg"), rel: "mask-icon", type: "image/svg", color: "#0b0c0c" %>
<%= favicon_link_tag asset_path('images/govuk-apple-touch-icon.png'), rel: 'apple-touch-icon', type: 'image/png' %> <%= favicon_link_tag asset_path("images/govuk-apple-touch-icon.png"), rel: "apple-touch-icon", type: "image/png" %>
<%= favicon_link_tag asset_path('images/govuk-apple-touch-icon-152x152.png'), rel: 'apple-touch-icon', type: 'image/png', size: '152x152' %> <%= favicon_link_tag asset_path("images/govuk-apple-touch-icon-152x152.png"), rel: "apple-touch-icon", type: "image/png", size: "152x152" %>
<%= favicon_link_tag asset_path('images/govuk-apple-touch-icon-167x167.png'), rel: 'apple-touch-icon', type: 'image/png', size: '167x167' %> <%= favicon_link_tag asset_path("images/govuk-apple-touch-icon-167x167.png"), rel: "apple-touch-icon", type: "image/png", size: "167x167" %>
<%= favicon_link_tag asset_path('images/govuk-apple-touch-icon-180x180.png'), rel: 'apple-touch-icon', type: 'image/png', size: '180x180' %> <%= favicon_link_tag asset_path("images/govuk-apple-touch-icon-180x180.png"), rel: "apple-touch-icon", type: "image/png", size: "180x180" %>
<%= stylesheet_link_tag "application" %> <%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "vendor/html5shiv.min.js" %> <%= javascript_include_tag "vendor/html5shiv.min.js" %>
<%= javascript_tag do -%> <script>
window.html5.elements = 'output'; window.html5.elements = "output";
html5.shivDocument(document); html5.shivDocument(document);
<% end -%> </script>
<%= javascript_include_tag "vendor/polyfill-output-value.js" %> <%= javascript_include_tag "vendor/polyfill-output-value.js" %>
<%= javascript_include_tag "vendor/outerHTML.js" %> <%= javascript_include_tag "vendor/outerHTML.js" %>
<%= javascript_include_tag "application", defer: true %> <%= javascript_include_tag "application", defer: true %>
@ -37,46 +37,61 @@
<body class="govuk-template__body app-template--wide"> <body class="govuk-template__body app-template--wide">
<script> <script>
document.body.className = ((document.body.className) ? document.body.className + ' js-enabled' : 'js-enabled'); document.body.className = ((document.body.className) ? document.body.className + " js-enabled" : "js-enabled");
</script> </script>
<%= govuk_skip_link %> <%= govuk_skip_link %>
<%= govuk_header( <%= govuk_header(
logotype: 'GOV.UK', classes: "app-header",
service_name: t('service_name'), service_url: current_user.nil? ? "/" : "/logs",
service_url: current_user.nil? ? "/" : '/logs' navigation_classes: "govuk-header__navigation--end"
) do |component| ) do |component|
component.product_name(name: t("service_name"))
if current_user.nil? if current_user.nil?
component.navigation_item(text: 'Sign in', href: user_session_path) component.navigation_item(text: "Sign in", href: user_session_path)
elsif else
component.navigation_item(text: 'Logs', href: case_logs_path) component.navigation_item(text: "Your account", href: account_path)
component.navigation_item(text: 'Your organisation', href: "/organisations/#{current_user.organisation.id}") component.navigation_item(text: "Sign out", href: destroy_user_session_path)
component.navigation_item(text: 'Your account', href: account_path)
component.navigation_item(text: 'Sign out', href: destroy_user_session_path)
end
end end
%> end %>
<div class="govuk-width-container">
<aside>
<%= govuk_phase_banner( <%= govuk_phase_banner(
tag: { text: 'Beta' }, classes: "govuk-width-container",
text: "This is a new service – help us improve it by <a class=\"govuk-link\" href=\"#{t('feedback_form')}\" rel=\"noreferrer noopener\" target=\"_blank\">giving us your feedback (opens in a new tab)</a>".html_safe tag: { text: "Beta" },
text: "This is a new service – help us improve it by <a class=\"govuk-link\" href=\"#{t('feedback_form')}\" rel=\"noreferrer noopener\" target=\"_blank\">giving us your feedback (opens in a new tab)</a>".html_safe,
) %> ) %>
<% if !current_user.nil? %>
<% if current_user.support? %>
<% items = [
{ name: "Organisations", url: "/organisations" },
{ name: "Users", url: "/users" },
{ name: "Logs", url: case_logs_path },
] %>
<% else %>
<% items = [
{ name: "Logs", url: case_logs_path },
{ name: "Users", url: users_organisation_path(current_user.organisation) },
{ name: "About your organisation", url: "/organisations/#{current_user.organisation.id}" },
] %>
<% end %>
<%= render PrimaryNavigationComponent.new(items:) %>
<% end %>
<div class="govuk-width-container">
<%= content_for(:breadcrumbs) %> <%= content_for(:breadcrumbs) %>
<%= content_for(:before_content) %> <%= content_for(:before_content) %>
</aside>
<main class="govuk-main-wrapper" id="main-content" role="main"> <main class="govuk-main-wrapper" id="main-content" role="main">
<% if flash.notice && !flash.notice.include?('translation missing') %> <% if flash.notice && !flash.notice.include?("translation missing") %>
<%= govuk_notification_banner( <%= govuk_notification_banner(
title_text: 'Success', title_text: "Success",
success: true, title_heading_level: 3, success: true, title_heading_level: 3,
title_id: "swanky-notifications") do |notification_banner| title_id: "swanky-notifications"
) do |notification_banner|
notification_banner.heading(text: flash.notice) notification_banner.heading(text: flash.notice)
end end %>
%>
<% end %> <% end %>
<%= content_for?(:content) ? yield(:content) : yield %> <%= content_for?(:content) ? yield(:content) : yield %>
</main> </main>

2
app/views/layouts/mailer.html.erb

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style> <style>
/* Email styles need to be inline */ /* Email styles need to be inline */
</style> </style>

2
app/views/layouts/organisations.html.erb

@ -5,8 +5,6 @@
<% items = tab_items(current_user) %> <% items = tab_items(current_user) %>
<%= render TabNavigationComponent.new(items: items) %>
<h2 class="govuk-visually-hidden"><%= content_for(:tab_title) %></h2> <h2 class="govuk-visually-hidden"><%= content_for(:tab_title) %></h2>
<%= content_for?(:organisations_content) ? yield(:organisations_content) : yield %> <%= content_for?(:organisations_content) ? yield(:organisations_content) : yield %>

17
app/views/organisations/edit.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -15,29 +15,24 @@
</h1> </h1>
<%= f.govuk_text_field :name, <%= f.govuk_text_field :name,
autocomplete: "name" autocomplete: "name" %>
%>
<%= f.govuk_text_field :address_line1, <%= f.govuk_text_field :address_line1,
label: { text: "Address line 1" }, label: { text: "Address line 1" },
autocomplete: "address-line1" autocomplete: "address-line1" %>
%>
<%= f.govuk_text_field :address_line2, <%= f.govuk_text_field :address_line2,
label: { text: "Address line 2" }, label: { text: "Address line 2" },
autocomplete: "address-line2" autocomplete: "address-line2" %>
%>
<%= f.govuk_text_field :postcode, <%= f.govuk_text_field :postcode,
autocomplete: "postal-code", autocomplete: "postal-code",
width: 10 width: 10 %>
%>
<%= f.govuk_phone_field :phone, <%= f.govuk_phone_field :phone,
label: { text: "Telephone number" }, label: { text: "Telephone number" },
autocomplete: "tel", autocomplete: "tel",
width: 20 width: 20 %>
%>
<%= f.govuk_submit "Save changes" %> <%= f.govuk_submit "Save changes" %>
</div> </div>

0
app/views/organisations/index.html.erb

28
app/views/organisations/show.html.erb

@ -10,20 +10,28 @@
<% @organisation.display_attributes.each do |attr| %> <% @organisation.display_attributes.each do |attr| %>
<% if current_user.data_coordinator? && attr[:editable] %> <% if current_user.data_coordinator? && attr[:editable] %>
<%= summary_list.row do |row| <%= summary_list.row do |row| %>
row.key { attr[:name].to_s.humanize } <% row.key { attr[:name].to_s.humanize } %>
row.value { simple_format(attr[:value].to_s, {}, wrapper_tag: "div") } <% row.value { simple_format(attr[:value].to_s, {}, wrapper_tag: "div") } %>
row.action(visually_hidden_text: 'name', href: edit_organisation_path, html_attributes: { 'data-qa': "change-#{attr[:name]}" }) <% row.action(
end %> visually_hidden_text: "name",
href: edit_organisation_path,
html_attributes: { "data-qa": "change-#{attr[:name]}" },
) %>
<% end %>
<% else %> <% else %>
<%= summary_list.row do |row| <%= summary_list.row do |row| %>
row.key { attr[:name].to_s.humanize } <% row.key { attr[:name].to_s.humanize } %>
row.value { simple_format(attr[:value].to_s, {}, wrapper_tag: "div") } <% row.value { simple_format(attr[:value].to_s, {}, wrapper_tag: "div") } %>
row.action() <% row.action %>
end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>
<div class="govuk-grid-column-one-third-from-desktop">
<%= render partial: "layouts/collection_resources" %>
</div>
</div> </div>

20
app/views/organisations/users.html.erb

@ -9,19 +9,19 @@
<% end %> <% end %>
<%= govuk_table do |table| %> <%= govuk_table do |table| %>
<%= table.head do |head| %> <%= table.head do |head| %>
<%= head.row do |row| <%= head.row do |row| %>
row.cell(header: true, text: "Name and email adress") <% row.cell(header: true, text: "Name and email adress") %>
row.cell(header: true, text: "Organisation and role") <% row.cell(header: true, text: "Organisation and role") %>
row.cell(header: true, text: "Last logged in") <% row.cell(header: true, text: "Last logged in") %>
end %> <% end %>
<% end %> <% end %>
<% @organisation.users.each do |user| %> <% @organisation.users.each do |user| %>
<%= table.body do |body| %> <%= table.body do |body| %>
<%= body.row do |row| <%= body.row do |row| %>
row.cell(text: simple_format(user_cell(user), {}, wrapper_tag: "div")) <% row.cell(text: simple_format(user_cell(user), {}, wrapper_tag: "div")) %>
row.cell(text: simple_format(org_cell(user), {}, wrapper_tag: "div")) <% row.cell(text: simple_format(org_cell(user), {}, wrapper_tag: "div")) %>
row.cell(text: user.last_sign_in_at&.to_formatted_s(:govuk_date) ) <% row.cell(text: user.last_sign_in_at&.to_formatted_s(:govuk_date)) %>
end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>

8
app/views/pagy/_nav.html.erb

@ -5,7 +5,7 @@
<ul class="app-pagination__list"> <ul class="app-pagination__list">
<li class="app-pagination__item app-pagination__item--prev"> <li class="app-pagination__item app-pagination__item--prev">
<% if pagy.prev %> <% if pagy.prev %>
<a class="app-pagination__link" href=<%= "/logs?page=#{pagy.prev}" %>> <a class="app-pagination__link" href="<%= "/logs?page=#{pagy.prev}" %>">
<% end %> <% end %>
<span class="app-pagination__link-title"> <span class="app-pagination__link-title">
<svg class="app-pagination__icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17"> <svg class="app-pagination__icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17">
@ -16,16 +16,16 @@
</li> </li>
<% pagy.series.each do |item| %> <% pagy.series.each do |item| %>
<% if item == :gap %> <% if item == :gap %>
<li class="app-pagination__item app-pagination__item--ellipses">...</li> <li class="app-pagination__item app-pagination__item--ellipses"></li>
<% elsif item.is_a?(String) %> <% elsif item.is_a?(String) %>
<li class="app-pagination__item app-pagination__item--current"><span class="govuk-visually-hidden">Page </span><%= item %><span class="govuk-visually-hidden"> (current page) </span></li> <li class="app-pagination__item app-pagination__item--current"><span class="govuk-visually-hidden">Page </span><%= item %><span class="govuk-visually-hidden"> (current page) </span></li>
<% else %> <% else %>
<li class="app-pagination__item"><a class="app-pagination__link" href=<%= "/logs?page=#{item}" %>><span class="govuk-visually-hidden">Page </span><%= item %></a></li> <li class="app-pagination__item"><a class="app-pagination__link" href="<%= "/logs?page=#{item}" %>"><span class="govuk-visually-hidden">Page </span><%= item %></a></li>
<% end %> <% end %>
<% end %> <% end %>
<li class="app-pagination__item app-pagination__item--next"> <li class="app-pagination__item app-pagination__item--next">
<% if pagy.next %> <% if pagy.next %>
<a class="app-pagination__link" href=<%= "/logs?page=#{pagy.next}" %>> <a class="app-pagination__link" href="<%= "/logs?page=#{pagy.next}" %>">
<% end %> <% end %>
Next <span class="govuk-visually-hidden">page</span> Next <span class="govuk-visually-hidden">page</span>
<span class="app-pagination__link-title"> <span class="app-pagination__link-title">

35
app/views/start/index.html.erb

@ -3,23 +3,17 @@
</h1> </h1>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds-from-desktop">
<p class="govuk-body">Use this service to submit social housing lettings and sales data to the Department for Levelling Up, Housing and Communities (DLUHC).</p> <p class="govuk-body">Use this service to submit social housing lettings and sales data to the Department for Levelling Up, Housing and Communities (DLUHC).</p>
<p class="govuk-body">We’ll ask you questions about a letting or sale, like details about the household or property. Your answers will create a log that you can submit directly to us.</p> <p class="govuk-body">We’ll ask you questions about a letting or sale, like details about the household or property. Your answers will create a log that you can submit directly to us.</p>
<p class="govuk-body">Your organisation can also:</p> <p class="govuk-body">Your organisation can also set up and manage user accounts.</p>
<ul class="govuk-list govuk-list--bullet">
<li>upload data for multiple sales and lettings</li>
<li>transfer data using an API</li>
<%# TODO: Add link to lettings log form %>
<li><%= govuk_link_to("download a copy of the 2021 to 2022 lettings log as a PDF", "#") %> (2MB)</li>
</ul>
<p class="govuk-body">The data will be used to update the national record for social housing. It will also help to inform policy about the cost of social housing and what type of housing needs to be built.</p> <p class="govuk-body">The data will be used to update the national record for social housing. It will also help to inform policy about the cost of social housing and what type of housing needs to be built.</p>
<p class="govuk-body">This service is only for social housing in England.</p> <p class="govuk-body">This service is only for social housing in England.</p>
<% start_path = current_user ? case_logs_path : (user_session_path + "?start=true") %> <% start_path = current_user ? case_logs_path : "#{user_session_path}?start=true" %>
<%= govuk_start_button( <%= govuk_start_button(
text: 'Start now', text: "Start now",
href: start_path href: start_path,
) %> ) %>
<h2 class="govuk-heading-m">Before you start</h2> <h2 class="govuk-heading-m">Before you start</h2>
@ -28,22 +22,7 @@
<p class="govuk-body">You can <%= govuk_link_to("request an account", "https://digital.dclg.gov.uk/jira/servicedesk/customer/portal/4/group/21") %> if your organisation doesn’t have one.</p> <p class="govuk-body">You can <%= govuk_link_to("request an account", "https://digital.dclg.gov.uk/jira/servicedesk/customer/portal/4/group/21") %> if your organisation doesn’t have one.</p>
</div> </div>
<div class="govuk-grid-column-one-third"> <div class="govuk-grid-column-one-third-from-desktop">
<div class="app-related-navigation"> <%= render partial: "layouts/collection_resources" %>
<nav class="app-related-navigation__nav-section" role="navigation" aria-labelledby="related-content">
<h2 class="app-related-navigation__main-heading" id="related-content">
Related content
</h2>
<ul class="app-related-navigation__link-list">
<li class="app-related-navigation__link">
<%# TODO: Add link to guidance %>
<%= govuk_link_to("How to submit social housing lettings and sales data (CORE)", "#", classes: "app-related-navigation__section-link app-related-navigation__section-link--other") %>
</li>
<li>
<%= govuk_link_to("Data sharing agreement", data_sharing_agreement_path, classes: "app-related-navigation__section-link app-related-navigation__section-link--other") %>
</li>
</ul>
</nav>
</div>
</div> </div>
</div> </div>

23
app/views/users/edit.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -17,36 +17,35 @@
</h1> </h1>
<%= f.govuk_text_field :name, <%= f.govuk_text_field :name,
autocomplete: "name" autocomplete: "name" %>
%>
<%= f.govuk_email_field :email, <%= f.govuk_email_field :email,
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false" spellcheck: "false" %>
%>
<% if current_user.data_coordinator? || current_user.support? %> <% if current_user.data_coordinator? || current_user.support? %>
<%= roles = current_user.assignable_roles.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } <%= roles = current_user.assignable_roles.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %>
f.govuk_collection_radio_buttons :role, roles, :id, :name, legend: { text: "Role", size: "m" } <%= f.govuk_collection_radio_buttons :role,
%> roles,
:id,
:name,
legend: { text: "Role", size: "m" } %>
<%= f.govuk_collection_radio_buttons :is_dpo, <%= f.govuk_collection_radio_buttons :is_dpo,
[OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")], [OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")],
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" } %>
%>
<%= f.govuk_collection_radio_buttons :is_key_contact, <%= f.govuk_collection_radio_buttons :is_key_contact,
[OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")], [OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")],
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" } %>
%>
<% end %> <% end %>
<%= f.govuk_submit "Save changes" %> <%= f.govuk_submit "Save changes" %>

0
app/views/users/index.html.erb

24
app/views/users/new.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -17,35 +17,35 @@
</h1> </h1>
<%= f.govuk_text_field :name, <%= f.govuk_text_field :name,
autocomplete: "name" autocomplete: "name" %>
%>
<%= f.govuk_email_field :email, <%= f.govuk_email_field :email,
label: { text: "Email address" }, label: { text: "Email address" },
autocomplete: "email", autocomplete: "email",
spellcheck: "false", spellcheck: "false",
value: @resource.email value: @resource.email %>
%>
<%= roles = current_user.assignable_roles.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } <%= roles = current_user.assignable_roles.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %>
f.govuk_collection_radio_buttons :role, roles, :id, :name, legend: { text: "Role", size: "m" }
%> <%= f.govuk_collection_radio_buttons :role,
roles,
:id,
:name,
legend: { text: "Role", size: "m" } %>
<%= f.govuk_collection_radio_buttons :is_dpo, <%= f.govuk_collection_radio_buttons :is_dpo,
[OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")], [OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")],
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a data protection officer?", size: "m" } %>
%>
<%= f.govuk_collection_radio_buttons :is_key_contact, <%= f.govuk_collection_radio_buttons :is_key_contact,
[OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")], [OpenStruct.new(id: false, name: "No"), OpenStruct.new(id: true, name: "Yes")],
:id, :id,
:name, :name,
inline: true, inline: true,
legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" } legend: { text: "Are #{pronoun(@user, current_user)} a key contact?", size: "m" } %>
%>
<%= f.govuk_submit "Continue" %> <%= f.govuk_submit "Continue" %>
</div> </div>

40
app/views/users/show.html.erb

@ -17,17 +17,17 @@
if can_edit_names?(@user, current_user) if can_edit_names?(@user, current_user)
row.action(visually_hidden_text: "name", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-name" }) row.action(visually_hidden_text: "name", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-name" })
else else
row.action() row.action
end end
end %> end %>
<%= summary_list.row() do |row| <%= summary_list.row do |row|
row.key { "Email address" } row.key { "Email address" }
row.value { @user.email } row.value { @user.email }
if can_edit_emails?(@user, current_user) if can_edit_emails?(@user, current_user)
row.action(visually_hidden_text: "email address", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-email-address" }) row.action(visually_hidden_text: "email address", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-email-address" })
else else
row.action() row.action
end end
end %> end %>
@ -35,25 +35,33 @@
row.key { "Password" } row.key { "Password" }
row.value { "••••••••" } row.value { "••••••••" }
if can_edit_password?(@user, current_user) if can_edit_password?(@user, current_user)
row.action(visually_hidden_text: "password", href: edit_password_account_path, html_attributes: { "data-qa": "change-password" }) row.action(
visually_hidden_text: "password",
href: edit_password_account_path,
html_attributes: { "data-qa": "change-password" },
)
else else
row.action() row.action
end end
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { "Organisation" } row.key { "Organisation" }
row.value { @user.organisation.name } row.value { @user.organisation.name }
row.action() row.action
end %> end %>
<%= summary_list.row do |row| <%= summary_list.row do |row|
row.key { "Role" } row.key { "Role" }
row.value { @user.role.humanize } row.value { @user.role.humanize }
if can_edit_roles?(@user, current_user) if can_edit_roles?(@user, current_user)
row.action(visually_hidden_text: "role", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-role" }) row.action(
visually_hidden_text: "role",
href: aliased_user_edit(@user, current_user),
html_attributes: { "data-qa": "change-role" },
)
else else
row.action() row.action
end end
end %> end %>
@ -61,9 +69,13 @@
row.key { "Data protection officer" } row.key { "Data protection officer" }
row.value { @user.is_data_protection_officer? ? "Yes" : "No" } row.value { @user.is_data_protection_officer? ? "Yes" : "No" }
if can_edit_dpo?(@user, current_user) if can_edit_dpo?(@user, current_user)
row.action(visually_hidden_text: "are #{pronoun(@user, current_user)} a data protection officer?", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-data-protection-officer" }) row.action(
visually_hidden_text: "are #{pronoun(@user, current_user)} a data protection officer?",
href: aliased_user_edit(@user, current_user),
html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-data-protection-officer" },
)
else else
row.action() row.action
end end
end %> end %>
@ -71,9 +83,13 @@
row.key { "Key contact" } row.key { "Key contact" }
row.value { @user.is_key_contact? ? "Yes" : "No" } row.value { @user.is_key_contact? ? "Yes" : "No" }
if can_edit_key_contact?(@user, current_user) if can_edit_key_contact?(@user, current_user)
row.action(visually_hidden_text: "are #{pronoun(@user, current_user)} a key contact?", href: aliased_user_edit(@user, current_user), html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-key-contact" }) row.action(
visually_hidden_text: "are #{pronoun(@user, current_user)} a key contact?",
href: aliased_user_edit(@user, current_user),
html_attributes: { "data-qa": "change-are-#{pronoun(@user, current_user)}-a-key-contact" },
)
else else
row.action() row.action
end end
end %> end %>
<% end %> <% end %>

350
config/forms/2021_2022.json

@ -22,7 +22,7 @@
"1": { "1": {
"value": "General needs" "value": "General needs"
}, },
"0": { "2": {
"value": "Supported housing" "value": "Supported housing"
} }
} }
@ -90,12 +90,12 @@
} }
}, },
"conditional_for": { "conditional_for": {
"intermediate_rent_product_name": [ "irproduct_other": [
5 5
] ]
} }
}, },
"intermediate_rent_product_name": { "irproduct_other": {
"check_answer_label": "Product name", "check_answer_label": "Product name",
"header": "Name of rent product", "header": "Name of rent product",
"type": "text" "type": "text"
@ -587,13 +587,13 @@
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "1": {
"value": "Affordable rent basis" "value": "Social rent basis"
}, },
"2": { "2": {
"value": "Intermediate rent basis" "value": "Affordable rent basis"
}, },
"0": { "4": {
"value": "Social rent basis" "value": "Intermediate rent basis"
}, },
"divider": { "divider": {
"value": true "value": true
@ -621,39 +621,39 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "13": {
"value": "Internal transfer", "value": "Internal transfer",
"hint": "Excluding renewals of a fixed-term tenancy" "hint": "Excluding renewals of a fixed-term tenancy"
}, },
"10": { "5": {
"value": "Previous tenant died with no succession" "value": "Previous tenant died with no succession"
}, },
"2": { "9": {
"value": "Re-let to tenant who occupied same property as temporary accommodation" "value": "Re-let to tenant who occupied same property as temporary accommodation"
}, },
"0": { "14": {
"value": "Renewal of fixed-term tenancy" "value": "Renewal of fixed-term tenancy"
}, },
"7": { "19": {
"value": "Tenant abandoned property"
},
"3": {
"value": "Tenant involved in a succession downsize" "value": "Tenant involved in a succession downsize"
}, },
"6": { "8": {
"value": "Tenant moved to care home" "value": "Tenant moved to private sector or other accommodation"
}, },
"5": { "12": {
"value": "Tenant moved to other social housing provider" "value": "Tenant moved to other social housing provider"
}, },
"4": { "18": {
"value": "Tenant moved to private sector or other accommodation" "value": "Tenant moved to care home"
}, },
"9": { "6": {
"value": "Tenant was evicted due to anti-social behaviour" "value": "Tenant abandoned property"
}, },
"8": { "10": {
"value": "Tenant was evicted due to rent arrears" "value": "Tenant was evicted due to rent arrears"
},
"11": {
"value": "Tenant was evicted due to anti-social behaviour"
} }
} }
} }
@ -675,14 +675,14 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"15": {
"value": "First let of new-build property"
},
"16": { "16": {
"value": "First let of conversion, rehabilitation or acquired property" "value": "First let of conversion, rehabilitation or acquired property"
}, },
"17": { "17": {
"value": "First let of leased property" "value": "First let of leased property"
},
"15": {
"value": "First let of new-build property"
} }
} }
} }
@ -748,28 +748,28 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "2": {
"value": "Bedsit" "value": "Bedsit"
}, },
"3": { "8": {
"value": "Bungalow" "value": "Bungalow"
}, },
"0": { "1": {
"value": "Flat or maisonette" "value": "Flat or maisonette"
}, },
"2": { "7": {
"value": "House" "value": "House"
}, },
"6": { "10": {
"value": "Shared bungalow" "value": "Shared bungalow"
}, },
"4": { "4": {
"value": "Shared flat or maisonette" "value": "Shared flat or maisonette"
}, },
"5": { "9": {
"value": "Shared house" "value": "Shared house"
}, },
"7": { "6": {
"value": "Other" "value": "Other"
} }
} }
@ -786,10 +786,10 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"1": { "2": {
"value": "Converted from previous residential or non-residential property" "value": "Converted from previous residential or non-residential property"
}, },
"0": { "1": {
"value": "Purpose built" "value": "Purpose built"
} }
} }
@ -806,10 +806,10 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes" "value": "Yes"
}, },
"1": { "2": {
"value": "No" "value": "No"
} }
} }
@ -841,7 +841,7 @@
"header": "", "header": "",
"description": "", "description": "",
"questions": { "questions": {
"property_void_date": { "voiddate": {
"check_answer_label": "Void or renewal date", "check_answer_label": "Void or renewal date",
"header": "What is the void or renewal date?", "header": "What is the void or renewal date?",
"hint_text": "For example, 27 3 2021.", "hint_text": "For example, 27 3 2021.",
@ -863,7 +863,7 @@
"header": "", "header": "",
"description": "", "description": "",
"questions": { "questions": {
"property_void_date": { "voiddate": {
"check_answer_label": "New-build handover date", "check_answer_label": "New-build handover date",
"header": "What is the new-build handover date?", "header": "What is the new-build handover date?",
"hint_text": "", "hint_text": "",
@ -938,10 +938,10 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes" "value": "Yes"
}, },
"1": { "2": {
"value": "No" "value": "No"
} }
} }
@ -958,25 +958,25 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "2": {
"value": "Assured" "value": "Assured"
}, },
"1": { "4": {
"value": "Assured Shorthold" "value": "Assured Shorthold"
}, },
"2": { "5": {
"value": "Licence agreement (almshouses only)" "value": "Licence agreement (almshouses only)"
}, },
"3": { "1": {
"value": "Secure (including flexible)" "value": "Secure (including flexible)"
}, },
"4": { "3": {
"value": "Other" "value": "Other"
} }
}, },
"conditional_for": { "conditional_for": {
"tenancyother": [ "tenancyother": [
4 3
] ]
} }
}, },
@ -1002,25 +1002,25 @@
"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": {
"0": { "2": {
"value": "Assured" "value": "Assured"
}, },
"1": { "4": {
"value": "Assured Shorthold" "value": "Assured Shorthold"
}, },
"2": { "5": {
"value": "Licence agreement (almshouses only)" "value": "Licence agreement (almshouses only)"
}, },
"3": { "1": {
"value": "Secure (including flexible)" "value": "Secure (including flexible)"
}, },
"4": { "3": {
"value": "Other" "value": "Other"
} }
}, },
"conditional_for": { "conditional_for": {
"tenancyother": [ "tenancyother": [
4 3
] ]
} }
}, },
@ -1053,10 +1053,10 @@
}, },
"depends_on": [ "depends_on": [
{ {
"tenancy": 3 "tenancy": 1
}, },
{ {
"tenancy": 1 "tenancy": 4
} }
] ]
}, },
@ -1064,25 +1064,25 @@
"header": "", "header": "",
"description": "", "description": "",
"questions": { "questions": {
"letting_in_sheltered_accommodation": { "shelteredaccom": {
"check_answer_label": "Is this letting in sheltered accommodation?", "check_answer_label": "Is this letting in sheltered accommodation?",
"header": "Is this letting in sheltered accommodation?", "header": "Is this letting in sheltered accommodation?",
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes – sheltered housing" "value": "Yes – sheltered housing"
}, },
"1": { "2": {
"value": "Yes – extra care housing" "value": "Yes – extra care housing"
}, },
"2": { "3": {
"value": "No" "value": "No"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"3": { "4": {
"value": "Don’t know" "value": "Don’t know"
} }
} }
@ -1090,7 +1090,7 @@
}, },
"depends_on": [ "depends_on": [
{ {
"needstype": 0 "needstype": 2
} }
] ]
} }
@ -1243,7 +1243,7 @@
"divider": { "divider": {
"value": true "value": true
}, },
"5": { "17": {
"value": "Tenant prefers not to say" "value": "Tenant prefers not to say"
} }
} }
@ -1260,16 +1260,16 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "19": {
"value": "Arab" "value": "Arab"
}, },
"1": { "16": {
"value": "Other ethnic group" "value": "Other ethnic group"
} }
}, },
"conditional_for": { "conditional_for": {
"ethnic_other": [ "ethnic_other": [
1 16
] ]
} }
}, },
@ -1295,25 +1295,25 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "10": {
"value": "Bangladeshi" "value": "Bangladeshi"
}, },
"1": { "15": {
"value": "Chinese" "value": "Chinese"
}, },
"2": { "8": {
"value": "Indian" "value": "Indian"
}, },
"3": { "9": {
"value": "Pakistani" "value": "Pakistani"
}, },
"4": { "11": {
"value": "Other ethnic group" "value": "Other ethnic group"
} }
}, },
"conditional_for": { "conditional_for": {
"ethnic_other": [ "ethnic_other": [
4 11
] ]
} }
}, },
@ -1339,13 +1339,13 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "13": {
"value": "African" "value": "African"
}, },
"1": { "12": {
"value": "Caribbean" "value": "Caribbean"
}, },
"2": { "14": {
"value": "Any other Black, African or Caribbean background" "value": "Any other Black, African or Caribbean background"
} }
}, },
@ -1377,19 +1377,22 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "4": {
"value": "White and Black Caribbean" "value": "White and Black Caribbean"
}, },
"1": { "5": {
"value": "White and Black African" "value": "White and Black African"
}, },
"2": { "6": {
"value": "White and Asian"
},
"7": {
"value": "Any other Mixed or Multiple ethnic background" "value": "Any other Mixed or Multiple ethnic background"
} }
}, },
"conditional_for": { "conditional_for": {
"ethnic_other": [ "ethnic_other": [
2 7
] ]
} }
}, },
@ -1415,17 +1418,14 @@
"hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.", "hint_text": "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "English, Welsh, Northern Irish, Scottish or British" "value": "English, Welsh, Northern Irish, Scottish or British"
}, },
"1": { "2": {
"value": "Irish" "value": "Irish"
}, },
"2": { "18": {
"value": "Gypsy or Irish Traveller" "value": "Gypsy or Irish Traveller"
},
"3": {
"value": "Any other White background"
} }
}, },
"conditional_for": { "conditional_for": {
@ -1579,25 +1579,25 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 1 "hhmemb": 2
}, },
{ {
"other_hhmemb": 2 "hhmemb": 3
}, },
{ {
"other_hhmemb": 3 "hhmemb": 4
}, },
{ {
"other_hhmemb": 4 "hhmemb": 5
}, },
{ {
"other_hhmemb": 5 "hhmemb": 6
}, },
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -1792,22 +1792,22 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 2 "hhmemb": 3
}, },
{ {
"other_hhmemb": 3 "hhmemb": 4
}, },
{ {
"other_hhmemb": 4 "hhmemb": 5
}, },
{ {
"other_hhmemb": 5 "hhmemb": 6
}, },
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -2002,19 +2002,19 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 3 "hhmemb": 4
}, },
{ {
"other_hhmemb": 4 "hhmemb": 5
}, },
{ {
"other_hhmemb": 5 "hhmemb": 6
}, },
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -2209,16 +2209,16 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 4 "hhmemb": 5
}, },
{ {
"other_hhmemb": 5 "hhmemb": 6
}, },
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -2413,13 +2413,13 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 5 "hhmemb": 6
}, },
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -2614,10 +2614,10 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 6 "hhmemb": 7
}, },
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -2812,7 +2812,7 @@
}, },
"depends_on": [ "depends_on": [
{ {
"other_hhmemb": 7 "hhmemb": 8
} }
] ]
}, },
@ -3007,22 +3007,22 @@
"type": "radio", "type": "radio",
"check_answer_label": "Household links to UK armed forces", "check_answer_label": "Household links to UK armed forces",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes – the person is a current or former regular" "value": "Yes – the person is a current or former regular"
}, },
"1": { "4": {
"value": "Yes – the person is a current or former reserve" "value": "Yes – the person is a current or former reserve"
}, },
"2": { "5": {
"value": "Yes – the person is a spouse or civil partner of a UK armed forces member and has been bereaved or separated from them within the last 2 years" "value": "Yes – the person is a spouse or civil partner of a UK armed forces member and has been bereaved or separated from them within the last 2 years"
}, },
"3": { "2": {
"value": "No" "value": "No"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"4": { "3": {
"value": "Person prefers not to say" "value": "Person prefers not to say"
} }
} }
@ -3034,7 +3034,7 @@
"description": "", "description": "",
"depends_on": [ "depends_on": [
{ {
"armedforces": 0 "armedforces": 1
} }
], ],
"questions": { "questions": {
@ -3068,10 +3068,10 @@
"description": "", "description": "",
"depends_on": [ "depends_on": [
{ {
"armedforces": 0 "armedforces": 1
}, },
{ {
"armedforces": 1 "armedforces": 4
} }
], ],
"questions": { "questions": {
@ -3107,16 +3107,16 @@
"type": "radio", "type": "radio",
"check_answer_label": "Anybody in household pregnant", "check_answer_label": "Anybody in household pregnant",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes" "value": "Yes"
}, },
"1": { "2": {
"value": "No" "value": "No"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"2": { "3": {
"value": "Tenant prefers not to say" "value": "Tenant prefers not to say"
} }
} }
@ -3168,16 +3168,16 @@
"type": "radio", "type": "radio",
"check_answer_label": "Anybody in household with physical or mental health condition", "check_answer_label": "Anybody in household with physical or mental health condition",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Yes" "value": "Yes"
}, },
"1": { "2": {
"value": "No" "value": "No"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"2": { "3": {
"value": "Tenant prefers not to say" "value": "Tenant prefers not to say"
} }
} }
@ -3189,7 +3189,7 @@
"description": "", "description": "",
"depends_on": [ "depends_on": [
{ {
"illness": 0 "illness": 1
} }
], ],
"questions": { "questions": {
@ -3299,37 +3299,37 @@
"header": "", "header": "",
"description": "", "description": "",
"questions": { "questions": {
"lawaitlist": { "waityear": {
"check_answer_label": "Length of time on local authority waiting list", "check_answer_label": "Length of time on local authority waiting list",
"header": "How long has the household been on the local authority waiting list for the new letting?", "header": "How long has the household been on the local authority waiting list for the new letting?",
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Just moved to local authority area" "value": "Just moved to local authority area"
}, },
"1": { "2": {
"value": "Less than 1 year" "value": "Less than 1 year"
}, },
"2": { "7": {
"value": "1 year but under 2 years" "value": "1 year but under 2 years"
}, },
"3": { "8": {
"value": "2 years but under 3 years" "value": "2 years but under 3 years"
}, },
"4": { "9": {
"value": "3 years but under 4 years" "value": "3 years but under 4 years"
}, },
"5": { "10": {
"value": "4 years but under 5 years" "value": "4 years but under 5 years"
}, },
"6": { "5": {
"value": "5 years or more" "value": "5 years or more"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"7": { "6": {
"value": "Don’t know" "value": "Don’t know"
} }
} }
@ -3452,18 +3452,15 @@
}, },
"28": { "28": {
"value": "Don’t know" "value": "Don’t know"
},
"10000": {
"value": "Tenant prefers not to say"
} }
}, },
"conditional_for": { "conditional_for": {
"other_reason_for_leaving_last_settled_home": [ "reasonother": [
31 20
] ]
} }
}, },
"other_reason_for_leaving_last_settled_home": { "reasonother": {
"header": "What is the reason?", "header": "What is the reason?",
"hint_text": "", "hint_text": "",
"type": "text" "type": "text"
@ -3610,7 +3607,7 @@
"depends_on": [ "depends_on": [
{ {
"renewal": 1, "renewal": 1,
"needstype": 0 "needstype": 2
} }
] ]
}, },
@ -4406,7 +4403,7 @@
"depends_on": [ "depends_on": [
{ {
"managing_organisation.provider_type": "LA", "managing_organisation.provider_type": "LA",
"needstype": 0, "needstype": 2,
"renewal": 0 "renewal": 0
} }
] ]
@ -4466,7 +4463,7 @@
"depends_on": [ "depends_on": [
{ {
"managing_organisation.provider_type": "PRP", "managing_organisation.provider_type": "PRP",
"needstype": 0, "needstype": 2,
"renewal": 0 "renewal": 0
} }
] ]
@ -4535,19 +4532,19 @@
{ {
"label": "every week", "label": "every week",
"depends_on": { "depends_on": {
"incfreq": 0 "incfreq": 1
} }
}, },
{ {
"label": "every month", "label": "every month",
"depends_on": { "depends_on": {
"incfreq": 1 "incfreq": 2
} }
}, },
{ {
"label": "every month", "label": "every year",
"depends_on": { "depends_on": {
"incfreq": 2 "incfreq": 3
} }
} }
] ]
@ -4558,13 +4555,13 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "Weekly" "value": "Weekly"
}, },
"1": { "2": {
"value": "Monthly" "value": "Monthly"
}, },
"2": { "3": {
"value": "Yearly" "value": "Yearly"
} }
}, },
@ -4626,9 +4623,6 @@
}, },
"3": { "3": {
"value": "Don’t know" "value": "Don’t know"
},
"6": {
"value": "Tenant prefers not to say"
} }
} }
} }
@ -4644,19 +4638,19 @@
"hint_text": "This excludes child and housing benefit, council tax support and tax credits.", "hint_text": "This excludes child and housing benefit, council tax support and tax credits.",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": { "1": {
"value": "All" "value": "All"
}, },
"1": { "2": {
"value": "Some" "value": "Some"
}, },
"2": { "3": {
"value": "None" "value": "None"
}, },
"divider": { "divider": {
"value": true "value": true
}, },
"3": { "4": {
"value": "Don’t know" "value": "Don’t know"
} }
} }
@ -4684,7 +4678,7 @@
}, },
"depends_on": [ "depends_on": [
{ {
"needstype": 0 "needstype": 2
} }
] ]
}, },
@ -4774,62 +4768,62 @@
"depends_on": [ "depends_on": [
{ {
"period": 1, "period": 1,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 1, "period": 1,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
}, },
{ {
"period": 5, "period": 5,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 5, "period": 5,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
}, },
{ {
"period": 6, "period": 6,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 6, "period": 6,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
}, },
{ {
"period": 7, "period": 7,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 7, "period": 7,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
}, },
{ {
"period": 8, "period": 8,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 8, "period": 8,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
}, },
{ {
"period": 9, "period": 9,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 9, "period": 9,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
} }
] ]
@ -4871,12 +4865,12 @@
"depends_on": [ "depends_on": [
{ {
"period": 2, "period": 2,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 2, "period": 2,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
} }
] ]
@ -4918,12 +4912,12 @@
"depends_on": [ "depends_on": [
{ {
"period": 3, "period": 3,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 3, "period": 3,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
} }
] ]
@ -4965,12 +4959,12 @@
"depends_on": [ "depends_on": [
{ {
"period": 4, "period": 4,
"needstype": 0, "needstype": 2,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 4, "period": 4,
"needstype": 0, "needstype": 2,
"household_charge": null "household_charge": null
} }
] ]

44
config/locales/en.yml

@ -93,34 +93,34 @@ en:
benefits: benefits:
part_or_full_time: "Answer cannot be 'all' for income from Universal Credit, state pensions or benefits if the tenant or their partner works part-time or full-time" part_or_full_time: "Answer cannot be 'all' for income from Universal Credit, state pensions or benefits if the tenant or their partner works part-time or full-time"
earnings: earnings:
over_hard_max: "Net income cannot be greater than %{hard_max} given the tenant’s working situation" over_hard_max: "Net income cannot be greater than £%{hard_max} per week given the tenant’s working situation"
under_hard_min: "Net income cannot be less than %{hard_min} given the tenant’s working situation" under_hard_min: "Net income cannot be less than £%{hard_min} per week given the tenant’s working situation"
freq_missing: "Select how often the household receives income" freq_missing: "Select how often the household receives income"
earnings_missing: "Enter how much income the household has in total" earnings_missing: "Enter how much income the household has in total"
negative_currency: "Enter an amount above 0" negative_currency: "Enter an amount above 0"
rent: rent:
less_than_double_shortfall: "Answer must be more than double the shortfall in basic rent" less_than_double_shortfall: "Answer must be more than double the shortfall in basic rent"
scharge: scharge:
this_landlord: private_registered_provider:
general_needs: "Service charge must be between £0 and £55 per week if the landlord is the same and it is a general needs letting" general_needs: "Service charge must be between £0 and £55 per week if the landlord is a private registered provider and it is a general needs letting"
supported_housing: "Service charge must be between £0 and £280 per week if the landlord is the same and it is a supported housing letting" supported_housing: "Service charge must be between £0 and £280 per week if the landlord is a private registered provider and it is a supported housing letting"
other_landlord: local_authority:
general_needs: "Service charge must be between £0 and £45 per week if the landlord is another registered provider and it is a general needs letting" general_needs: "Service charge must be between £0 and £45 per week if the landlord is a local authority and it is a general needs letting"
supported_housing: "Service charge must be between £0 and £165 per week if the landlord is another registered provider and it is a supported housing letting" supported_housing: "Service charge must be between £0 and £165 per week if the landlord is a local authority and it is a supported housing letting"
pscharge: pscharge:
this_landlord: private_registered_provider:
general_needs: "Personal service charge must be between £0 and £30 per week if the landlord is the same and it is a general needs letting" general_needs: "Personal service charge must be between £0 and £30 per week if the landlord is a private registered provider and it is a general needs letting"
supported_housing: "Personal service charge must be between £0 and £200 per week if the landlord is the same and it is a supported housing letting" supported_housing: "Personal service charge must be between £0 and £200 per week if the landlord is a private registered provider and it is a supported housing letting"
other_landlord: local_authority:
general_needs: "Personal service charge must be between £0 and £35 per week if the landlord is another registered provider and it is a general needs letting" general_needs: "Personal service charge must be between £0 and £35 per week if the landlord is a local authority and it is a general needs letting"
supported_housing: "Personal service charge must be between £0 and £75 per week if the landlord is another registered provider and it is a supported housing letting" supported_housing: "Personal service charge must be between £0 and £75 per week if the landlord is a local authority and it is a supported housing letting"
supcharg: supcharg:
this_landlord: private_registered_provider:
general_needs: "Support charge must be between £0 and £40 per week if the landlord is the same and it is a general needs letting" general_needs: "Support charge must be between £0 and £40 per week if the landlord is a private registered provider and it is a general needs letting"
supported_housing: "Support charge must be between £0 and £465 per week if the landlord is the same and it is a supported housing letting" supported_housing: "Support charge must be between £0 and £465 per week if the landlord is a private registered provider and it is a supported housing letting"
other_landlord: local_authority:
general_needs: "Support charge must be between £0 and £60 per week if the landlord is another registered provider and it is a general needs letting" general_needs: "Support charge must be between £0 and £60 per week if the landlord is a local authority and it is a general needs letting"
supported_housing: "Support charge must be between £0 and £120 per week if the landlord is another registered provider and it is a supported housing letting" supported_housing: "Support charge must be between £0 and £120 per week if the landlord is a local authority and it is a supported housing letting"
brent: brent:
not_in_range: "Basic rent is outside of the expected range based on the lettings type, local authority and number of bedrooms" not_in_range: "Basic rent is outside of the expected range based on the lettings type, local authority and number of bedrooms"
la: la:
@ -183,7 +183,7 @@ en:
male_refuge: "Answer cannot be refuge as the lead tenant identifies as male" male_refuge: "Answer cannot be refuge as the lead tenant identifies as male"
internal_transfer: "Answer cannot be %{prevten} as you already told us this tenancy is an internal transfer" internal_transfer: "Answer cannot be %{prevten} as you already told us this tenancy is an internal transfer"
la_general_needs: la_general_needs:
internal_transfer: "Answer cannot be a fixed-term or lifetime local authority general needs tenancy as you already told us it's the same landlord on the tenancy agreement and it is an internal transfer" internal_transfer: "Answer cannot be a fixed-term or lifetime local authority general needs tenancy as you already told us it's a private registered provider on the tenancy agreement and it is an internal transfer"
referral: referral:
secure_tenancy: "Answer must be internal transfer as you already told us this is a secure tenancy" secure_tenancy: "Answer must be internal transfer as you already told us this is a secure tenancy"
rsnvac_non_temp: "Answer cannot be this source of referral as you already told us this is a re-let to tenant who occupied the same property as temporary accommodation" rsnvac_non_temp: "Answer cannot be this source of referral as you already told us this is a re-let to tenant who occupied the same property as temporary accommodation"
@ -195,7 +195,7 @@ en:
la_general_needs: la_general_needs:
internal_transfer: "Answer cannot be internal transfer as you already told us it's the same landlord on the tenancy agreement and the household had either a fixed-term or lifetime local authority general needs tenancy immediately before this letting" internal_transfer: "Answer cannot be internal transfer as you already told us it's the same landlord on the tenancy agreement and the household had either a fixed-term or lifetime local authority general needs tenancy immediately before this letting"
prp: prp:
local_housing_referral: "Answer cannot be 'nominated by a local housing authority' as you already told us it's another landlord on the tenancy agreement" local_housing_referral: "Answer cannot be 'nominated by a local housing authority' as you already told us it is a local authority on the tenancy agreement"
homeless: homeless:
assessed: assessed:
internal_transfer: "Answer cannot be assessed as homeless as you already told us this tenancy is an internal transfer" internal_transfer: "Answer cannot be assessed as homeless as you already told us this tenancy is an internal transfer"

0
db/migrate/202202071123100_additional_user_fields2.rb → db/migrate/20220207112310_additional_user_fields2.rb

13
db/migrate/20220411092231_update_case_logs_fields.rb

@ -0,0 +1,13 @@
class UpdateCaseLogsFields < ActiveRecord::Migration[7.0]
def change
change_table :case_logs, bulk: true do |t|
t.integer :old_form_id, :lar, :irproduct
t.remove :day, :month, :year, :vday, :vmonth, :vyear, :mrcday, :mrcmonth, :mrcyear, :other_hhmemb, :accessibility_requirements_prefer_not_to_say, :landlord, type: :integer
t.remove :ppostc1, :ppostc2, :postcode, :postcod2, type: :string
t.rename :intermediate_rent_product_name, :irproduct_other
t.rename :lawaitlist, :waityear
t.rename :other_reason_for_leaving_last_settled_home, :reasonother
t.rename :property_void_date, :voiddate
end
end
end

30
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: 202202071123100) do ActiveRecord::Schema[7.0].define(version: 2022_04_11_092231) 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"
@ -86,7 +86,6 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.integer "startertenancy" t.integer "startertenancy"
t.integer "tenancylength" t.integer "tenancylength"
t.integer "tenancy" t.integer "tenancy"
t.integer "landlord"
t.string "ppostcode_full" t.string "ppostcode_full"
t.integer "rsnvac" t.integer "rsnvac"
t.integer "unittype_gn" t.integer "unittype_gn"
@ -98,20 +97,19 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.integer "benefits" t.integer "benefits"
t.integer "period" t.integer "period"
t.integer "layear" t.integer "layear"
t.integer "lawaitlist" t.integer "waityear"
t.string "postcode_full" t.string "postcode_full"
t.integer "reasonpref" t.integer "reasonpref"
t.integer "cbl" t.integer "cbl"
t.integer "chr" t.integer "chr"
t.integer "cap" t.integer "cap"
t.string "other_reason_for_leaving_last_settled_home" t.string "reasonother"
t.integer "housingneeds_a" t.integer "housingneeds_a"
t.integer "housingneeds_b" t.integer "housingneeds_b"
t.integer "housingneeds_c" t.integer "housingneeds_c"
t.integer "housingneeds_f" t.integer "housingneeds_f"
t.integer "housingneeds_g" t.integer "housingneeds_g"
t.integer "housingneeds_h" t.integer "housingneeds_h"
t.integer "accessibility_requirements_prefer_not_to_say"
t.integer "illness_type_1" t.integer "illness_type_1"
t.integer "illness_type_2" t.integer "illness_type_2"
t.integer "illness_type_3" t.integer "illness_type_3"
@ -132,7 +130,7 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.string "property_owner_organisation" t.string "property_owner_organisation"
t.string "property_manager_organisation" t.string "property_manager_organisation"
t.string "sale_or_letting" t.string "sale_or_letting"
t.string "intermediate_rent_product_name" t.string "irproduct_other"
t.string "purchaser_code" t.string "purchaser_code"
t.integer "reason" t.integer "reason"
t.string "propcode" t.string "propcode"
@ -141,16 +139,8 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.string "prevloc" t.string "prevloc"
t.integer "hb" t.integer "hb"
t.integer "hbrentshortfall" t.integer "hbrentshortfall"
t.string "postcode"
t.string "postcod2"
t.string "ppostc1"
t.string "ppostc2"
t.integer "property_relet" t.integer "property_relet"
t.datetime "mrcdate", precision: nil t.datetime "mrcdate", precision: nil
t.integer "mrcday"
t.integer "mrcmonth"
t.integer "mrcyear"
t.integer "other_hhmemb"
t.integer "incref" t.integer "incref"
t.datetime "sale_completion_date", precision: nil t.datetime "sale_completion_date", precision: nil
t.datetime "startdate", precision: nil t.datetime "startdate", precision: nil
@ -158,7 +148,7 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.integer "first_time_property_let_as_social_housing" t.integer "first_time_property_let_as_social_housing"
t.integer "unitletas" t.integer "unitletas"
t.integer "builtype" t.integer "builtype"
t.datetime "property_void_date", precision: nil t.datetime "voiddate", precision: nil
t.bigint "owning_organisation_id" t.bigint "owning_organisation_id"
t.bigint "managing_organisation_id" t.bigint "managing_organisation_id"
t.integer "renttype" t.integer "renttype"
@ -167,9 +157,6 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.integer "postcode_known" t.integer "postcode_known"
t.integer "la_known" t.integer "la_known"
t.boolean "is_la_inferred" t.boolean "is_la_inferred"
t.integer "day"
t.integer "month"
t.integer "year"
t.integer "totchild" t.integer "totchild"
t.integer "totelder" t.integer "totelder"
t.integer "totadult" t.integer "totadult"
@ -219,9 +206,6 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.decimal "wtshortfall", precision: 10, scale: 2 t.decimal "wtshortfall", precision: 10, scale: 2
t.integer "refused" t.integer "refused"
t.integer "housingneeds" t.integer "housingneeds"
t.integer "vday"
t.integer "vmonth"
t.integer "vyear"
t.decimal "wchchrg", precision: 10, scale: 2 t.decimal "wchchrg", precision: 10, scale: 2
t.integer "newprop" t.integer "newprop"
t.string "relat2" t.string "relat2"
@ -232,6 +216,9 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.string "relat7" t.string "relat7"
t.string "relat8" t.string "relat8"
t.integer "rent_value_check" t.integer "rent_value_check"
t.integer "old_form_id"
t.integer "lar"
t.integer "irproduct"
t.index ["managing_organisation_id"], name: "index_case_logs_on_managing_organisation_id" t.index ["managing_organisation_id"], name: "index_case_logs_on_managing_organisation_id"
t.index ["owning_organisation_id"], name: "index_case_logs_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_case_logs_on_owning_organisation_id"
end end
@ -318,6 +305,7 @@ ActiveRecord::Schema[7.0].define(version: 202202071123100) do
t.string "last_sign_in_ip" t.string "last_sign_in_ip"
t.integer "role" t.integer "role"
t.string "old_user_id" t.string "old_user_id"
t.string "phone"
t.integer "failed_attempts", default: 0 t.integer "failed_attempts", default: 0
t.string "unlock_token" t.string "unlock_token"
t.datetime "locked_at", precision: nil t.datetime "locked_at", precision: nil

2
docs/api/DLUHC-CORE-Data.v1.json

@ -361,7 +361,7 @@
"cap": 0, "cap": 0,
"hbrentshortfall": 0, "hbrentshortfall": 0,
"tshortfall": 12, "tshortfall": 12,
"other_reason_for_leaving_last_settled_home": null, "reasonother": null,
"housingneeds_a": 1, "housingneeds_a": 1,
"housingneeds_b": 0, "housingneeds_b": 0,
"housingneeds_c": 0, "housingneeds_c": 0,

19
spec/components/document_list_component_spec.rb

@ -0,0 +1,19 @@
require "rails_helper"
RSpec.describe DocumentListComponent, type: :component do
let(:items) do
[{ name: "PDF Form", href: "/forms/form.pdf", description: "An important form", metadata: "4 pages" },
{ name: "Website", href: "https://example.com" }]
end
context "when rendering tabs" do
it "all of the nav tabs specified in the items hash are passed to it" do
result = render_inline(described_class.new(items:))
expect(result.text).to include("PDF Form")
expect(result.text).to include("An important form")
expect(result.text).to include("4 pages")
expect(result.text).to include("Website")
end
end
end

27
spec/components/primary_navigation_component_spec.rb

@ -0,0 +1,27 @@
require "rails_helper"
RSpec.describe PrimaryNavigationComponent, type: :component do
let(:items) do
[{ name: "Organisations", url: "#", current: true },
{ name: "Users", url: "#" },
{ name: "Logs ", url: "#" }]
end
context "when the item is 'current' in nav tabs" do
it "then that tab appears as selected" do
result = render_inline(described_class.new(items:))
expect(result.css('.app-primary-navigation__link[aria-current="page"]').text).to include("Organisations")
end
end
context "when rendering tabs" do
it "all of the nav tabs specified in the items hash are passed to it" do
result = render_inline(described_class.new(items:))
expect(result.text).to include("Organisations")
expect(result.text).to include("Users")
expect(result.text).to include("Logs")
end
end
end

27
spec/components/tab_navigation_component_spec.rb

@ -1,27 +0,0 @@
require "rails_helper"
RSpec.describe TabNavigationComponent, type: :component do
let(:items) do
[{ name: "Application", url: "#", current: true },
{ name: "Notes", url: "#" },
{ name: "Timeline", url: "#" }]
end
context "when the item is 'current' in nav tabs" do
it "then that tab appears as selected" do
result = render_inline(described_class.new(items:))
expect(result.css('.app-tab-navigation__link[aria-current="page"]').text).to include("Application")
end
end
context "when rendering tabs" do
it "all of the nav tabs specified in the items hash are passed to it" do
result = render_inline(described_class.new(items:))
expect(result.text).to include("Application")
expect(result.text).to include("Notes")
expect(result.text).to include("Timeline")
end
end
end

4
spec/controllers/admin/admin_users_controller_spec.rb

@ -28,7 +28,7 @@ describe Admin::AdminUsersController, type: :controller do
let(:params) { { admin_user: { email: "test2@example.com", password: "pAssword1", phone: "07566126368" } } } let(:params) { { admin_user: { email: "test2@example.com", password: "pAssword1", phone: "07566126368" } } }
it "creates a new admin user" do it "creates a new admin user" do
expect { post :create, session: valid_session, params: params }.to change(AdminUser, :count).by(1) expect { post :create, session: valid_session, params: }.to change(AdminUser, :count).by(1)
end end
it "tracks who created the record" do it "tracks who created the record" do
@ -59,7 +59,7 @@ describe Admin::AdminUsersController, type: :controller do
let(:params) { { id: admin_user.id, admin_user: { email: } } } let(:params) { { id: admin_user.id, admin_user: { email: } } }
before do before do
patch :update, session: valid_session, params: params patch :update, session: valid_session, params:
end end
it "updates the user without needing to input a password" do it "updates the user without needing to input a password" do

4
spec/controllers/admin/case_logs_controller_spec.rb

@ -40,7 +40,7 @@ describe Admin::CaseLogsController, type: :controller do
end end
it "creates a new case log" do it "creates a new case log" do
expect { post :create, session: valid_session, params: params }.to change(CaseLog, :count).by(1) expect { post :create, session: valid_session, params: }.to change(CaseLog, :count).by(1)
end end
it "tracks who created the record" do it "tracks who created the record" do
@ -71,7 +71,7 @@ describe Admin::CaseLogsController, type: :controller do
let(:params) { { id: case_log.id, case_log: { tenant_code: } } } let(:params) { { id: case_log.id, case_log: { tenant_code: } } }
before do before do
patch :update, session: valid_session, params: params patch :update, session: valid_session, params:
end end
it "updates the case log" do it "updates the case log" do

4
spec/controllers/admin/organisations_controller_spec.rb

@ -29,7 +29,7 @@ describe Admin::OrganisationsController, type: :controller do
let(:params) { { organisation: { name: "DLUHC", provider_type: "LA" } } } let(:params) { { organisation: { name: "DLUHC", provider_type: "LA" } } }
it "creates a organisation" do it "creates a organisation" do
expect { post :create, session: valid_session, params: params }.to change(Organisation, :count).by(1) expect { post :create, session: valid_session, params: }.to change(Organisation, :count).by(1)
end end
it "tracks who created the record" do it "tracks who created the record" do
@ -59,7 +59,7 @@ describe Admin::OrganisationsController, type: :controller do
let(:params) { { id: organisation.id, organisation: { name: } } } let(:params) { { id: organisation.id, organisation: { name: } } }
before do before do
patch :update, session: valid_session, params: params patch :update, session: valid_session, params:
end end
it "updates the organisation" do it "updates the organisation" do

4
spec/controllers/admin/users_controller_spec.rb

@ -40,7 +40,7 @@ describe Admin::UsersController, type: :controller do
end end
it "creates a new user" do it "creates a new user" do
expect { post :create, session: valid_session, params: params }.to change(User, :count).by(1) expect { post :create, session: valid_session, params: }.to change(User, :count).by(1)
end end
it "tracks who created the record" do it "tracks who created the record" do
@ -73,7 +73,7 @@ describe Admin::UsersController, type: :controller do
let(:params) { { id: user.id, user: { name: } } } let(:params) { { id: user.id, user: { name: } } }
before do before do
patch :update, session: valid_session, params: params patch :update, session: valid_session, params:
end end
it "updates the user without needing to input a password" do it "updates the user without needing to input a password" do

42
spec/factories/case_log.rb

@ -7,7 +7,6 @@ FactoryBot.define do
needstype { 1 } needstype { 1 }
rent_type { 1 } rent_type { 1 }
startdate { Time.zone.local(2022, 5, 1) } startdate { Time.zone.local(2022, 5, 1) }
year { 2022 }
end end
trait :in_progress do trait :in_progress do
status { 1 } status { 1 }
@ -21,7 +20,7 @@ FactoryBot.define do
status { 1 } status { 1 }
ecstat1 { 1 } ecstat1 { 1 }
earnings { 750 } earnings { 750 }
incfreq { 0 } incfreq { 1 }
end end
trait :conditional_section_complete do trait :conditional_section_complete do
tenant_code { "TH356" } tenant_code { "TH356" }
@ -30,19 +29,17 @@ FactoryBot.define do
ethnic { 2 } ethnic { 2 }
national { 4 } national { 4 }
ecstat1 { 2 } ecstat1 { 2 }
other_hhmemb { 0 } hhmemb { 1 }
end end
trait :completed do trait :completed do
status { 2 } status { 2 }
tenant_code { "BZ737" } tenant_code { "BZ737" }
postcode { "NW1 7TY" }
age1 { 35 } age1 { 35 }
sex1 { "F" } sex1 { "F" }
ethnic { 2 } ethnic { 2 }
national { 4 } national { 4 }
prevten { 6 } prevten { 6 }
ecstat1 { 0 } ecstat1 { 0 }
other_hhmemb { 1 }
hhmemb { 2 } hhmemb { 2 }
relat2 { "P" } relat2 { "P" }
age2 { 32 } age2 { 32 }
@ -52,25 +49,21 @@ FactoryBot.define do
underoccupation_benefitcap { 0 } underoccupation_benefitcap { 0 }
leftreg { 1 } leftreg { 1 }
reservist { 0 } reservist { 0 }
illness { 0 } illness { 1 }
preg_occ { 1 } preg_occ { 2 }
tenancy_code { "BZ757" } tenancy_code { "BZ757" }
startertenancy { 0 } startertenancy { 0 }
tenancylength { 5 } tenancylength { 5 }
tenancy { 3 } tenancy { 1 }
landlord { 1 }
ppostcode_full { "SE2 6RT" } ppostcode_full { "SE2 6RT" }
rsnvac { 7 } rsnvac { 6 }
unittype_gn { 2 } unittype_gn { 7 }
beds { 3 } beds { 3 }
property_void_date { "03/11/2019" } voiddate { "03/11/2019" }
vday { 3 }
vmonth { 11 }
vyear { 2019 }
offered { 2 } offered { 2 }
wchair { 1 } wchair { 1 }
earnings { 68 } earnings { 68 }
incfreq { 0 } incfreq { 1 }
benefits { 1 } benefits { 1 }
period { 2 } period { 2 }
brent { 200 } brent { 200 }
@ -79,20 +72,19 @@ FactoryBot.define do
supcharg { 35 } supcharg { 35 }
tcharge { 325 } tcharge { 325 }
layear { 2 } layear { 2 }
lawaitlist { 1 } waityear { 1 }
postcode_full { "NW1 5TY" } postcode_full { "NW1 5TY" }
reasonpref { 1 } reasonpref { 1 }
cbl { 1 } cbl { 1 }
chr { 1 } chr { 1 }
cap { 0 } cap { 0 }
other_reason_for_leaving_last_settled_home { nil } reasonother { nil }
housingneeds_a { 1 } housingneeds_a { 1 }
housingneeds_b { 0 } housingneeds_b { 0 }
housingneeds_c { 0 } housingneeds_c { 0 }
housingneeds_f { 0 } housingneeds_f { 0 }
housingneeds_g { 0 } housingneeds_g { 0 }
housingneeds_h { 0 } housingneeds_h { 0 }
accessibility_requirements_prefer_not_to_say { 0 }
illness_type_1 { 0 } illness_type_1 { 0 }
illness_type_2 { 1 } illness_type_2 { 1 }
illness_type_3 { 0 } illness_type_3 { 0 }
@ -115,7 +107,6 @@ FactoryBot.define do
property_manager_organisation { "Test" } property_manager_organisation { "Test" }
renewal { 0 } renewal { 0 }
rent_type { 1 } rent_type { 1 }
intermediate_rent_product_name { 2 }
needstype { 1 } needstype { 1 }
purchaser_code { 798_794 } purchaser_code { 798_794 }
reason { 4 } reason { 4 }
@ -126,21 +117,12 @@ FactoryBot.define do
hb { 6 } hb { 6 }
hbrentshortfall { 0 } hbrentshortfall { 0 }
tshortfall { 12 } tshortfall { 12 }
postcod2 { "w3" }
ppostc1 { "w3" }
ppostc2 { "w3" }
property_relet { 0 } property_relet { 0 }
mrcdate { Time.utc(2020, 5, 0o5, 10, 36, 49) } mrcdate { Time.utc(2020, 5, 0o5, 10, 36, 49) }
mrcday { mrcdate.day }
mrcmonth { mrcdate.month }
mrcyear { mrcdate.year }
incref { 0 } incref { 0 }
sale_completion_date { nil } sale_completion_date { nil }
startdate { Time.utc(2022, 2, 2, 10, 36, 49) } startdate { Time.utc(2022, 2, 2, 10, 36, 49) }
day { startdate.day } armedforces { 1 }
month { startdate.month }
year { startdate.year }
armedforces { 0 }
builtype { 1 } builtype { 1 }
unitletas { 2 } unitletas { 2 }
has_benefits { 1 } has_benefits { 1 }

16
spec/features/form/check_answers_page_spec.rb

@ -53,7 +53,7 @@ RSpec.describe "Form Check Answers Page" do
it "has question headings based on the subsection" do it "has question headings based on the subsection" do
visit("/logs/#{id}/#{subsection}/check-answers") visit("/logs/#{id}/#{subsection}/check-answers")
question_labels = ["Tenant code", "Lead tenant’s age", "Lead tenant’s gender identity", "Number of Other Household Members"] question_labels = ["Tenant code", "Lead tenant’s age", "Lead tenant’s gender identity", "Number of Household Members"]
question_labels.each do |label| question_labels.each do |label|
expect(page).to have_content(label) expect(page).to have_content(label)
end end
@ -113,7 +113,7 @@ RSpec.describe "Form Check Answers Page" do
it "displays conditional question that were visited" do it "displays conditional question that were visited" do
visit("/logs/#{id}/conditional-question") visit("/logs/#{id}/conditional-question")
choose("case-log-preg-occ-1-field", allow_label_click: true) choose("case-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
visit("/logs/#{id}/#{conditional_subsection}/check-answers") visit("/logs/#{id}/#{conditional_subsection}/check-answers")
question_labels = ["Has the condition been met?", "Has the condition not been met?"] question_labels = ["Has the condition been met?", "Has the condition not been met?"]
@ -151,7 +151,7 @@ RSpec.describe "Form Check Answers Page" do
tenant_code: "123", tenant_code: "123",
age1: 35, age1: 35,
sex1: "M", sex1: "M",
other_hhmemb: 0, hhmemb: 1,
) )
end end
@ -164,9 +164,9 @@ RSpec.describe "Form Check Answers Page" do
tenant_code: "123", tenant_code: "123",
age1: 35, age1: 35,
sex1: "M", sex1: "M",
other_hhmemb: 0, hhmemb: 1,
armedforces: 3, armedforces: 3,
illness: 0, illness: 1,
) )
end end
@ -179,9 +179,9 @@ RSpec.describe "Form Check Answers Page" do
tenant_code: "123", tenant_code: "123",
age1: 35, age1: 35,
sex1: "M", sex1: "M",
other_hhmemb: 0, hhmemb: 1,
armedforces: 3, armedforces: 3,
illness: 0, illness: 1,
housingneeds_h: 1, housingneeds_h: 1,
la: "E06000014", la: "E06000014",
illness_type_1: 1, illness_type_1: 1,
@ -197,7 +197,7 @@ RSpec.describe "Form Check Answers Page" do
tenant_code: nil, tenant_code: nil,
age1: nil, age1: nil,
layear: 2, layear: 2,
lawaitlist: 1, waityear: 1,
postcode_full: "NW1 5TY", postcode_full: "NW1 5TY",
reason: 4, reason: 4,
ppostcode_full: "SE2 6RT", ppostcode_full: "SE2 6RT",

6
spec/features/form/conditional_questions_spec.rb

@ -27,11 +27,11 @@ RSpec.describe "Form Conditional Questions" do
it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", js: true do it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", js: true do
visit("/logs/#{id}/armed-forces") visit("/logs/#{id}/armed-forces")
# Something about our styling makes the selenium webdriver think the actual radio buttons are not visible so we allow label click here # Something about our styling makes the selenium webdriver think the actual radio buttons are not visible so we allow label click here
choose("case-log-armedforces-0-field", allow_label_click: true)
fill_in("case-log-leftreg-field", with: "text")
choose("case-log-armedforces-1-field", allow_label_click: true) choose("case-log-armedforces-1-field", allow_label_click: true)
fill_in("case-log-leftreg-field", with: "text")
choose("case-log-armedforces-4-field", allow_label_click: true)
expect(page).not_to have_field("case-log-leftreg-field") expect(page).not_to have_field("case-log-leftreg-field")
choose("case-log-armedforces-0-field", allow_label_click: true) choose("case-log-armedforces-1-field", allow_label_click: true)
expect(page).to have_field("case-log-leftreg-field", with: "") expect(page).to have_field("case-log-leftreg-field", with: "")
end end
end end

4
spec/features/form/form_navigation_spec.rb

@ -19,7 +19,7 @@ RSpec.describe "Form Navigation" do
age1: { type: "numeric", answer: 25, path: "person-1-age" }, age1: { type: "numeric", answer: 25, path: "person-1-age" },
sex1: { type: "radio", answer: "Female", path: "person-1-gender" }, sex1: { type: "radio", answer: "Female", path: "person-1-gender" },
ecstat1: { type: "radio", answer: 3, path: "person-1-working-situation" }, ecstat1: { type: "radio", answer: 3, path: "person-1-working-situation" },
other_hhmemb: { type: "numeric", answer: 2, path: "household-number-of-other-members" }, hhmemb: { type: "numeric", answer: 1, path: "household-number-of-members" },
} }
end end
@ -71,7 +71,7 @@ RSpec.describe "Form Navigation" do
visit("/logs") visit("/logs")
visit("/logs/#{id}/net-income") visit("/logs/#{id}/net-income")
fill_in("case-log-earnings-field", with: 740) fill_in("case-log-earnings-field", with: 740)
choose("case-log-incfreq-0-field", allow_label_click: true) choose("case-log-incfreq-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
click_link(text: "Back") click_link(text: "Back")
click_link(text: "Back") click_link(text: "Back")

6
spec/features/form/page_routing_spec.rb

@ -24,12 +24,12 @@ RSpec.describe "Form Page Routing" do
visit("/logs/#{id}/conditional-question") visit("/logs/#{id}/conditional-question")
# using a question name that is already in the db to avoid # using a question name that is already in the db to avoid
# having to add a new column to the db for this test # having to add a new column to the db for this test
choose("case-log-preg-occ-0-field", allow_label_click: true) choose("case-log-preg-occ-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{id}/conditional-question-yes-page") expect(page).to have_current_path("/logs/#{id}/conditional-question-yes-page")
click_link(text: "Back") click_link(text: "Back")
expect(page).to have_current_path("/logs/#{id}/conditional-question") expect(page).to have_current_path("/logs/#{id}/conditional-question")
choose("case-log-preg-occ-1-field", allow_label_click: true) choose("case-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{id}/conditional-question-no-page") expect(page).to have_current_path("/logs/#{id}/conditional-question-no-page")
end end
@ -40,7 +40,7 @@ RSpec.describe "Form Page Routing" do
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{id}/person-1-working-situation") expect(page).to have_current_path("/logs/#{id}/person-1-working-situation")
visit("/logs/#{id}/conditional-question") visit("/logs/#{id}/conditional-question")
choose("case-log-preg-occ-1-field", allow_label_click: true) choose("case-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{id}/conditional-question-no-page") expect(page).to have_current_path("/logs/#{id}/conditional-question-no-page")
click_button("Save and continue") click_button("Save and continue")

2
spec/features/form/saving_data_spec.rb

@ -26,7 +26,7 @@ RSpec.describe "Form Saving Data" do
tenant_code: { type: "text", answer: "BZ737", path: "tenant_code" }, tenant_code: { type: "text", answer: "BZ737", path: "tenant_code" },
age1: { type: "numeric", answer: 25, path: "person_1_age" }, age1: { type: "numeric", answer: 25, path: "person_1_age" },
sex1: { type: "radio", answer: { "F" => "Female" }, path: "person_1_gender" }, sex1: { type: "radio", answer: { "F" => "Female" }, path: "person_1_gender" },
other_hhmemb: { type: "numeric", answer: 2, path: "household_number_of_other_members" }, hhmemb: { type: "numeric", answer: 3, path: "household_number_of_members" },
} }
end end

4
spec/features/form/validations_spec.rb

@ -127,7 +127,7 @@ RSpec.describe "validations" do
it "prompts the user to confirm the value is correct with an interruption screen" do it "prompts the user to confirm the value is correct with an interruption screen" do
visit("/logs/#{case_log.id}/net-income") visit("/logs/#{case_log.id}/net-income")
fill_in("case-log-earnings-field", with: income_over_soft_limit) fill_in("case-log-earnings-field", with: income_over_soft_limit)
choose("case-log-incfreq-0-field", allow_label_click: true) choose("case-log-incfreq-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{case_log.id}/net-income-value-check") expect(page).to have_current_path("/logs/#{case_log.id}/net-income-value-check")
expect(page).to have_content("Net income is outside the expected range based on the lead tenant’s working situation") expect(page).to have_content("Net income is outside the expected range based on the lead tenant’s working situation")
@ -141,7 +141,7 @@ RSpec.describe "validations" do
it "returns the user to the previous question if they do not confirm the value as correct on the interruption screen" do it "returns the user to the previous question if they do not confirm the value as correct on the interruption screen" do
visit("/logs/#{case_log.id}/net-income") visit("/logs/#{case_log.id}/net-income")
fill_in("case-log-earnings-field", with: income_over_soft_limit) fill_in("case-log-earnings-field", with: income_over_soft_limit)
choose("case-log-incfreq-0-field", allow_label_click: true) choose("case-log-incfreq-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")
choose("case-log-net-income-value-check-1-field", allow_label_click: true) choose("case-log-net-income-value-check-1-field", allow_label_click: true)
click_button("Save and continue") click_button("Save and continue")

9
spec/features/organisation_spec.rb

@ -24,7 +24,7 @@ RSpec.describe "User Features" do
context "when viewing organisation page" do context "when viewing organisation page" do
it "defaults to organisation details" do it "defaults to organisation details" do
visit("/logs") visit("/logs")
click_link("Your organisation") click_link("About your organisation")
expect(page).to have_content(user.organisation.name) expect(page).to have_content(user.organisation.name)
end end
@ -32,7 +32,7 @@ RSpec.describe "User Features" do
visit("/organisations/#{org_id}") visit("/organisations/#{org_id}")
click_link("Users") click_link("Users")
expect(page).to have_current_path("/organisations/#{org_id}/users") expect(page).to have_current_path("/organisations/#{org_id}/users")
click_link("Details") click_link("About your organisation")
expect(page).to have_current_path("/organisations/#{org_id}/details") expect(page).to have_current_path("/organisations/#{org_id}/details")
end end
end end
@ -72,10 +72,11 @@ RSpec.describe "User Features" do
context "when viewing organisation page" do context "when viewing organisation page" do
it "can see the details tab and users tab" do it "can see the details tab and users tab" do
visit("/logs") visit("/logs")
click_link("Your organisation") click_link("About your organisation")
expect(page).to have_current_path("/organisations/#{org_id}/details") expect(page).to have_current_path("/organisations/#{org_id}/details")
expect(page).to have_link("Details") expect(page).to have_link("Logs")
expect(page).to have_link("Users") expect(page).to have_link("Users")
expect(page).to have_link("About your organisation")
end end
end end
end end

8
spec/features/reset_password.html.erb

@ -2,7 +2,7 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: 'Back', text: "Back",
href: :back, href: :back,
) %> ) %>
<% end %> <% end %>
@ -20,12 +20,10 @@
<%= f.govuk_password_field :password, <%= f.govuk_password_field :password,
label: { text: "New password" }, label: { text: "New password" },
hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil, hint: @minimum_password_length ? { text: "Your password must be at least #{@minimum_password_length} characters and hard to guess." } : nil,
autocomplete: "new-password" autocomplete: "new-password" %>
%>
<%= f.govuk_password_field :password_confirmation, <%= f.govuk_password_field :password_confirmation,
label: { text: "Confirm new password" } label: { text: "Confirm new password" } %>
%>
<%= f.govuk_submit "Update" %> <%= f.govuk_submit "Update" %>
</div> </div>

30
spec/fixtures/complete_case_log.json vendored

@ -6,10 +6,9 @@
"ethnic": 0, "ethnic": 0,
"national": 0, "national": 0,
"prevten": 6, "prevten": 6,
"armedforces": 0, "armedforces": 1,
"armed_forces_partner": "", "armed_forces_partner": "",
"ecstat1": 1, "ecstat1": 1,
"other_hhmemb": 7,
"hhmemb": 8, "hhmemb": 8,
"relat2": "P", "relat2": "P",
"age2": 32, "age2": 32,
@ -43,39 +42,30 @@
"underoccupation_benefitcap": 0, "underoccupation_benefitcap": 0,
"leftreg": 1, "leftreg": 1,
"reservist": 0, "reservist": 0,
"illness": 0, "illness": 1,
"preg_occ": 0, "preg_occ": 1,
"tenancy_code": "BZ757", "tenancy_code": "BZ757",
"startdate": "12/12/2021", "startdate": "12/12/2021",
"day": 12,
"month": 12,
"year": 2021,
"startertenancy": 0, "startertenancy": 0,
"tenancylength": 5, "tenancylength": 5,
"tenancy": 3, "tenancy": 1,
"landlord": 1, "landlord": 1,
"la": "Barnet", "la": "Barnet",
"postcode_full": "NW1 5TY", "postcode_full": "NW1 5TY",
"property_relet": 0, "property_relet": 0,
"rsnvac": 0, "rsnvac": 14,
"property_reference": "P9876", "property_reference": "P9876",
"unittype_gn": 2, "unittype_gn": 7,
"property_building_type": "dummy", "property_building_type": "dummy",
"beds": 3, "beds": 3,
"property_void_date": "10/10/2020", "voiddate": "10/10/2020",
"vday": 10,
"vmonth": 10,
"vyear": 2020,
"majorrepairs": 1, "majorrepairs": 1,
"mrcdate": "11/11/2020", "mrcdate": "11/11/2020",
"mrcday": 11,
"mrcmonth": 11,
"mrcyear": 2020,
"offered": 2, "offered": 2,
"wchair": 1, "wchair": 1,
"net_income_known": 1, "net_income_known": 1,
"earnings": 150, "earnings": 150,
"incfreq": 0, "incfreq": 1,
"benefits": 1, "benefits": 1,
"hb": 1, "hb": 1,
"period": 2, "period": 2,
@ -95,7 +85,7 @@
"cap": 0, "cap": 0,
"hbrentshortfall": 0, "hbrentshortfall": 0,
"tshortfall": 12, "tshortfall": 12,
"other_reason_for_leaving_last_settled_home": null, "reasonother": null,
"housingneeds_a": 1, "housingneeds_a": 1,
"housingneeds_b": 0, "housingneeds_b": 0,
"housingneeds_c": 0, "housingneeds_c": 0,
@ -131,8 +121,6 @@
"propcode": "123", "propcode": "123",
"postcode": "a1", "postcode": "a1",
"postcod2": "w3", "postcod2": "w3",
"ppostc1": "w3",
"ppostc2": "w3",
"first_time_property_let_as_social_housing": 0, "first_time_property_let_as_social_housing": 0,
"unitletas": 1, "unitletas": 1,
"builtype": 0, "builtype": 0,

41
spec/fixtures/exports/case_logs.xml vendored

@ -38,38 +38,36 @@
<underoccupation_benefitcap>0</underoccupation_benefitcap> <underoccupation_benefitcap>0</underoccupation_benefitcap>
<leftreg>1</leftreg> <leftreg>1</leftreg>
<reservist>0</reservist> <reservist>0</reservist>
<illness>0</illness> <illness>1</illness>
<preg_occ>1</preg_occ> <preg_occ>2</preg_occ>
<tenancy_code>BZ757</tenancy_code> <tenancy_code>BZ757</tenancy_code>
<startertenancy>0</startertenancy> <startertenancy>0</startertenancy>
<tenancylength>5</tenancylength> <tenancylength>5</tenancylength>
<tenancy>3</tenancy> <tenancy>1</tenancy>
<landlord>1</landlord>
<ppostcode_full>SE26RT</ppostcode_full> <ppostcode_full>SE26RT</ppostcode_full>
<rsnvac>7</rsnvac> <rsnvac>6</rsnvac>
<unittype_gn>2</unittype_gn> <unittype_gn>7</unittype_gn>
<beds>3</beds> <beds>3</beds>
<offered>2</offered> <offered>2</offered>
<wchair>1</wchair> <wchair>1</wchair>
<earnings>68</earnings> <earnings>68</earnings>
<incfreq>0</incfreq> <incfreq>1</incfreq>
<benefits>1</benefits> <benefits>1</benefits>
<period>2</period> <period>2</period>
<layear>2</layear> <layear>2</layear>
<lawaitlist>1</lawaitlist> <waityear>1</waityear>
<postcode_full>NW15TY</postcode_full> <postcode_full>NW15TY</postcode_full>
<reasonpref>1</reasonpref> <reasonpref>1</reasonpref>
<cbl>1</cbl> <cbl>1</cbl>
<chr>1</chr> <chr>1</chr>
<cap>0</cap> <cap>0</cap>
<other_reason_for_leaving_last_settled_home/> <reasonother/>
<housingneeds_a>1</housingneeds_a> <housingneeds_a>1</housingneeds_a>
<housingneeds_b>0</housingneeds_b> <housingneeds_b>0</housingneeds_b>
<housingneeds_c>0</housingneeds_c> <housingneeds_c>0</housingneeds_c>
<housingneeds_f>0</housingneeds_f> <housingneeds_f>0</housingneeds_f>
<housingneeds_g>0</housingneeds_g> <housingneeds_g>0</housingneeds_g>
<housingneeds_h>0</housingneeds_h> <housingneeds_h>0</housingneeds_h>
<accessibility_requirements_prefer_not_to_say>0</accessibility_requirements_prefer_not_to_say>
<illness_type_1>0</illness_type_1> <illness_type_1>0</illness_type_1>
<illness_type_2>1</illness_type_2> <illness_type_2>1</illness_type_2>
<illness_type_3>0</illness_type_3> <illness_type_3>0</illness_type_3>
@ -90,7 +88,7 @@
<property_owner_organisation>Test</property_owner_organisation> <property_owner_organisation>Test</property_owner_organisation>
<property_manager_organisation>Test</property_manager_organisation> <property_manager_organisation>Test</property_manager_organisation>
<sale_or_letting/> <sale_or_letting/>
<intermediate_rent_product_name>2</intermediate_rent_product_name> <irproduct_other/>
<purchaser_code>798794</purchaser_code> <purchaser_code>798794</purchaser_code>
<reason>4</reason> <reason>4</reason>
<propcode>123</propcode> <propcode>123</propcode>
@ -99,24 +97,16 @@
<prevloc>E07000105</prevloc> <prevloc>E07000105</prevloc>
<hb>6</hb> <hb>6</hb>
<hbrentshortfall>0</hbrentshortfall> <hbrentshortfall>0</hbrentshortfall>
<postcode>NW1</postcode>
<postcod2>5TY</postcod2>
<ppostc1>SE2</ppostc1>
<ppostc2>6RT</ppostc2>
<property_relet>0</property_relet> <property_relet>0</property_relet>
<mrcdate>2020-05-05 10:36:49 UTC</mrcdate> <mrcdate>2020-05-05 10:36:49 UTC</mrcdate>
<mrcday>5</mrcday>
<mrcmonth>5</mrcmonth>
<mrcyear>2020</mrcyear>
<other_hhmemb>1</other_hhmemb>
<incref>0</incref> <incref>0</incref>
<sale_completion_date/> <sale_completion_date/>
<startdate>2022-02-02 10:36:49 UTC</startdate> <startdate>2022-02-02 10:36:49 UTC</startdate>
<armedforces>0</armedforces> <armedforces>1</armedforces>
<first_time_property_let_as_social_housing/> <first_time_property_let_as_social_housing/>
<unitletas>2</unitletas> <unitletas>2</unitletas>
<builtype>1</builtype> <builtype>1</builtype>
<property_void_date>2019-11-03 00:00:00 UTC</property_void_date> <voiddate>2019-11-03 00:00:00 UTC</voiddate>
<owning_organisation_id>{owning_org_id}</owning_organisation_id> <owning_organisation_id>{owning_org_id}</owning_organisation_id>
<managing_organisation_id>{managing_org_id}</managing_organisation_id> <managing_organisation_id>{managing_org_id}</managing_organisation_id>
<renttype>2</renttype> <renttype>2</renttype>
@ -125,9 +115,6 @@
<postcode_known>1</postcode_known> <postcode_known>1</postcode_known>
<la_known>1</la_known> <la_known>1</la_known>
<is_la_inferred>false</is_la_inferred> <is_la_inferred>false</is_la_inferred>
<day>2</day>
<month>2</month>
<year>2022</year>
<totchild>0</totchild> <totchild>0</totchild>
<totelder>0</totelder> <totelder>0</totelder>
<totadult>2</totadult> <totadult>2</totadult>
@ -161,9 +148,6 @@
<wtshortfall>6.0</wtshortfall> <wtshortfall>6.0</wtshortfall>
<refused>0</refused> <refused>0</refused>
<housingneeds>1</housingneeds> <housingneeds>1</housingneeds>
<vday>3</vday>
<vmonth>11</vmonth>
<vyear>2019</vyear>
<wchchrg/> <wchchrg/>
<newprop>2</newprop> <newprop>2</newprop>
<relat2>P</relat2> <relat2>P</relat2>
@ -174,6 +158,9 @@
<relat7/> <relat7/>
<relat8/> <relat8/>
<rent_value_check/> <rent_value_check/>
<old_form_id/>
<lar/>
<irproduct/>
<providertype>1</providertype> <providertype>1</providertype>
</form> </form>
</forms> </forms>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save