diff --git a/.github/workflows/aws_deploy.yml b/.github/workflows/aws_deploy.yml
index c72c9d874..5af3c2d08 100644
--- a/.github/workflows/aws_deploy.yml
+++ b/.github/workflows/aws_deploy.yml
@@ -41,19 +41,17 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: ${{ env.app_repo_role }}
- name: Login to Amazon ECR
id: ecr-login
- uses: aws-actions/amazon-ecr-login@v1
- with:
- mask-password: "true"
+ uses: aws-actions/amazon-ecr-login@v2
- name: Check if image with tag already exists
run: |
@@ -81,16 +79,14 @@ jobs:
steps:
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: ${{ env.app_repo_role }}
- name: Login to Amazon ECR
id: ecr-login
- uses: aws-actions/amazon-ecr-login@v1
- with:
- mask-password: "true"
+ uses: aws-actions/amazon-ecr-login@v2
- name: Get timestamp
id: timestamp
@@ -112,7 +108,7 @@ jobs:
echo "image=$registry/$repository:$readable_tag" >> $GITHUB_ENV
- name: Configure AWS credentials for environment
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: arn:aws:iam::${{ inputs.aws_account_id }}:role/${{ inputs.aws_role_prefix }}-deployment
@@ -133,7 +129,7 @@ jobs:
image: ${{ env.image }}
- name: Update ad hoc task definition
- uses: aws-actions/amazon-ecs-deploy-task-definition@v1
+ uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
task-definition: ${{ steps.ad-hoc-task-def.outputs.task-definition }}
@@ -185,7 +181,7 @@ jobs:
image: ${{ env.image }}
- name: Deploy updated application
- uses: aws-actions/amazon-ecs-deploy-task-definition@v1
+ uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
cluster: ${{ inputs.aws_task_prefix }}-app
service: ${{ inputs.aws_task_prefix }}-app
@@ -207,7 +203,7 @@ jobs:
image: ${{ env.image }}
- name: Deploy updated sidekiq
- uses: aws-actions/amazon-ecs-deploy-task-definition@v1
+ uses: aws-actions/amazon-ecs-deploy-task-definition@v2
with:
cluster: ${{ inputs.aws_task_prefix }}-app
service: ${{ inputs.aws_task_prefix }}-sidekiq
diff --git a/.github/workflows/review_teardown_pipeline.yml b/.github/workflows/review_teardown_pipeline.yml
index 4303e4063..8925b3340 100644
--- a/.github/workflows/review_teardown_pipeline.yml
+++ b/.github/workflows/review_teardown_pipeline.yml
@@ -25,13 +25,13 @@ jobs:
steps:
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: ${{ env.app_repo_role }}
- name: Configure AWS credentials for review environment
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: arn:aws:iam::${{ env.aws_account_id }}:role/${{ env.aws_role_prefix }}-deployment
@@ -46,7 +46,7 @@ jobs:
network=$(aws ecs describe-services --cluster $cluster --services $service --query services[0].networkConfiguration)
overrides='{ "containerOverrides" : [{ "name" : "app", "command" : ["bundle", "exec", "rake", "db:drop"]}]}'
arn=$(aws ecs run-task --cluster $cluster --task-definition $ad_hoc_task_definition --network-configuration "$network" --overrides "$overrides" --group migrations --launch-type FARGATE --query tasks[0].taskArn)
- echo "Waiting for db prepare task to complete"
+ echo "Waiting for db drop task to complete"
temp=${arn##*/}
id=${temp%*\"}
aws ecs wait tasks-stopped --cluster $cluster --tasks $id
diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml
new file mode 100644
index 000000000..41a65be92
--- /dev/null
+++ b/.github/workflows/run_tests.yml
@@ -0,0 +1,411 @@
+name: Run Tests
+
+on:
+ workflow_call:
+ pull_request:
+ types:
+ - opened
+ - synchronize
+ merge_group:
+ workflow_dispatch:
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+ test:
+ name: Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec\/(?!features|models|requests|services)']
+
+ feature_test:
+ name: Feature Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake db:prepare
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/features --fail-fast --exclude-pattern "spec/features/accessibility_spec.rb"
+
+ model_test:
+ name: Model tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake db:prepare
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/models --fail-fast
+
+ requests_test:
+ name: Requests tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec/requests']
+
+ services_test:
+ name: Services Tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rake parallel:spec['spec\/services']
+
+ accessibility_test:
+ name: Accessibility tests
+ runs-on: ubuntu-latest
+
+ services:
+ postgres:
+ image: postgres:13.18
+ env:
+ POSTGRES_PASSWORD: password
+ POSTGRES_USER: postgres
+ POSTGRES_DB: data_collector
+ ports:
+ - 5432:5432
+ # Needed because the Postgres container does not provide a health check
+ # tmpfs makes database faster by using RAM
+ options: >-
+ --mount type=tmpfs,destination=/var/lib/postgresql/data
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ env:
+ RAILS_ENV: test
+ GEMFILE_RUBY_VERSION: 3.1.1
+ DB_HOST: localhost
+ DB_DATABASE: data_collector
+ DB_USERNAME: postgres
+ DB_PASSWORD: password
+ RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
+ PARALLEL_TEST_PROCESSORS: 4
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Create database
+ run: |
+ bundle exec rake parallel:setup
+
+ - name: Compile assets
+ run: |
+ bundle exec rake assets:precompile
+
+ - name: Run tests
+ run: |
+ bundle exec rspec spec/features/accessibility_spec.rb --fail-fast
+
+ lint:
+ name: Lint
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v4
+ with:
+ cache: yarn
+ node-version: 20
+
+ - name: Install packages and symlink local dependencies
+ run: |
+ yarn install --immutable --immutable-cache --check-cache
+
+ - name: Lint
+ run: |
+ bundle exec rake lint
+
+ audit:
+ name: Audit dependencies
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - name: Audit
+ run: |
+ bundle exec bundler-audit
diff --git a/.github/workflows/staging_pipeline.yml b/.github/workflows/staging_pipeline.yml
index e5447f4ef..a2e777db0 100644
--- a/.github/workflows/staging_pipeline.yml
+++ b/.github/workflows/staging_pipeline.yml
@@ -4,11 +4,6 @@ on:
push:
branches:
- main
- pull_request:
- types:
- - opened
- - synchronize
- merge_group:
workflow_dispatch:
defaults:
@@ -21,347 +16,13 @@ env:
repository: core
jobs:
- test:
- name: Tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rake parallel:spec['spec\/(?!features|models|requests)']
-
- feature_test:
- name: Feature Tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake db:prepare
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/features --fail-fast --exclude-pattern "spec/features/accessibility_spec.rb"
-
- model_test:
- name: Model tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake db:prepare
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/models --fail-fast
-
- requests_test:
- name: Requests tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rake parallel:spec['spec/requests']
-
- accessibility_test:
- name: Accessibility tests
- runs-on: ubuntu-latest
-
- services:
- postgres:
- image: postgres:13.5
- env:
- POSTGRES_PASSWORD: password
- POSTGRES_USER: postgres
- POSTGRES_DB: data_collector
- ports:
- - 5432:5432
- # Needed because the Postgres container does not provide a health check
- # tmpfs makes database faster by using RAM
- options: >-
- --mount type=tmpfs,destination=/var/lib/postgresql/data
- --health-cmd pg_isready
- --health-interval 10s
- --health-timeout 5s
- --health-retries 5
-
- env:
- RAILS_ENV: test
- GEMFILE_RUBY_VERSION: 3.1.1
- DB_HOST: localhost
- DB_DATABASE: data_collector
- DB_USERNAME: postgres
- DB_PASSWORD: password
- RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
- PARALLEL_TEST_PROCESSORS: 4
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Create database
- run: |
- bundle exec rake parallel:setup
-
- - name: Compile assets
- run: |
- bundle exec rake assets:precompile
-
- - name: Run tests
- run: |
- bundle exec rspec spec/features/accessibility_spec.rb --fail-fast
-
- lint:
- name: Lint
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Set up Node.js
- uses: actions/setup-node@v3
- with:
- cache: yarn
- node-version: 20
-
- - name: Install packages and symlink local dependencies
- run: |
- yarn install --immutable --immutable-cache --check-cache
-
- - name: Lint
- run: |
- bundle exec rake lint
-
- audit:
- name: Audit dependencies
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Set up Ruby
- uses: ruby/setup-ruby@v1
- with:
- bundler-cache: true
-
- - name: Audit
- run: |
- bundle exec bundler-audit
+ tests:
+ name: Run Tests
+ uses: ./.github/workflows/run_tests.yml
aws_deploy:
name: AWS Deploy
- if: github.ref == 'refs/heads/main'
- needs: [lint, test, feature_test, requests_test, model_test, audit]
+ needs: [tests]
uses: ./.github/workflows/aws_deploy.yml
with:
aws_account_id: 107155005276
@@ -379,13 +40,13 @@ jobs:
steps:
- name: Configure AWS credentials
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ env.aws_region }}
role-to-assume: ${{ env.app_repo_role }}
- name: Configure AWS credentials for the environment
- uses: aws-actions/configure-aws-credentials@v3
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: eu-west-2
role-to-assume: arn:aws:iam::107155005276:role/core-staging-deployment
diff --git a/Gemfile b/Gemfile
index e9af29d55..033706b39 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,11 +6,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.4"
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
-gem "rails", "~> 7.0.8.5"
+gem "rails", "~> 7.2.2"
# Use postgresql as the database for Active Record
gem "pg", "~> 1.1"
# Use Puma as the app server
-gem "puma", "~> 5.6"
+gem "puma", "~> 6.4"
# The modern asset pipeline for Rails [https://github.com/rails/propshaft]
gem "propshaft"
# Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails]
@@ -18,9 +18,9 @@ gem "jsbundling-rails"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.4.4", require: false
# GOV UK frontend components
-gem "govuk-components", "~> 5.1"
+gem "govuk-components", "~> 5.7"
# GOV UK component form builder DSL
-gem "govuk_design_system_formbuilder", "~> 5.0"
+gem "govuk_design_system_formbuilder", "~> 5.7"
# Convert Markdown into GOV.UK frontend-styled HTML
gem "govuk_markdown"
gem "redcarpet", "~> 3.6"
@@ -44,7 +44,7 @@ gem "view_component", "~> 3.9"
# Use the AWS S3 SDK as storage mechanism
gem "aws-sdk-s3"
# Track changes to models for auditing or versioning.
-gem "paper_trail"
+gem "paper_trail", "~> 15.2"
# Store active record objects in version whodunnits
gem "paper_trail-globalid"
@@ -90,7 +90,7 @@ group :development do
# 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
gem "erb_lint", require: false
- gem "rack-mini-profiler", "~> 2.0"
+ gem "rack-mini-profiler", "~> 3.3.0"
gem "rubocop-govuk", "4.3.0", require: false
gem "rubocop-performance", require: false
gem "rubocop-rails", require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index d2a5de05d..5017836a1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,75 +1,81 @@
GEM
remote: https://rubygems.org/
specs:
- actioncable (7.0.8.5)
- actionpack (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ actioncable (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (7.0.8.5)
- actionpack (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- mail (>= 2.7.1)
- net-imap
- net-pop
- net-smtp
- actionmailer (7.0.8.5)
- actionpack (= 7.0.8.5)
- actionview (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- mail (~> 2.5, >= 2.5.4)
- net-imap
- net-pop
- net-smtp
- rails-dom-testing (~> 2.0)
- actionpack (7.0.8.5)
- actionview (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- rack (~> 2.0, >= 2.2.4)
+ zeitwerk (~> 2.6)
+ actionmailbox (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ activejob (= 7.2.2.1)
+ activerecord (= 7.2.2.1)
+ activestorage (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
+ mail (>= 2.8.0)
+ actionmailer (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ actionview (= 7.2.2.1)
+ activejob (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
+ mail (>= 2.8.0)
+ rails-dom-testing (~> 2.2)
+ actionpack (7.2.2.1)
+ actionview (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
+ nokogiri (>= 1.8.5)
+ racc
+ rack (>= 2.2.4, < 3.2)
+ rack-session (>= 1.0.1)
rack-test (>= 0.6.3)
- rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (7.0.8.5)
- actionpack (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ useragent (~> 0.16)
+ actiontext (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ activerecord (= 7.2.2.1)
+ activestorage (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
- actionview (7.0.8.5)
- activesupport (= 7.0.8.5)
+ actionview (7.2.2.1)
+ activesupport (= 7.2.2.1)
builder (~> 3.1)
- erubi (~> 1.4)
- rails-dom-testing (~> 2.0)
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
- activejob (7.0.8.5)
- activesupport (= 7.0.8.5)
+ erubi (~> 1.11)
+ rails-dom-testing (~> 2.2)
+ rails-html-sanitizer (~> 1.6)
+ activejob (7.2.2.1)
+ activesupport (= 7.2.2.1)
globalid (>= 0.3.6)
- activemodel (7.0.8.5)
- activesupport (= 7.0.8.5)
- activemodel-serializers-xml (1.0.2)
- activemodel (> 5.x)
- activesupport (> 5.x)
+ activemodel (7.2.2.1)
+ activesupport (= 7.2.2.1)
+ activemodel-serializers-xml (1.0.3)
+ activemodel (>= 5.0.0.a)
+ activesupport (>= 5.0.0.a)
builder (~> 3.1)
- activerecord (7.0.8.5)
- activemodel (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- activestorage (7.0.8.5)
- actionpack (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ activerecord (7.2.2.1)
+ activemodel (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
+ timeout (>= 0.4.0)
+ activestorage (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ activejob (= 7.2.2.1)
+ activerecord (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
marcel (~> 1.0)
- mini_mime (>= 1.1.0)
- activesupport (7.0.8.5)
- concurrent-ruby (~> 1.0, >= 1.0.2)
+ activesupport (7.2.2.1)
+ base64
+ benchmark (>= 0.3)
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.3.1)
+ connection_pool (>= 2.2.5)
+ drb
i18n (>= 1.6, < 2)
+ logger (>= 1.4.2)
minitest (>= 5.1)
- tzinfo (~> 2.0)
+ securerandom (>= 0.3)
+ tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
@@ -104,6 +110,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1)
base64 (0.2.0)
bcrypt (3.1.20)
+ benchmark (0.4.0)
better_html (2.0.2)
actionview (>= 6.0)
activesupport (>= 6.0)
@@ -111,7 +118,7 @@ GEM
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
- bigdecimal (3.1.6)
+ bigdecimal (3.1.8)
bindex (0.8.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
@@ -149,7 +156,8 @@ GEM
crass (1.0.6)
cssbundling-rails (1.4.0)
railties (>= 6.0.0)
- date (3.3.4)
+ csv (3.3.0)
+ date (3.4.1)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.9.3)
@@ -170,6 +178,7 @@ GEM
dotenv-rails (3.0.2)
dotenv (= 3.0.2)
railties (>= 6.1)
+ drb (2.2.1)
dumb_delegator (1.0.0)
encryptor (3.0.0)
erb_lint (0.5.0)
@@ -184,10 +193,10 @@ GEM
tzinfo
event_stream_parser (1.0.0)
excon (0.111.0)
- factory_bot (6.4.6)
+ factory_bot (6.5.0)
activesupport (>= 5.0.0)
- factory_bot_rails (6.4.3)
- factory_bot (~> 6.4)
+ factory_bot_rails (6.4.4)
+ factory_bot (~> 6.5)
railties (>= 5.0.0)
faker (3.2.3)
i18n (>= 1.8.11, < 2)
@@ -203,11 +212,11 @@ GEM
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
- govuk-components (5.2.1)
+ govuk-components (5.7.0)
html-attributes-utils (~> 1.0.0, >= 1.0.0)
- pagy (~> 6.0)
- view_component (>= 3.9, < 3.11)
- govuk_design_system_formbuilder (5.2.0)
+ pagy (>= 6, < 10)
+ view_component (>= 3.9, < 3.17)
+ govuk_design_system_formbuilder (5.7.1)
actionview (>= 6.1)
activemodel (>= 6.1)
activesupport (>= 6.1)
@@ -222,6 +231,10 @@ GEM
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
iniparse (1.5.0)
+ io-console (0.8.0)
+ irb (1.14.1)
+ rdoc (>= 4.0.0)
+ reline (>= 0.4.2)
jmespath (1.6.2)
jsbundling-rails (1.3.0)
railties (>= 6.0.0)
@@ -246,6 +259,7 @@ GEM
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
+ logger (1.6.2)
loofah (2.23.1)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
@@ -258,13 +272,13 @@ GEM
matrix (0.4.2)
method_source (1.1.0)
mini_mime (1.1.5)
- minitest (5.25.1)
+ minitest (5.25.4)
msgpack (1.7.2)
multipart-post (2.4.1)
nested_form (0.3.2)
net-http (0.4.1)
uri
- net-imap (0.4.17)
+ net-imap (0.5.1)
date
net-protocol
net-pop (0.1.2)
@@ -273,12 +287,12 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
- nio4r (2.7.3)
- nokogiri (1.16.8-arm64-darwin)
+ nio4r (2.7.4)
+ nokogiri (1.17.1-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.16.8-x86_64-darwin)
+ nokogiri (1.17.1-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.16.8-x86_64-linux)
+ nokogiri (1.17.1-x86_64-linux)
racc (~> 1.4)
notifications-ruby-client (6.0.0)
jwt (>= 1.5, < 3)
@@ -287,8 +301,8 @@ GEM
childprocess (>= 0.6.3, < 6)
iniparse (~> 1.4)
rexml (~> 3.2)
- pagy (6.5.0)
- paper_trail (15.1.0)
+ pagy (9.3.2)
+ paper_trail (15.2.0)
activerecord (>= 6.1)
request_store (~> 1.4)
paper_trail-globalid (0.2.0)
@@ -313,34 +327,41 @@ GEM
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
+ psych (5.2.1)
+ date
+ stringio
public_suffix (5.0.4)
- puma (5.6.9)
+ puma (6.5.0)
nio4r (~> 2.0)
pundit (2.3.1)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.8.1)
- rack (2.2.10)
+ rack (3.1.8)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
- rack-mini-profiler (2.3.4)
+ rack-mini-profiler (3.3.1)
rack (>= 1.2.0)
+ rack-session (2.0.0)
+ rack (>= 3.0.0)
rack-test (2.1.0)
rack (>= 1.3)
- rails (7.0.8.5)
- actioncable (= 7.0.8.5)
- actionmailbox (= 7.0.8.5)
- actionmailer (= 7.0.8.5)
- actionpack (= 7.0.8.5)
- actiontext (= 7.0.8.5)
- actionview (= 7.0.8.5)
- activejob (= 7.0.8.5)
- activemodel (= 7.0.8.5)
- activerecord (= 7.0.8.5)
- activestorage (= 7.0.8.5)
- activesupport (= 7.0.8.5)
+ rackup (2.2.1)
+ rack (>= 3)
+ rails (7.2.2.1)
+ actioncable (= 7.2.2.1)
+ actionmailbox (= 7.2.2.1)
+ actionmailer (= 7.2.2.1)
+ actionpack (= 7.2.2.1)
+ actiontext (= 7.2.2.1)
+ actionview (= 7.2.2.1)
+ activejob (= 7.2.2.1)
+ activemodel (= 7.2.2.1)
+ activerecord (= 7.2.2.1)
+ activestorage (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
bundler (>= 1.15.0)
- railties (= 7.0.8.5)
+ railties (= 7.2.2.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@@ -348,31 +369,37 @@ GEM
rails-html-sanitizer (1.6.1)
loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
- rails_admin (3.1.3)
+ rails_admin (3.3.0)
activemodel-serializers-xml (>= 1.0)
+ csv
kaminari (>= 0.14, < 2.0)
nested_form (~> 0.3)
- rails (>= 6.0, < 8)
- turbo-rails (~> 1.0)
- railties (7.0.8.5)
- actionpack (= 7.0.8.5)
- activesupport (= 7.0.8.5)
- method_source
+ rails (>= 6.0, < 9)
+ turbo-rails (>= 1.0, < 3)
+ railties (7.2.2.1)
+ actionpack (= 7.2.2.1)
+ activesupport (= 7.2.2.1)
+ irb (~> 1.13)
+ rackup (>= 1.0.0)
rake (>= 12.2)
- thor (~> 1.0)
- zeitwerk (~> 2.5)
+ thor (~> 1.0, >= 1.2.2)
+ zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.2.1)
randexp (0.1.7)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
+ rdoc (6.8.1)
+ psych (>= 4.0.0)
redcarpet (3.6.0)
redis (4.8.1)
redis-client (0.22.1)
connection_pool
regexp_parser (2.9.0)
- request_store (1.6.0)
+ reline (0.5.12)
+ io-console (~> 0.5)
+ request_store (1.7.0)
rack (>= 1.4)
responders (3.1.1)
actionpack (>= 5.2)
@@ -434,6 +461,7 @@ GEM
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
+ securerandom (0.4.0)
selenium-webdriver (4.18.1)
base64 (~> 0.2)
rexml (~> 3.2, >= 3.2.5)
@@ -462,21 +490,22 @@ GEM
smart_properties (1.17.0)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
+ stringio (3.1.2)
thor (1.3.2)
thread_safe (0.3.6)
timecop (0.9.8)
- timeout (0.4.1)
- turbo-rails (1.5.0)
+ timeout (0.4.2)
+ turbo-rails (2.0.11)
actionpack (>= 6.0.0)
- activejob (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uk_postcode (2.1.8)
unicode-display_width (2.5.0)
- unread (0.13.1)
+ unread (0.14.0)
activerecord (>= 6.1)
uri (0.13.0)
+ useragent (0.16.11)
view_component (3.10.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
@@ -532,8 +561,8 @@ DEPENDENCIES
excon (~> 0.111.0)
factory_bot_rails
faker
- govuk-components (~> 5.1)
- govuk_design_system_formbuilder (~> 5.0)
+ govuk-components (~> 5.7)
+ govuk_design_system_formbuilder (~> 5.7)
govuk_markdown
jsbundling-rails
json-schema
@@ -541,19 +570,19 @@ DEPENDENCIES
method_source (~> 1.1)
notifications-ruby-client
overcommit (>= 0.37.0)
- paper_trail
+ paper_trail (~> 15.2)
paper_trail-globalid
parallel_tests
pg (~> 1.1)
possessive
propshaft
pry-byebug
- puma (~> 5.6)
+ puma (~> 6.4)
pundit
rack (>= 2.2.6.3)
rack-attack
- rack-mini-profiler (~> 2.0)
- rails (~> 7.0.8.5)
+ rack-mini-profiler (~> 3.3.0)
+ rails (~> 7.2.2)
rails_admin (~> 3.1)
redcarpet (~> 3.6)
redis (~> 4.8)
diff --git a/app/components/bulk_upload_error_row_component.html.erb b/app/components/bulk_upload_error_row_component.html.erb
index 4bd303957..db1ceab7a 100644
--- a/app/components/bulk_upload_error_row_component.html.erb
+++ b/app/components/bulk_upload_error_row_component.html.erb
@@ -38,7 +38,7 @@
<% if potential_errors.any? %>
The following groups of cells might have conflicting data. Check the answers and fix any incorrect data.
If the answers are correct, fix the critical errors and reupload the file. You'll need to confirm that the following data is correct when the file only contains potential errors.
+ The following groups of cells might have conflicting data. Check the answers and fix any incorrect data.
If the answers are correct, fix the critical errors and upload the file again. You'll need to confirm that the following data is correct when the file only contains potential errors.
<%= govuk_table(html_attributes: { class: "no-bottom-border" }) do |table| %>
<%= table.with_head do |head| %>
<% head.with_row do |row| %>
diff --git a/app/components/primary_navigation_component.html.erb b/app/components/primary_navigation_component.html.erb
index 9cad3bc64..032c02b81 100644
--- a/app/components/primary_navigation_component.html.erb
+++ b/app/components/primary_navigation_component.html.erb
@@ -1,17 +1,5 @@
-
<%= f.govuk_text_field :search,
form_group: {
diff --git a/app/components/search_result_caption_component.html.erb b/app/components/search_result_caption_component.html.erb
index b8a9382b7..b2a28a505 100644
--- a/app/components/search_result_caption_component.html.erb
+++ b/app/components/search_result_caption_component.html.erb
@@ -7,7 +7,7 @@
<%= count %> <%= item_label.pluralize(count) %> matching filters
<% else %>
- <%= count %> total <%= item %>
+ <%= count %> total <%= item.pluralize(count) %>
<% end %>
diff --git a/app/controllers/bulk_upload_lettings_logs_controller.rb b/app/controllers/bulk_upload_lettings_logs_controller.rb
index a8ad14f9e..39bc05f7e 100644
--- a/app/controllers/bulk_upload_lettings_logs_controller.rb
+++ b/app/controllers/bulk_upload_lettings_logs_controller.rb
@@ -1,6 +1,7 @@
class BulkUploadLettingsLogsController < ApplicationController
before_action :authenticate_user!
- before_action :validate_data_protection_agrement_signed!
+ before_action :validate_data_protection_agreement_signed!
+ before_action :validate_year!, except: %w[start]
def start
if have_choice_of_year?
@@ -24,12 +25,26 @@ class BulkUploadLettingsLogsController < ApplicationController
private
- def validate_data_protection_agrement_signed!
+ def validate_data_protection_agreement_signed!
return if @current_user.organisation.data_protection_confirmed?
redirect_to lettings_logs_path
end
+ def validate_year!
+ return if params[:id] == "year"
+ return if params[:id] == "guidance" && params.dig(:form, :year).nil?
+
+ allowed_years = [current_year]
+ allowed_years.push(current_year - 1) if FormHandler.instance.lettings_in_crossover_period?
+ allowed_years.push(current_year + 1) if FeatureToggle.allow_future_form_use?
+
+ provided_year = params.dig(:form, :year)&.to_i
+ return if allowed_years.include?(provided_year)
+
+ render_not_found
+ end
+
def current_year
FormHandler.instance.current_collection_start_year
end
@@ -48,8 +63,6 @@ private
Forms::BulkUploadLettings::PrepareYourFile.new(form_params)
when "guidance"
Forms::BulkUploadLettings::Guidance.new(form_params.merge(referrer: params[:referrer]))
- when "needstype"
- Forms::BulkUploadLettings::Needstype.new(form_params)
when "upload-your-file"
Forms::BulkUploadLettings::UploadYourFile.new(form_params.merge(current_user:))
when "checking-file"
@@ -60,6 +73,6 @@ private
end
def form_params
- params.fetch(:form, {}).permit(:year, :needstype, :file, :organisation_id)
+ params.fetch(:form, {}).permit(:year, :file, :organisation_id)
end
end
diff --git a/app/controllers/bulk_upload_sales_logs_controller.rb b/app/controllers/bulk_upload_sales_logs_controller.rb
index 2fd312d10..cb04cea95 100644
--- a/app/controllers/bulk_upload_sales_logs_controller.rb
+++ b/app/controllers/bulk_upload_sales_logs_controller.rb
@@ -1,6 +1,7 @@
class BulkUploadSalesLogsController < ApplicationController
before_action :authenticate_user!
- before_action :validate_data_protection_agrement_signed!
+ before_action :validate_data_protection_agreement_signed!
+ before_action :validate_year!, except: %w[start]
def start
if have_choice_of_year?
@@ -24,12 +25,26 @@ class BulkUploadSalesLogsController < ApplicationController
private
- def validate_data_protection_agrement_signed!
+ def validate_data_protection_agreement_signed!
return if @current_user.organisation.data_protection_confirmed?
redirect_to sales_logs_path
end
+ def validate_year!
+ return if params[:id] == "year"
+ return if params[:id] == "guidance" && params.dig(:form, :year).nil?
+
+ allowed_years = [current_year]
+ allowed_years.push(current_year - 1) if FormHandler.instance.sales_in_crossover_period?
+ allowed_years.push(current_year + 1) if FeatureToggle.allow_future_form_use?
+
+ provided_year = params.dig(:form, :year)&.to_i
+ return if allowed_years.include?(provided_year)
+
+ render_not_found
+ end
+
def current_year
FormHandler.instance.current_collection_start_year
end
diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb
index 7ce63e609..f31662c4f 100644
--- a/app/controllers/form_controller.rb
+++ b/app/controllers/form_controller.rb
@@ -38,8 +38,14 @@ class FormController < ApplicationController
error_attributes = @log.errors.map(&:attribute)
Rails.logger.info "User triggered validation(s) on: #{error_attributes.join(', ')}"
@subsection = form.subsection_for_page(@page)
- flash[:errors] = @log.errors
+ flash[:errors] = @log.errors.each_with_object({}) do |error, result|
+ if @page.questions.map(&:id).include?(error.attribute.to_s)
+ result[error.attribute.to_s] = error.message
+ end
+ end
flash[:log_data] = responses_for_page
+ question_ids = (@log.errors.map(&:attribute) - [:base]).uniq
+ flash[:pages_with_errors_count] = question_ids.map { |id| @log.form.get_question(id, @log)&.page&.id }.compact.uniq.count
redirect_to send("#{@log.class.name.underscore}_#{@page.id}_path", @log, { referrer: request.params["referrer"], original_page_id: request.params["original_page_id"], related_question_ids: request.params["related_question_ids"] })
end
else
@@ -81,6 +87,7 @@ class FormController < ApplicationController
page_id = request.path.split("/")[-1].underscore
@page = form.get_page(page_id)
@subsection = form.subsection_for_page(@page)
+ @pages_with_errors_count = 0
if @page.routed_to?(@log, current_user) || is_referrer_type?("interruption_screen") || adding_answer_from_check_errors_page?
if updated_answer_from_check_errors_page?
@questions = request.params["related_question_ids"].map { |id| @log.form.get_question(id, @log) }
@@ -89,6 +96,7 @@ class FormController < ApplicationController
if flash[:errors].present?
restore_previous_errors(flash[:errors])
restore_error_field_values(flash[:log_data])
+ @pages_with_errors_count = flash[:pages_with_errors_count]
end
render "form/page"
end
@@ -105,8 +113,13 @@ private
def restore_error_field_values(previous_responses)
return unless previous_responses
- previous_responses_to_reset = previous_responses.reject do |key, _|
- @log.form.get_question(key, @log)&.type == "date"
+ previous_responses_to_reset = previous_responses.reject do |key, value|
+ if @log.form.get_question(key, @log)&.type == "date" && value.present?
+ year = value.split("-").first.to_i
+ year&.zero?
+ else
+ false
+ end
end
@log.assign_attributes(previous_responses_to_reset)
@@ -116,7 +129,7 @@ private
return unless previous_errors
previous_errors.each do |attribute, message|
- @log.errors.add attribute, message.first
+ @log.errors.add attribute, message.html_safe
end
end
@@ -433,7 +446,7 @@ private
@log.valid?
@log.reload
error_attributes = @log.errors.map(&:attribute)
- @questions = @log.form.questions.select { |q| error_attributes.include?(q.id.to_sym) }
+ @questions = @log.form.questions.select { |q| error_attributes.include?(q.id.to_sym) && q.page.routed_to?(@log, current_user) }
end
render "form/check_errors"
end
diff --git a/app/controllers/lettings_logs_controller.rb b/app/controllers/lettings_logs_controller.rb
index af3a6c32f..7fef9499b 100644
--- a/app/controllers/lettings_logs_controller.rb
+++ b/app/controllers/lettings_logs_controller.rb
@@ -22,7 +22,7 @@ class LettingsLogsController < LogsController
@total_count = all_logs.size
@unresolved_count = all_logs.unresolved.assigned_to(current_user).count
@filter_type = "lettings_logs"
- @duplicate_sets_count = FeatureToggle.duplicate_summary_enabled? && !current_user.support? ? duplicate_sets_count(current_user, current_user.organisation) : 0
+ @duplicate_sets_count = !current_user.support? ? duplicate_sets_count(current_user, current_user.organisation) : 0
render "logs/index"
end
diff --git a/app/controllers/logs_controller.rb b/app/controllers/logs_controller.rb
index 949e705bd..5576028a6 100644
--- a/app/controllers/logs_controller.rb
+++ b/app/controllers/logs_controller.rb
@@ -38,7 +38,7 @@ private
API_ACTIONS = %w[create show update].freeze
def json_api_request?
- API_ACTIONS.include?(request["action"]) && request.format.json?
+ API_ACTIONS.include?(params["action"]) && request.format.json?
end
def authenticate
diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb
index 8ffe426d7..a6d9fb61e 100644
--- a/app/controllers/organisations_controller.rb
+++ b/app/controllers/organisations_controller.rb
@@ -155,6 +155,7 @@ class OrganisationsController < ApplicationController
end
redirect_to details_organisation_path(@organisation)
else
+ @used_rent_periods = @organisation.lettings_logs.pluck(:period).uniq.compact.map(&:to_s)
@rent_periods = helpers.rent_periods_with_checked_attr(checked_periods: selected_rent_periods)
render :edit, status: :unprocessable_entity
end
@@ -185,7 +186,7 @@ class OrganisationsController < ApplicationController
@total_count = organisation_logs.size
@log_type = :lettings
@filter_type = "lettings_logs"
- @duplicate_sets_count = FeatureToggle.duplicate_summary_enabled? ? duplicate_sets_count(current_user, @organisation) : 0
+ @duplicate_sets_count = duplicate_sets_count(current_user, @organisation)
render "logs", layout: "application"
end
@@ -217,7 +218,7 @@ class OrganisationsController < ApplicationController
@total_count = organisation_logs.size
@log_type = :sales
@filter_type = "sales_logs"
- @duplicate_sets_count = FeatureToggle.duplicate_summary_enabled? ? duplicate_sets_count(current_user, @organisation) : 0
+ @duplicate_sets_count = duplicate_sets_count(current_user, @organisation)
render "logs", layout: "application"
end
diff --git a/app/controllers/sales_logs_controller.rb b/app/controllers/sales_logs_controller.rb
index 8799fe528..237fd94d7 100644
--- a/app/controllers/sales_logs_controller.rb
+++ b/app/controllers/sales_logs_controller.rb
@@ -24,7 +24,7 @@ class SalesLogsController < LogsController
@searched = search_term.presence
@total_count = all_logs.size
@filter_type = "sales_logs"
- @duplicate_sets_count = FeatureToggle.duplicate_summary_enabled? && !current_user.support? ? duplicate_sets_count(current_user, current_user.organisation) : 0
+ @duplicate_sets_count = !current_user.support? ? duplicate_sets_count(current_user, current_user.organisation) : 0
render "logs/index"
end
diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb
index 3dc642345..a76c9db52 100644
--- a/app/controllers/schemes_controller.rb
+++ b/app/controllers/schemes_controller.rb
@@ -150,7 +150,7 @@ class SchemesController < ApplicationController
@scheme.update!(secondary_client_group: nil) if @scheme.has_other_client_group == "No"
if scheme_params[:confirmed] == "true" || @scheme.confirmed?
if check_answers && should_direct_via_secondary_client_group_page?(page)
- redirect_to scheme_secondary_client_group_path(@scheme, referrer: "check-answers")
+ redirect_to scheme_secondary_client_group_path(@scheme, referrer: "has-other-client-group")
else
@scheme.locations.update!(confirmed: true)
flash[:notice] = if scheme_previously_confirmed
@@ -162,7 +162,7 @@ class SchemesController < ApplicationController
end
elsif check_answers
if should_direct_via_secondary_client_group_page?(page)
- redirect_to scheme_secondary_client_group_path(@scheme, referrer: "check-answers")
+ redirect_to scheme_secondary_client_group_path(@scheme, referrer: "has-other-client-group")
else
redirect_to scheme_check_answers_path(@scheme)
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 70a538900..a912c9817 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,20 +1,20 @@
class SessionsController < ApplicationController
def clear_filters
session[session_name_for(params[:filter_type])] = "{}"
- path_params = params[:path_params].presence || {}
+ filter_path_params = params[:filter_path_params].presence || {}
- if path_params[:organisation_id].present?
- redirect_to send("#{params[:filter_type]}_organisation_path", id: path_params[:organisation_id], scheme_id: path_params[:scheme_id], search: path_params[:search])
+ if filter_path_params[:organisation_id].present?
+ redirect_to send("#{params[:filter_type]}_organisation_path", id: filter_path_params[:organisation_id], scheme_id: filter_path_params[:scheme_id], search: filter_path_params[:search])
elsif params[:filter_type].include?("bulk_uploads")
bulk_upload_type = params[:filter_type].split("_").first
uploading_organisation = params[:organisation_id].presence
if uploading_organisation.present?
- redirect_to send("bulk_uploads_#{bulk_upload_type}_logs_path", search: path_params[:search], uploading_organisation:)
+ redirect_to send("bulk_uploads_#{bulk_upload_type}_logs_path", search: filter_path_params[:search], uploading_organisation:)
else
- redirect_to send("bulk_uploads_#{bulk_upload_type}_logs_path", search: path_params[:search])
+ redirect_to send("bulk_uploads_#{bulk_upload_type}_logs_path", search: filter_path_params[:search])
end
else
- redirect_to send("#{params[:filter_type]}_path", scheme_id: path_params[:scheme_id], search: path_params[:search])
+ redirect_to send("#{params[:filter_type]}_path", scheme_id: filter_path_params[:scheme_id], search: filter_path_params[:search])
end
end
diff --git a/app/frontend/styles/_primary-navigation.scss b/app/frontend/styles/_primary-navigation.scss
deleted file mode 100644
index b21d41fc1..000000000
--- a/app/frontend/styles/_primary-navigation.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-.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;
-}
diff --git a/app/frontend/styles/application.scss b/app/frontend/styles/application.scss
index 837b0db6d..3e75107bd 100644
--- a/app/frontend/styles/application.scss
+++ b/app/frontend/styles/application.scss
@@ -45,7 +45,6 @@ $govuk-breakpoints: (
@import "task-list";
@import "template";
@import "panel";
-@import "primary-navigation";
@import "search";
@import "sub-navigation";
@import "unread-notification";
@@ -86,3 +85,44 @@ $govuk-breakpoints: (
.govuk-notification-banner__content > * {
max-width: fit-content;
}
+
+.govuk-service-navigation__active-fallback,
+.govuk-service-navigation__list {
+ font-weight: bold;
+}
+
+.govuk-service-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;
+ }
+}
+
+.govuk-service-navigation__item--active {
+ border-bottom-width: 4px;
+}
+
+.govuk-service-navigation__item {
+ padding-right: 15px;
+ padding-left: 15px;
+ margin: 0;
+}
+
+.govuk-service-navigation__item:not(:last-child) {
+ margin-right: 0;
+}
+
+.govuk-service-navigation__container {
+ left: -15px;
+ position: relative;
+}
diff --git a/app/helpers/filters_helper.rb b/app/helpers/filters_helper.rb
index 99c69c636..b983609b8 100644
--- a/app/helpers/filters_helper.rb
+++ b/app/helpers/filters_helper.rb
@@ -165,9 +165,9 @@ module FiltersHelper
applied_filters_count(filter_type).zero? ? "No filters applied" : "#{pluralize(applied_filters_count(filter_type), 'filter')} applied"
end
- def reset_filters_link(filter_type, path_params = {})
+ def reset_filters_link(filter_type, filter_path_params = {})
if applied_filters_count(filter_type).positive?
- govuk_link_to "Clear", clear_filters_path(filter_type:, path_params:)
+ govuk_link_to "Clear", clear_filters_path(filter_type:, filter_path_params:)
end
end
diff --git a/app/helpers/form_page_error_helper.rb b/app/helpers/form_page_error_helper.rb
index 2c90bfd2a..ded09d54c 100644
--- a/app/helpers/form_page_error_helper.rb
+++ b/app/helpers/form_page_error_helper.rb
@@ -12,8 +12,4 @@ module FormPageErrorHelper
errors.each { |error| lettings_log.errors.delete(error.attribute) }
end
end
-
- def all_questions_affected_by_errors(log)
- (log.errors.map(&:attribute) - [:base]).uniq
- end
end
diff --git a/app/helpers/logs_helper.rb b/app/helpers/logs_helper.rb
index 4b8f6211f..981642f92 100644
--- a/app/helpers/logs_helper.rb
+++ b/app/helpers/logs_helper.rb
@@ -10,7 +10,7 @@ module LogsHelper
def bulk_upload_options(bulk_upload)
array = bulk_upload ? [bulk_upload.id] : []
- array.index_with { |_bulk_upload_id| "With logs from bulk upload" }
+ array.index_with { |_bulk_upload_id| "Only logs from this bulk upload" }
end
def search_label_for_controller(controller)
diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb
index 12d86aba8..f262c08ff 100644
--- a/app/helpers/schemes_helper.rb
+++ b/app/helpers/schemes_helper.rb
@@ -101,6 +101,24 @@ module SchemesHelper
organisation.owned_schemes.duplicate_sets.any? || organisation.owned_schemes.any? { |scheme| scheme.locations.duplicate_sets.any? }
end
+ def scheme_back_button_path(scheme, current_page)
+ return scheme_check_answers_path(scheme) if request.params[:referrer] == "check-answers"
+ return scheme_confirm_secondary_client_group_path(scheme, referrer: "check-answers") if request.params[:referrer] == "has-other-client-group"
+
+ case current_page
+ when "details"
+ schemes_path
+ when "primary_client_group"
+ scheme_details_path(scheme)
+ when "confirm_secondary_client_group"
+ scheme_primary_client_group_path(scheme)
+ when "secondary_client_group"
+ scheme_confirm_secondary_client_group_path(scheme)
+ when "support"
+ scheme.has_other_client_group == "Yes" ? scheme_secondary_client_group_path(scheme) : scheme_confirm_secondary_client_group_path(scheme)
+ end
+ end
+
private
ActivePeriod = Struct.new(:from, :to)
diff --git a/app/mailers/bulk_upload_mailer.rb b/app/mailers/bulk_upload_mailer.rb
index e0115abb0..7c62f71a1 100644
--- a/app/mailers/bulk_upload_mailer.rb
+++ b/app/mailers/bulk_upload_mailer.rb
@@ -3,6 +3,7 @@ class BulkUploadMailer < NotifyMailer
COMPLETE_TEMPLATE_ID = "83279578-c890-4168-838b-33c9cf0dc9f0".freeze
FAILED_CSV_ERRORS_TEMPLATE_ID = "e27abcd4-5295-48c2-b127-e9ee4b781b75".freeze
+ FAILED_CSV_DUPLICATE_ERRORS_TEMPLATE_ID = "931d5bda-a08f-4de6-a455-38a63bff1956".freeze
FAILED_FILE_SETUP_ERROR_TEMPLATE_ID = "24c9f4c7-96ad-470a-ba31-eb51b7cbafd9".freeze
FAILED_SERVICE_ERROR_TEMPLATE_ID = "c3f6288c-7a74-4e77-99ee-6c4a0f6e125a".freeze
HOW_TO_FIX_UPLOAD_TEMPLATE_ID = "21a07b26-f625-4846-9f4d-39e30937aa24".freeze
@@ -95,6 +96,26 @@ class BulkUploadMailer < NotifyMailer
)
end
+ def send_correct_duplicates_and_upload_again_mail(bulk_upload:)
+ summary_report_link = if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
+ bulk_upload.sales? ? summary_bulk_upload_sales_result_url(bulk_upload) : summary_bulk_upload_lettings_result_url(bulk_upload)
+ else
+ bulk_upload.sales? ? bulk_upload_sales_result_url(bulk_upload) : bulk_upload_lettings_result_url(bulk_upload)
+ end
+
+ send_email(
+ bulk_upload.user.email,
+ FAILED_CSV_DUPLICATE_ERRORS_TEMPLATE_ID,
+ {
+ filename: bulk_upload.filename,
+ upload_timestamp: bulk_upload.created_at.to_fs(:govuk_date_and_time),
+ year_combo: bulk_upload.year_combo,
+ lettings_or_sales: bulk_upload.log_type,
+ summary_report_link:,
+ },
+ )
+ end
+
def send_bulk_upload_failed_file_setup_error_mail(bulk_upload:)
bulk_upload_link = if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
bulk_upload.sales? ? summary_bulk_upload_sales_result_url(bulk_upload) : summary_bulk_upload_lettings_result_url(bulk_upload)
diff --git a/app/models/bulk_upload.rb b/app/models/bulk_upload.rb
index a0ed265c9..2e0232dfe 100644
--- a/app/models/bulk_upload.rb
+++ b/app/models/bulk_upload.rb
@@ -1,7 +1,7 @@
class BulkUpload < ApplicationRecord
- enum log_type: { lettings: "lettings", sales: "sales" }
- enum rent_type_fix_status: { not_applied: "not_applied", applied: "applied", not_needed: "not_needed" }
- enum failure_reason: { blank_template: "blank_template", wrong_template: "wrong_template" }
+ enum :log_type, { lettings: "lettings", sales: "sales" }
+ enum :rent_type_fix_status, { not_applied: "not_applied", applied: "applied", not_needed: "not_needed" }
+ enum :failure_reason, { blank_template: "blank_template", wrong_template: "wrong_template" }
belongs_to :user
diff --git a/app/models/csv_download.rb b/app/models/csv_download.rb
index 4064c62f3..5623f4a43 100644
--- a/app/models/csv_download.rb
+++ b/app/models/csv_download.rb
@@ -1,5 +1,5 @@
class CsvDownload < ApplicationRecord
- enum download_type: { lettings: "lettings", sales: "sales", schemes: "schemes", locations: "locations", combined: "combined" }
+ enum :download_type, { lettings: "lettings", sales: "sales", schemes: "schemes", locations: "locations", combined: "combined" }
belongs_to :user
belongs_to :organisation
diff --git a/app/models/form/lettings/questions/offered.rb b/app/models/form/lettings/questions/offered.rb
index 701a6f737..c1aae8d32 100644
--- a/app/models/form/lettings/questions/offered.rb
+++ b/app/models/form/lettings/questions/offered.rb
@@ -7,7 +7,6 @@ class Form::Lettings::Questions::Offered < ::Form::Question
@check_answers_card_number = 0
@max = 150
@min = 0
- @hint_text = I18n.t("hints.offered")
@step = 1
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max]
end
diff --git a/app/models/form/sales/pages/owning_organisation.rb b/app/models/form/sales/pages/owning_organisation.rb
index f0c9e4e68..f1875d52d 100644
--- a/app/models/form/sales/pages/owning_organisation.rb
+++ b/app/models/form/sales/pages/owning_organisation.rb
@@ -20,11 +20,13 @@ class Form::Sales::Pages::OwningOrganisation < ::Form::Page
if current_user.organisation.holds_own_stock?
return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true if stock_owners.count >= 1
+ return false if log.owning_organisation == current_user.organisation
log.update!(owning_organisation: current_user.organisation)
else
return false if stock_owners.count.zero?
return true if stock_owners.count > 1
+ return false if log.owning_organisation == stock_owners.first
log.update!(owning_organisation: stock_owners.first)
end
diff --git a/app/models/form/sales/questions/buyer2_income_known.rb b/app/models/form/sales/questions/buyer2_income_known.rb
index 0b125f2af..26d4b2fca 100644
--- a/app/models/form/sales/questions/buyer2_income_known.rb
+++ b/app/models/form/sales/questions/buyer2_income_known.rb
@@ -2,7 +2,7 @@ class Form::Sales::Questions::Buyer2IncomeKnown < ::Form::Question
def initialize(id, hsh, page)
super
@id = "income2nk"
- @copy_key = "sales.income_benefits_and_savings.buyer_2_income.income2"
+ @copy_key = "sales.income_benefits_and_savings.buyer_2_income.income2nk"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@conditional_for = {
diff --git a/app/models/form/sales/questions/buyer2_working_situation.rb b/app/models/form/sales/questions/buyer2_working_situation.rb
index 38ab320b3..9105b8597 100644
--- a/app/models/form/sales/questions/buyer2_working_situation.rb
+++ b/app/models/form/sales/questions/buyer2_working_situation.rb
@@ -15,6 +15,10 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
@question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max]
end
+ def displayed_answer_options(_log, _user = nil)
+ answer_options.reject { |key, _| key == "9" }
+ end
+
def answer_options
if form.start_year_2025_or_later?
{
@@ -26,6 +30,7 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
"6" => { "value" => "Not seeking work" },
"7" => { "value" => "Full-time student" },
"8" => { "value" => "Unable to work due to long term sick or disability" },
+ "9" => { "value" => "Child under 16" },
"0" => { "value" => "Other" },
"10" => { "value" => "Buyer prefers not to say" },
}.freeze
@@ -41,6 +46,7 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
"0" => { "value" => "Other" },
"10" => { "value" => "Buyer prefers not to say" },
"7" => { "value" => "Full-time student" },
+ "9" => { "value" => "Child under 16" },
}.freeze
end
end
diff --git a/app/models/form/sales/questions/equity.rb b/app/models/form/sales/questions/equity.rb
index e39e77ebb..74f5e9970 100644
--- a/app/models/form/sales/questions/equity.rb
+++ b/app/models/form/sales/questions/equity.rb
@@ -2,7 +2,7 @@ class Form::Sales::Questions::Equity < ::Form::Question
def initialize(id, hsh, page)
super
@id = "equity"
- @copy_key = "sales.sale_information.equity.#{page.id}"
+ @copy_key = form.start_year_2025_or_later? ? "sales.sale_information.equity.#{page.id}" : "sales.sale_information.equity"
@type = "numeric"
@min = 0
@max = 100
diff --git a/app/models/form/sales/questions/value.rb b/app/models/form/sales/questions/value.rb
index ad021e920..ce8d07e28 100644
--- a/app/models/form/sales/questions/value.rb
+++ b/app/models/form/sales/questions/value.rb
@@ -2,7 +2,7 @@ class Form::Sales::Questions::Value < ::Form::Question
def initialize(id, hsh, page)
super
@id = "value"
- @copy_key = "sales.sale_information.value.#{page.id}"
+ @copy_key = form.start_year_2025_or_later? ? "sales.sale_information.value.#{page.id}" : "sales.sale_information.value"
@type = "numeric"
@min = 0
@step = 1
diff --git a/app/models/forms/bulk_upload_lettings/needstype.rb b/app/models/forms/bulk_upload_lettings/needstype.rb
deleted file mode 100644
index b15c05b52..000000000
--- a/app/models/forms/bulk_upload_lettings/needstype.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module Forms
- module BulkUploadLettings
- class Needstype
- include ActiveModel::Model
- include ActiveModel::Attributes
- include Rails.application.routes.url_helpers
-
- attribute :needstype, :integer
- attribute :year, :integer
- attribute :organisation_id, :integer
-
- validates :needstype, presence: true
-
- def view_path
- "bulk_upload_lettings_logs/forms/needstype"
- end
-
- def options
- [OpenStruct.new(id: 1, name: "General needs"), OpenStruct.new(id: 2, name: "Supported housing")]
- end
-
- def back_path
- bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year:, needstype:, organisation_id: }.compact)
- end
-
- def next_path
- bulk_upload_lettings_log_path(id: "upload-your-file", form: { year:, needstype:, organisation_id: }.compact)
- end
-
- def year_combo
- "#{year} to #{year + 1}"
- end
-
- def save!
- true
- end
- end
- end
-end
diff --git a/app/models/forms/bulk_upload_lettings_resume/fix_choice.rb b/app/models/forms/bulk_upload_lettings_resume/fix_choice.rb
index 5ee4d37fd..40ada602e 100644
--- a/app/models/forms/bulk_upload_lettings_resume/fix_choice.rb
+++ b/app/models/forms/bulk_upload_lettings_resume/fix_choice.rb
@@ -14,7 +14,7 @@ module Forms
def options
[
OpenStruct.new(id: "create-fix-inline", name: "Upload these logs and fix errors on CORE site"),
- OpenStruct.new(id: "upload-again", name: "Fix errors in the CSV and re-upload"),
+ OpenStruct.new(id: "upload-again", name: "Fix errors in the CSV and upload the file again"),
]
end
diff --git a/app/models/forms/bulk_upload_sales_resume/fix_choice.rb b/app/models/forms/bulk_upload_sales_resume/fix_choice.rb
index b34f50d3a..79d06529a 100644
--- a/app/models/forms/bulk_upload_sales_resume/fix_choice.rb
+++ b/app/models/forms/bulk_upload_sales_resume/fix_choice.rb
@@ -14,7 +14,7 @@ module Forms
def options
[
OpenStruct.new(id: "create-fix-inline", name: "Upload these logs and fix errors on CORE site"),
- OpenStruct.new(id: "upload-again", name: "Fix errors in the CSV and re-upload"),
+ OpenStruct.new(id: "upload-again", name: "Fix errors in the CSV and upload the file again"),
]
end
diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb
index d1ff6f738..67cafb75b 100644
--- a/app/models/lettings_log.rb
+++ b/app/models/lettings_log.rb
@@ -779,8 +779,7 @@ private
not_required << "previous_la_known" if postcode_known?
not_required << "tshortfall" if tshortfall_unknown?
not_required << "tenancylength" if tenancylength_optional?
-
- not_required |= %w[address_line2 county postcode_full] if startdate && collection_start_year_for_date(startdate) >= 2023
+ not_required += %w[address_line2 county]
not_required
end
diff --git a/app/models/location.rb b/app/models/location.rb
index c333f653f..0f5616c16 100644
--- a/app/models/location.rb
+++ b/app/models/location.rb
@@ -171,7 +171,8 @@ class Location < ApplicationRecord
DUPLICATE_LOCATION_ATTRIBUTES = %w[scheme_id postcode mobility_type].freeze
LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h
- enum local_authorities: LOCAL_AUTHORITIES
+ attribute :local_authorities, :string
+ enum :local_authorities, LOCAL_AUTHORITIES
def self.local_authorities_for_current_year
LocalAuthority.all.active(Time.zone.today).england.map { |la| [la.code, la.name] }.to_h
end
@@ -184,7 +185,7 @@ class Location < ApplicationRecord
"Missing": "X",
}.freeze
- enum mobility_type: MOBILITY_TYPE
+ enum :mobility_type, MOBILITY_TYPE
TYPE_OF_UNIT = {
"Bungalow": 6,
@@ -195,7 +196,7 @@ class Location < ApplicationRecord
"Shared house or hostel": 4,
}.freeze
- enum type_of_unit: TYPE_OF_UNIT
+ enum :type_of_unit, TYPE_OF_UNIT
def self.find_by_id_on_multiple_fields(id)
return if id.nil?
diff --git a/app/models/log.rb b/app/models/log.rb
index bcbea9c92..94f0ff58d 100644
--- a/app/models/log.rb
+++ b/app/models/log.rb
@@ -18,14 +18,14 @@ class Log < ApplicationRecord
"pending" => 3,
"deleted" => 4,
}.freeze
- enum status: STATUS
- enum status_cache: STATUS, _prefix: true
+ enum :status, STATUS
+ enum :status_cache, STATUS, prefix: true
CREATION_METHOD = {
"single log" => 1,
"bulk upload" => 2,
}.freeze
- enum creation_method: CREATION_METHOD, _prefix: true
+ enum :creation_method, CREATION_METHOD, prefix: true
scope :visible, -> { where(status: %w[not_started in_progress completed]) }
scope :exportable, -> { where(status: %w[not_started in_progress completed deleted]) }
@@ -110,7 +110,7 @@ class Log < ApplicationRecord
self.address_line2 = nil
self.town_or_city = nil
self.county = nil
- self.postcode_full = postcode_full_input
+ self.postcode_full = postcode_full_input if postcode_full_input.match(POSTCODE_REGEXP)
process_postcode_changes!
else
self.uprn = uprn_selection
@@ -317,7 +317,11 @@ private
def update_status!
return if skip_update_status
- self.status = calculate_status
+ if status == "pending"
+ self.status_cache = calculate_status
+ else
+ self.status = calculate_status
+ end
end
def all_subsections_completed?
@@ -373,14 +377,14 @@ private
end
def reset_location_fields!
- reset_location(is_la_inferred, "la", "is_la_inferred", "postcode_full", 1)
+ reset_log_location(is_la_inferred, "la", "is_la_inferred", "postcode_full", 1)
end
def reset_previous_location_fields!
- reset_location(is_previous_la_inferred, "prevloc", "is_previous_la_inferred", "ppostcode_full", previous_la_known)
+ reset_log_location(is_previous_la_inferred, "prevloc", "is_previous_la_inferred", "ppostcode_full", previous_la_known)
end
- def reset_location(is_inferred, la_key, is_inferred_key, postcode_key, is_la_known)
+ def reset_log_location(is_inferred, la_key, is_inferred_key, postcode_key, is_la_known)
if is_inferred || is_la_known != 1
self[la_key] = nil
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 24fa26bde..47ffc84dc 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -13,7 +13,9 @@ class MergeRequest < ApplicationRecord
request_merged: "request_merged",
deleted: "deleted",
}.freeze
- enum status: STATUS
+
+ attribute :status, :string
+ enum :status, STATUS
scope :not_merged, -> { where(request_merged: [false, nil]) }
scope :merged, -> { where(request_merged: true) }
diff --git a/app/models/organisation.rb b/app/models/organisation.rb
index 23f91f1ad..c3d0a8ca0 100644
--- a/app/models/organisation.rb
+++ b/app/models/organisation.rb
@@ -53,11 +53,12 @@ class Organisation < ApplicationRecord
PRP: 2,
}.freeze
- enum provider_type: PROVIDER_TYPE
+ enum :provider_type, PROVIDER_TYPE
alias_method :la?, :LA?
validates :name, presence: { message: I18n.t("validations.organisation.name_missing") }
+ validates :name, uniqueness: { case_sensitive: false, message: I18n.t("validations.organisation.name_not_unique") }
validates :provider_type, presence: { message: I18n.t("validations.organisation.provider_type_missing") }
def self.find_by_id_on_multiple_fields(id)
diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb
index 361aab6f6..3064cba31 100644
--- a/app/models/sales_log.rb
+++ b/app/models/sales_log.rb
@@ -132,8 +132,7 @@ class SalesLog < Log
not_required << "mortlen" if mortlen_optional?
not_required << "frombeds" if frombeds_optional?
not_required << "deposit" if form.start_year_2024_or_later? && stairowned_100?
-
- not_required |= %w[address_line2 county postcode_full] if saledate && collection_start_year_for_date(saledate) >= 2023
+ not_required += %w[address_line2 county]
not_required
end
diff --git a/app/models/scheme.rb b/app/models/scheme.rb
index 1cd56ac7d..ae772b30b 100644
--- a/app/models/scheme.rb
+++ b/app/models/scheme.rb
@@ -145,7 +145,7 @@ class Scheme < ApplicationRecord
Yes: 1,
}.freeze
- enum sensitive: SENSITIVE, _suffix: true
+ enum :sensitive, SENSITIVE, suffix: true
REGISTERED_UNDER_CARE_ACT = {
"Yes – registered care home providing nursing care": 4,
@@ -154,7 +154,7 @@ class Scheme < ApplicationRecord
"No": 1,
}.freeze
- enum registered_under_care_act: REGISTERED_UNDER_CARE_ACT
+ enum :registered_under_care_act, REGISTERED_UNDER_CARE_ACT
SCHEME_TYPE = {
"Direct Access Hostel": 5,
@@ -164,7 +164,7 @@ class Scheme < ApplicationRecord
"Missing": 0,
}.freeze
- enum scheme_type: SCHEME_TYPE, _suffix: true
+ enum :scheme_type, SCHEME_TYPE, suffix: true
SUPPORT_TYPE = {
"Missing": 0,
@@ -175,7 +175,7 @@ class Scheme < ApplicationRecord
"Floating support": 6,
}.freeze
- enum support_type: SUPPORT_TYPE, _suffix: true
+ enum :support_type, SUPPORT_TYPE, suffix: true
PRIMARY_CLIENT_GROUP = {
"Homeless families with support needs": "O",
@@ -197,8 +197,8 @@ class Scheme < ApplicationRecord
"Missing": "X",
}.freeze
- enum primary_client_group: PRIMARY_CLIENT_GROUP, _suffix: true
- enum secondary_client_group: PRIMARY_CLIENT_GROUP, _suffix: true
+ enum :primary_client_group, PRIMARY_CLIENT_GROUP, suffix: true
+ enum :secondary_client_group, PRIMARY_CLIENT_GROUP, suffix: true
INTENDED_STAY = {
"Very short stay": "V",
@@ -213,8 +213,8 @@ class Scheme < ApplicationRecord
Yes: 1,
}.freeze
- enum intended_stay: INTENDED_STAY, _suffix: true
- enum has_other_client_group: HAS_OTHER_CLIENT_GROUP, _suffix: true
+ enum :intended_stay, INTENDED_STAY, suffix: true
+ enum :has_other_client_group, HAS_OTHER_CLIENT_GROUP, suffix: true
ARRANGEMENT_TYPE = {
"The same organisation that owns the housing stock": "D",
@@ -226,7 +226,7 @@ class Scheme < ApplicationRecord
DUPLICATE_SCHEME_ATTRIBUTES = %w[scheme_type registered_under_care_act primary_client_group secondary_client_group has_other_client_group support_type intended_stay].freeze
- enum arrangement_type: ARRANGEMENT_TYPE, _suffix: true
+ enum :arrangement_type, ARRANGEMENT_TYPE, suffix: true
def self.find_by_id_on_multiple_fields(scheme_id, location_id)
return if scheme_id.nil?
@@ -329,9 +329,9 @@ class Scheme < ApplicationRecord
def status_at(date)
return :deleted if discarded_at.present?
- return :incomplete unless confirmed && locations.confirmed.any?
return :deactivated if owning_organisation.status_at(date) == :deactivated || owning_organisation.status_at(date) == :merged ||
(open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date)
+ return :incomplete unless confirmed && locations.confirmed.any?
return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
return :reactivating_soon if last_deactivation_before(date)&.reactivation_date.present? && date < last_deactivation_before(date).reactivation_date
return :activating_soon if startdate.present? && date < startdate
diff --git a/app/models/user.rb b/app/models/user.rb
index 3d6dbe893..823e78b2b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -56,7 +56,7 @@ class User < ApplicationRecord
unassign: "No, unassign the logs",
}.freeze
- enum role: ROLES
+ enum :role, ROLES
scope :search_by_name, ->(name) { where("users.name ILIKE ?", "%#{name}%") }
scope :search_by_email, ->(email) { where("email ILIKE ?", "%#{email}%") }
diff --git a/app/models/validations/property_validations.rb b/app/models/validations/property_validations.rb
index e9eba8184..1cf710857 100644
--- a/app/models/validations/property_validations.rb
+++ b/app/models/validations/property_validations.rb
@@ -41,6 +41,8 @@ module Validations::PropertyValidations
def validate_property_postcode(record)
postcode = record.postcode_full
+ return unless postcode
+
if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = I18n.t("validations.lettings.property.postcode_full.invalid")
record.errors.add :postcode_full, :wrong_format, message: error_message
diff --git a/app/models/validations/sales/property_validations.rb b/app/models/validations/sales/property_validations.rb
index 2238a634a..7fd4d2440 100644
--- a/app/models/validations/sales/property_validations.rb
+++ b/app/models/validations/sales/property_validations.rb
@@ -31,6 +31,8 @@ module Validations::Sales::PropertyValidations
def validate_property_postcode(record)
postcode = record.postcode_full
+ return unless postcode
+
if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = I18n.t("validations.sales.property_information.postcode_full.invalid")
record.errors.add :postcode_full, :wrong_format, message: error_message
diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb
index 3825271c5..4b8948053 100644
--- a/app/models/validations/sales/sale_information_validations.rb
+++ b/app/models/validations/sales/sale_information_validations.rb
@@ -64,7 +64,7 @@ module Validations::Sales::SaleInformationValidations
if over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: !record.discount.nil?) && record.discounted_ownership_sale?
deposit_and_grant_sentence = record.grant.present? ? ", cash deposit (#{record.field_formatted_as_currency('deposit')}), and grant (#{record.field_formatted_as_currency('grant')})" : " and cash deposit (#{record.field_formatted_as_currency('deposit')})"
discount_sentence = record.discount.present? ? " (#{record.field_formatted_as_currency('value')}) subtracted by the sum of the full purchase price (#{record.field_formatted_as_currency('value')}) multiplied by the percentage discount (#{record.discount}%)" : ""
- %i[mortgageused mortgage value deposit ownershipsch discount grant].each do |field|
+ %i[mortgageused mortgage value deposit discount grant].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.discounted_ownership_value",
mortgage: record.mortgage&.positive? ? " (#{record.field_formatted_as_currency('mortgage')})" : "",
deposit_and_grant_sentence:,
@@ -72,6 +72,12 @@ module Validations::Sales::SaleInformationValidations
discount_sentence:,
value_with_discount: record.field_formatted_as_currency("value_with_discount")).html_safe
end
+ record.errors.add :ownershipsch, :skip_bu_error, message: I18n.t("validations.sales.sale_information.ownershipsch.discounted_ownership_value",
+ mortgage: record.mortgage&.positive? ? " (#{record.field_formatted_as_currency('mortgage')})" : "",
+ deposit_and_grant_sentence:,
+ mortgage_deposit_and_grant_total: record.field_formatted_as_currency("mortgage_deposit_and_grant_total"),
+ discount_sentence:,
+ value_with_discount: record.field_formatted_as_currency("value_with_discount")).html_safe
end
end
diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb
index 0b76f792b..1a2c61138 100644
--- a/app/models/validations/soft_validations.rb
+++ b/app/models/validations/soft_validations.rb
@@ -84,6 +84,8 @@ module Validations::SoftValidations
end
def all_tenants_age_and_gender_information_completed?
+ return false if hhmemb.present? && hhmemb > 8
+
person_count = hhmemb || 8
(1..person_count).all? do |n|
@@ -235,6 +237,8 @@ private
end
def all_male_tenants_in_the_household?
+ return false if hhmemb.present? && hhmemb > 8
+
person_count = hhmemb || 8
(1..person_count).all? do |n|
diff --git a/app/services/bulk_upload/lettings/log_creator.rb b/app/services/bulk_upload/lettings/log_creator.rb
index 1fd0d45b6..0df59b310 100644
--- a/app/services/bulk_upload/lettings/log_creator.rb
+++ b/app/services/bulk_upload/lettings/log_creator.rb
@@ -16,9 +16,7 @@ class BulkUpload::Lettings::LogCreator
row_parser.log.blank_invalid_non_setup_fields!
row_parser.log.bulk_upload = bulk_upload
row_parser.log.creation_method = "bulk upload"
- row_parser.log.skip_update_status = true
row_parser.log.status = "pending"
- row_parser.log.status_cache = row_parser.log.calculate_status
begin
row_parser.log.save!
diff --git a/app/services/bulk_upload/lettings/validator.rb b/app/services/bulk_upload/lettings/validator.rb
index 116c3b745..291bf45e7 100644
--- a/app/services/bulk_upload/lettings/validator.rb
+++ b/app/services/bulk_upload/lettings/validator.rb
@@ -40,29 +40,25 @@ class BulkUpload::Lettings::Validator
end
end
- def create_logs?
- return false if any_setup_errors?
+ def block_log_creation_reason
+ return "setup_errors" if any_setup_errors?
if row_parsers.any?(&:block_log_creation?)
Sentry.capture_message("Bulk upload log creation blocked: #{bulk_upload.id}.")
- return false
+ return "row_parser_block_log_creation"
end
if any_logs_already_exist? && FeatureToggle.bulk_upload_duplicate_log_check_enabled?
- Sentry.capture_message("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.")
- return false
+ return "duplicate_logs"
end
row_parsers.each do |row_parser|
row_parser.log.blank_invalid_non_setup_fields!
end
-
if any_logs_invalid?
Sentry.capture_message("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.")
- return false
+ "logs_invalid"
end
-
- true
end
def self.question_for_field(field)
diff --git a/app/services/bulk_upload/processor.rb b/app/services/bulk_upload/processor.rb
index 38f67ede4..c54032fda 100644
--- a/app/services/bulk_upload/processor.rb
+++ b/app/services/bulk_upload/processor.rb
@@ -36,20 +36,28 @@ class BulkUpload::Processor
if validator.any_setup_errors?
send_setup_errors_mail
-
- elsif validator.create_logs?
- create_logs
-
- if validator.soft_validation_errors_only?
- send_check_soft_validations_mail
- elsif created_logs_but_incompleted?
- send_how_to_fix_upload_mail
- elsif created_logs_and_all_completed?
- bulk_upload.unpend
- send_success_mail
- end
else
- send_correct_and_upload_again_mail # summary/full report
+ block_creation_reason = validator.block_log_creation_reason
+
+ if block_creation_reason.present?
+ case block_creation_reason
+ when "duplicate_logs"
+ send_correct_duplicates_and_upload_again_mail
+ else
+ send_correct_and_upload_again_mail # summary/full report
+ end
+ else
+ create_logs
+
+ if validator.soft_validation_errors_only?
+ send_check_soft_validations_mail
+ elsif created_logs_but_incompleted?
+ send_how_to_fix_upload_mail
+ elsif created_logs_and_all_completed?
+ bulk_upload.unpend
+ send_success_mail
+ end
+ end
end
rescue StandardError => e
Sentry.capture_exception(e)
@@ -97,6 +105,12 @@ private
.deliver_later
end
+ def send_correct_duplicates_and_upload_again_mail
+ BulkUploadMailer
+ .send_correct_duplicates_and_upload_again_mail(bulk_upload:)
+ .deliver_later
+ end
+
def send_success_mail
BulkUploadMailer
.send_bulk_upload_complete_mail(user:, bulk_upload:)
diff --git a/app/services/bulk_upload/sales/log_creator.rb b/app/services/bulk_upload/sales/log_creator.rb
index ea337d220..69f1580a0 100644
--- a/app/services/bulk_upload/sales/log_creator.rb
+++ b/app/services/bulk_upload/sales/log_creator.rb
@@ -15,9 +15,7 @@ class BulkUpload::Sales::LogCreator
row_parser.log.blank_invalid_non_setup_fields!
row_parser.log.bulk_upload = bulk_upload
row_parser.log.creation_method = "bulk upload"
- row_parser.log.skip_update_status = true
row_parser.log.status = "pending"
- row_parser.log.status_cache = row_parser.log.calculate_status
begin
row_parser.log.save!
diff --git a/app/services/bulk_upload/sales/validator.rb b/app/services/bulk_upload/sales/validator.rb
index 76fb6f1ae..7ad9638d7 100644
--- a/app/services/bulk_upload/sales/validator.rb
+++ b/app/services/bulk_upload/sales/validator.rb
@@ -39,17 +39,17 @@ class BulkUpload::Sales::Validator
end
end
- def create_logs?
- return false if any_setup_errors?
+ def block_log_creation_reason
+ return "setup_errors" if any_setup_errors?
if row_parsers.any?(&:block_log_creation?)
Sentry.capture_message("Bulk upload log creation blocked: #{bulk_upload.id}.")
- return false
+ return "row_parser_block_log_creation"
end
if any_logs_already_exist? && FeatureToggle.bulk_upload_duplicate_log_check_enabled?
Sentry.capture_message("Bulk upload log creation blocked due to duplicate logs: #{bulk_upload.id}.")
- return false
+ return "duplicate_logs"
end
row_parsers.each do |row_parser|
@@ -58,10 +58,8 @@ class BulkUpload::Sales::Validator
if any_logs_invalid?
Sentry.capture_message("Bulk upload log creation blocked due to invalid logs after blanking non setup fields: #{bulk_upload.id}.")
- return false
+ "logs_invalid"
end
-
- true
end
def any_setup_errors?
diff --git a/app/services/exports/organisation_export_service.rb b/app/services/exports/organisation_export_service.rb
index 2b2da71c8..afcf16cb0 100644
--- a/app/services/exports/organisation_export_service.rb
+++ b/app/services/exports/organisation_export_service.rb
@@ -56,11 +56,13 @@ module Exports
def apply_cds_transformation(organisation)
attribute_hash = organisation.attributes
- attribute_hash["deleted_at"] = organisation.discarded_at
+ attribute_hash["deleted_at"] = organisation.discarded_at&.iso8601
attribute_hash["dsa_signed"] = organisation.data_protection_confirmed?
- attribute_hash["dsa_signed_at"] = organisation.data_protection_confirmation&.signed_at
+ attribute_hash["dsa_signed_at"] = organisation.data_protection_confirmation&.signed_at&.iso8601
attribute_hash["dpo_email"] = organisation.data_protection_confirmation&.data_protection_officer_email
attribute_hash["provider_type"] = organisation.provider_type_before_type_cast
+ attribute_hash["merge_date"] = organisation.merge_date&.iso8601
+ attribute_hash["available_from"] = organisation.available_from&.iso8601
attribute_hash["profit_status"] = nil # will need update when we add the field to the org
attribute_hash["group"] = nil # will need update when we add the field to the org
diff --git a/app/services/exports/user_export_service.rb b/app/services/exports/user_export_service.rb
index aaa30c424..707d13c14 100644
--- a/app/services/exports/user_export_service.rb
+++ b/app/services/exports/user_export_service.rb
@@ -60,6 +60,7 @@ module Exports
attribute_hash["organisation_name"] = user.organisation.name
attribute_hash["active"] = user.active?
attribute_hash["phone"] = [user.phone, user.phone_extension].compact.join(" ")
+ attribute_hash["last_sign_in_at"] = user.last_sign_in_at&.iso8601
attribute_hash
end
end
diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb
index 065c3b54e..8c3fe9362 100644
--- a/app/services/feature_toggle.rb
+++ b/app/services/feature_toggle.rb
@@ -11,10 +11,6 @@ class FeatureToggle
!Rails.env.development?
end
- def self.duplicate_summary_enabled?
- true
- end
-
def self.service_unavailable?
false
end
@@ -23,18 +19,6 @@ class FeatureToggle
false
end
- def self.delete_scheme_enabled?
- true
- end
-
- def self.delete_location_enabled?
- true
- end
-
- def self.delete_user_enabled?
- true
- end
-
def self.local_storage?
Rails.env.development?
end
diff --git a/app/views/bulk_upload_lettings_logs/forms/needstype.erb b/app/views/bulk_upload_lettings_logs/forms/needstype.erb
deleted file mode 100644
index 644dd9f5f..000000000
--- a/app/views/bulk_upload_lettings_logs/forms/needstype.erb
+++ /dev/null
@@ -1,23 +0,0 @@
-<% content_for :before_content do %>
- <%= govuk_back_link href: @form.back_path %>
-<% end %>
-
-
-
- <%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "needstype"), method: :patch do |f| %>
- <%= f.govuk_error_summary %>
- <%= f.hidden_field :year %>
- <%= f.hidden_field :organisation_id %>
-
- <%= f.govuk_collection_radio_buttons :needstype,
- @form.options,
- :id,
- :name,
- hint: { text: I18n.t("hints.bulk_upload.needstype") },
- legend: { text: "What is the needs type?", size: "l" },
- caption: { text: "Upload lettings logs in bulk (#{@form.year_combo})", size: "l" } %>
-
- <%= f.govuk_submit %>
- <% end %>
-
-
diff --git a/app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb b/app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb
index 0e91061c3..ce873b6d7 100644
--- a/app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb
+++ b/app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb
@@ -19,22 +19,17 @@
Create your file
-
- - Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. Leave column A blank - the bulk upload fields start in column B.
- - Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.
- - Use the <%= govuk_link_to "Lettings bulk upload Specification (2024 to 2025)", @form.specification_path %> to check your data is in the correct format.
- - Username field: To assign a log to someone else, enter the email address they use to log into CORE.
- - If you have reordered the headers, keep the headers in the file.
-
-
- <%= govuk_inset_text(text: "You can upload both general needs and supported housing logs in the same file for 2024 to 2025 data.") %>
+ <%= govuk_list [
+ "Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. Leave column A blank - the bulk upload fields start in column B.",
+ "Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.",
+ "Use the #{govuk_link_to 'Lettings bulk upload Specification (2024 to 2025)', @form.specification_path} to check your data is in the correct format.".html_safe,
+ "
Username field: To assign a log to someone else, enter the email address they use to log into CORE.".html_safe,
+ "If you have reordered the headers, keep the headers in the file.",
+ ], type: :bullet %>
Save your file
-
- - Save your file as a CSV.
- - Your file should now be ready to upload.
-
+ <%= govuk_list ["Save your file as a CSV.", "Your file should now be ready to upload."], type: :bullet %>
<%= f.govuk_submit class: "govuk-!-margin-top-7" %>
<% end %>
diff --git a/app/views/bulk_upload_lettings_resume/deletion_report.html.erb b/app/views/bulk_upload_lettings_resume/deletion_report.html.erb
index a13979dfd..d3533a130 100644
--- a/app/views/bulk_upload_lettings_resume/deletion_report.html.erb
+++ b/app/views/bulk_upload_lettings_resume/deletion_report.html.erb
@@ -28,6 +28,6 @@
<%= form_with model: @form, scope: :form, url: page_bulk_upload_lettings_resume_path(@bulk_upload, "confirm"), method: :patch do |f| %>
<%= f.govuk_submit "Clear this data and upload the logs" %>
- <%= govuk_button_link_to "I have fixed these errors and I want to reupload the file", start_bulk_upload_lettings_logs_path, secondary: true %>
+ <%= govuk_button_link_to "I have fixed these errors and I want to upload the file again", start_bulk_upload_lettings_logs_path, secondary: true %>
<% end %>
diff --git a/app/views/bulk_upload_lettings_resume/fix_choice.html.erb b/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
index 383cdbfa1..225fb07bf 100644
--- a/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
+++ b/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
@@ -24,17 +24,9 @@
<%= govuk_details(summary_text: "How to choose between fixing errors on the CORE site or in the CSV") do %>
You may find it easier to fix the errors in the CSV file if:
-
- - you have a lot of errors
- - the CSV file is formatted incorrectly and you can see where the errors are
- - you need to fix multiple errors at once
-
+ <%= govuk_list ["you have a lot of errors", "the CSV file is formatted incorrectly and you can see where the errors are", "you need to fix multiple errors at once"], type: :bullet %>
You may find it easier to fix the errors on the CORE site if:
-
- - you need to see the data in context
- - you have a smaller file, with a few errors
- - you are not sure where the errors are
-
+ <%= govuk_list ["you need to see the data in context", "you have a smaller file, with a few errors", "you are not sure where the errors are"], type: :bullet %>
<% end %>
<%= f.govuk_collection_radio_buttons :choice,
diff --git a/app/views/bulk_upload_lettings_soft_validations_check/confirm.html.erb b/app/views/bulk_upload_lettings_soft_validations_check/confirm.html.erb
index 90f5a00b3..e17b55130 100644
--- a/app/views/bulk_upload_lettings_soft_validations_check/confirm.html.erb
+++ b/app/views/bulk_upload_lettings_soft_validations_check/confirm.html.erb
@@ -5,7 +5,7 @@
Upload lettings logs in bulk (<%= @bulk_upload.year_combo %>)
-
You have chosen to upload all logs from this bulk upload.
+
Are you sure you want to upload all logs from this bulk upload?
<%= logs_and_soft_validations_warning(@bulk_upload) %>
diff --git a/app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb b/app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb
index 2a64de689..723ae5314 100644
--- a/app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb
+++ b/app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb
@@ -19,19 +19,16 @@
There are 8 rows of content in the templates. These rows are called the ‘headers’. They contain the CORE form questions and guidance about which questions are required and how to format your answers.
Create your file
-
- - Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. The bulk upload fields start at column B. Leave column A blank.
- - Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.
- - Use the <%= govuk_link_to "Sales bulk upload Specification (2024 to 2025)", @form.specification_path %> to check your data is in the correct format.
- - Username field: To assign a log to someone else, enter the email address they use to log into CORE.
- - If you have reordered the headers, keep the headers in the file.
-
+ <%= govuk_list [
+ "Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. The bulk upload fields start at column B. Leave column A blank.",
+ "Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.",
+ "Use the #{govuk_link_to 'Sales bulk upload Specification (2024 to 2025)', @form.specification_path} to check your data is in the correct format.".html_safe,
+ "
Username field: To assign a log to someone else, enter the email address they use to log into CORE.".html_safe,
+ "If you have reordered the headers, keep the headers in the file.",
+ ], type: :bullet %>
Save your file
-
- - Save your file as a CSV.
- - Your file should now be ready to upload.
-
+ <%= govuk_list ["Save your file as a CSV.", "Your file should now be ready to upload."], type: :bullet %>
<%= f.govuk_submit %>
<% end %>
diff --git a/app/views/bulk_upload_sales_resume/deletion_report.html.erb b/app/views/bulk_upload_sales_resume/deletion_report.html.erb
index bcc044439..e9013a4e2 100644
--- a/app/views/bulk_upload_sales_resume/deletion_report.html.erb
+++ b/app/views/bulk_upload_sales_resume/deletion_report.html.erb
@@ -28,6 +28,6 @@
<%= form_with model: @form, scope: :form, url: page_bulk_upload_sales_resume_path(@bulk_upload, "confirm"), method: :patch do |f| %>
<%= f.govuk_submit "Clear this data and upload the logs" %>
- <%= govuk_button_link_to "I have fixed these errors and I want to reupload the file", start_bulk_upload_sales_logs_path, secondary: true %>
+ <%= govuk_button_link_to "I have fixed these errors and I want to upload the file again", start_bulk_upload_sales_logs_path, secondary: true %>
<% end %>
diff --git a/app/views/bulk_upload_sales_resume/fix_choice.html.erb b/app/views/bulk_upload_sales_resume/fix_choice.html.erb
index 946426d0c..b376ee62d 100644
--- a/app/views/bulk_upload_sales_resume/fix_choice.html.erb
+++ b/app/views/bulk_upload_sales_resume/fix_choice.html.erb
@@ -23,18 +23,10 @@
<%= govuk_details(summary_text: "How to choose between fixing errors on the CORE site or in the CSV") do %>
-
You may find it easier to fix the errors in the CSV file if:
-
- - you have a lot of errors
- - the CSV file is formatted incorrectly and you can see where the errors are
- - you need to fix multiple errors at once
-
+
You may find it easier to fix the errors in the CSV file if:
+ <%= govuk_list ["you have a lot of errors", "the CSV file is formatted incorrectly and you can see where the errors are", "you need to fix multiple errors at once"], type: :bullet %>
You may find it easier to fix the errors on the CORE site if:
-
- - you need to see the data in context
- - you have a smaller file, with a few errors
- - you are not sure where the errors are
-
+ <%= govuk_list ["you need to see the data in context", "you have a smaller file, with a few errors", "you are not sure where the errors are"], type: :bullet %>
<% end %>
<%= f.govuk_collection_radio_buttons :choice,
diff --git a/app/views/bulk_upload_sales_soft_validations_check/confirm.html.erb b/app/views/bulk_upload_sales_soft_validations_check/confirm.html.erb
index 2b4a6e981..5c81c179d 100644
--- a/app/views/bulk_upload_sales_soft_validations_check/confirm.html.erb
+++ b/app/views/bulk_upload_sales_soft_validations_check/confirm.html.erb
@@ -5,7 +5,7 @@
Upload sales logs in bulk (<%= @bulk_upload.year_combo %>)
-
You have chosen to upload all logs from this bulk upload.
+
Are you sure you want to upload all logs from this bulk upload?
<%= logs_and_soft_validations_warning(@bulk_upload) %>
diff --git a/app/views/bulk_upload_shared/_moved_user_banner.html.erb b/app/views/bulk_upload_shared/_moved_user_banner.html.erb
index 9ab97022e..220405cc5 100644
--- a/app/views/bulk_upload_shared/_moved_user_banner.html.erb
+++ b/app/views/bulk_upload_shared/_moved_user_banner.html.erb
@@ -4,9 +4,9 @@
This error report is out of date.
<% if current_user.id == @bulk_upload.moved_user_id %>
- You moved to a different organisation since this file was uploaded. Reupload the file to get an accurate error report.
+ You moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.
<% else %>
- Some logs in this upload are assigned to <%= @bulk_upload.moved_user_name %>, who has moved to a different organisation since this file was uploaded. Reupload the file to get an accurate error report.
+ Some logs in this upload are assigned to <%= @bulk_upload.moved_user_name %>, who has moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.
<% end %>
<% end %>
<% end %>
diff --git a/app/views/bulk_upload_shared/guidance.html.erb b/app/views/bulk_upload_shared/guidance.html.erb
index 4cb8b76b4..54e8063f0 100644
--- a/app/views/bulk_upload_shared/guidance.html.erb
+++ b/app/views/bulk_upload_shared/guidance.html.erb
@@ -34,12 +34,7 @@
The bulk upload templates contain 8 rows of ‘headers’ with information about how to fill in the template, including:
<% end %>
-
- - the CORE form questions and their field numbers
- - each field’s valid responses
- - if/when certain fields can be left blank
- - which fields are used to check for duplicate logs
-
+ <%= govuk_list ["the CORE form questions and their field numbers", "each field’s valid responses", "if/when certain fields can be left blank", "which fields are used to check for duplicate logs"], type: :bullet %>
You can paste your data below the headers or copy the headers and insert them above the data in your file. The bulk upload fields start at column B. Leave column A blank.
Make sure that each column of data aligns with the corresponding question in the headers. We recommend ordering your data to match the headers, but you can also reorder the headers to match your data. When processing the file, we check what each column of data represents based on the headers above.
@@ -80,7 +75,7 @@
Once you've saved your CSV file, you can upload it via a button at the top of the lettings and sales logs pages.
When your file is done processing, you will receive an email explaining your next steps. If all your data is valid, your logs will be created. If some data is invalid, you’ll receive an email with instructions about how to resolve the errors.
If your file has errors on fields 1 through 15 for lettings, or 1 through 18 for sales, you must fix these in the CSV. This is because we need to know these answers to validate the rest of the data. Any errors in these fields will be featured in the error report’s summary tab.
-
If none of your errors are in fields 1 through 15 for lettings, or 1 through 18 for sales, you can choose how to fix the errors. You can either fix them in the CSV and reupload, or create partially complete logs and answer the remaining questions on the CORE site. Any errors that affect a significant number of logs will be featured in the error report’s summary tab to help you decide.
+
If none of your errors are in fields 1 through 15 for lettings, or 1 through 18 for sales, you can choose how to fix the errors. You can either fix them in the CSV and upload the file again, or create partially complete logs and answer the remaining questions on the CORE site. Any errors that affect a significant number of logs will be featured in the error report’s summary tab to help you decide.
<% end %>
diff --git a/app/views/bulk_upload_shared/uploads.html.erb b/app/views/bulk_upload_shared/uploads.html.erb
index 958887453..a9d134c60 100644
--- a/app/views/bulk_upload_shared/uploads.html.erb
+++ b/app/views/bulk_upload_shared/uploads.html.erb
@@ -1,4 +1,4 @@
-<% item_label = format_label(@pagy.count, "uploads") %>
+<% item_label = format_label(@pagy.count, "upload") %>
<% title = format_title(@searched, bulk_upload_title(controller.controller_name), current_user, item_label, @pagy.count, nil) %>
<% content_for :title, title %>
diff --git a/app/views/cookies/show.html.erb b/app/views/cookies/show.html.erb
index 56776b711..632e60af8 100644
--- a/app/views/cookies/show.html.erb
+++ b/app/views/cookies/show.html.erb
@@ -37,11 +37,7 @@
Google is not allowed to use or share our analytics data with anyone.
Google Analytics stores anonymised information about:
-
- - how you got to the service
- - the pages you visit on the service and how long you spend on them
- - any errors you see while using the service
-
+ <%= govuk_list ["how you got to the service", "the pages you visit on the service and how long you spend on them", "any errors you see while using the service"], type: :bullet %>
Google Analytics cookies
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index 04b436aa5..ee122dd37 100644
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -22,7 +22,7 @@
<%= f.govuk_password_field :password,
autocomplete: "current-password" %>
- <%= f.hidden_field :start, value: request["start"] %>
+ <%= f.hidden_field :start, value: request.params["start"] %>
<%= f.govuk_submit "Sign in" %>
diff --git a/app/views/form/page.html.erb b/app/views/form/page.html.erb
index 95dc38ec6..1d4f0e7a1 100644
--- a/app/views/form/page.html.erb
+++ b/app/views/form/page.html.erb
@@ -16,7 +16,6 @@
<%= form_with model: @log, url: request.original_url, method: "post", local: true do |f| %>
- <% all_questions_with_errors = all_questions_affected_by_errors(@log) %>
<% remove_other_page_errors(@log, @page) %>
<%= f.govuk_error_summary %>
@@ -76,7 +75,7 @@
<%= f.hidden_field :check_errors, value: @check_errors %>
<% end %>
- <% if all_questions_with_errors.count > 1 %>
+ <% if @pages_with_errors_count > 1 %>
<%= f.submit "See all related answers", name: "check_errors", class: "govuk-body govuk-link submit-button-link" %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index d235491a1..c7d5e2230 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -103,7 +103,7 @@
<% feedback_link = govuk_link_to "giving us your feedback (opens in a new tab)", t("feedback_form"), rel: "noreferrer noopener", target: "_blank" %>
<%= govuk_phase_banner(
- classes: "govuk-width-container",
+ classes: "#{current_user.present? ? 'no-bottom-border ' : ''}govuk-width-container",
tag: govuk_phase_banner_tag(current_user),
text: "This is a new service – help us improve it by #{feedback_link}".html_safe,
) %>
diff --git a/app/views/locations/check_answers.html.erb b/app/views/locations/check_answers.html.erb
index 8cd8bde2a..7a3a72e13 100644
--- a/app/views/locations/check_answers.html.erb
+++ b/app/views/locations/check_answers.html.erb
@@ -42,7 +42,7 @@
<% if LocationPolicy.new(current_user, @location).create? %>