Browse Source

Merge branch 'main' into CLDC-4351-only-teardown-review-apps-for-prs-with-review-apps

pull/3271/head
Nat Dean-Lewis 7 days ago committed by GitHub
parent
commit
1e7fea9e16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      Gemfile
  2. 9
      app/helpers/timecop_helper.rb
  3. 13
      app/mailers/devise_notify_mailer.rb
  4. 13
      app/mailers/notify_mailer.rb
  5. 2
      app/models/form/sales/questions/value.rb
  6. 2
      app/services/feature_toggle.rb
  7. 76
      app/services/storage/s3_service.rb
  8. 4
      config/initializers/timecop.rb
  9. 2
      config/locales/forms/2026/sales/sale_information.en.yml
  10. 2
      config/locales/validations/sales/sale_information.en.yml
  11. 2
      spec/models/form/sales/questions/value_spec.rb

5
Gemfile

@ -103,10 +103,6 @@ group :development do
gem "rubocop-rails", require: false gem "rubocop-rails", require: false
end end
group :test, :staging do
gem "timecop", "~> 0.9.4"
end
group :test do group :test do
gem "axe-core-rspec" gem "axe-core-rspec"
gem "capybara", require: false gem "capybara", require: false
@ -115,6 +111,7 @@ group :test do
gem "rspec-rails", require: false gem "rspec-rails", require: false
gem "selenium-webdriver", require: false gem "selenium-webdriver", require: false
gem "simplecov", require: false gem "simplecov", require: false
gem "timecop", "~> 0.9.4"
gem "webmock", require: false gem "webmock", require: false
end end

9
app/helpers/timecop_helper.rb

@ -1,9 +0,0 @@
module TimecopHelper
def without_timecop(&block)
if defined?(Timecop)
Timecop.return(&block)
else
yield
end
end
end

13
app/mailers/devise_notify_mailer.rb

@ -1,5 +1,4 @@
class DeviseNotifyMailer < Devise::Mailer class DeviseNotifyMailer < Devise::Mailer
include TimecopHelper
require "notifications/client" require "notifications/client"
def notify_client def notify_client
@ -9,13 +8,11 @@ class DeviseNotifyMailer < Devise::Mailer
def send_email(email_address, template_id, personalisation) def send_email(email_address, template_id, personalisation)
return true if intercept_send?(email_address) return true if intercept_send?(email_address)
without_timecop do notify_client.send_email(
notify_client.send_email( email_address:,
email_address:, template_id:,
template_id:, personalisation:,
personalisation:, )
)
end
rescue Notifications::Client::BadRequestError => e rescue Notifications::Client::BadRequestError => e
Sentry.capture_exception(e) Sentry.capture_exception(e)

13
app/mailers/notify_mailer.rb

@ -1,5 +1,4 @@
class NotifyMailer < ApplicationMailer class NotifyMailer < ApplicationMailer
include TimecopHelper
require "notifications/client" require "notifications/client"
def notify_client def notify_client
@ -9,13 +8,11 @@ class NotifyMailer < ApplicationMailer
def send_email(email, template_id, personalisation) def send_email(email, template_id, personalisation)
return true if intercept_send?(email) return true if intercept_send?(email)
without_timecop do notify_client.send_email(
notify_client.send_email( email_address: email,
email_address: email, template_id:,
template_id:, personalisation:,
personalisation:, )
)
end
end end
def personalisation(record, token, url, username: false) def personalisation(record, token, url, username: false)

2
app/models/form/sales/questions/value.rb

@ -6,7 +6,7 @@ class Form::Sales::Questions::Value < ::Form::Question
@type = "numeric" @type = "numeric"
@min = form.start_year_2026_or_later? ? 15_000 : 0 @min = form.start_year_2026_or_later? ? 15_000 : 0
@step = 1 @step = 1
@width = 5 @width = 10
@prefix = "£" @prefix = "£"
@question_number = get_question_number_from_hash(QUESTION_NUMBER_FROM_YEAR_AND_SECTION, value_key: subsection.id) @question_number = get_question_number_from_hash(QUESTION_NUMBER_FROM_YEAR_AND_SECTION, value_key: subsection.id)
@top_guidance_partial = "financial_calculations_shared_ownership" @top_guidance_partial = "financial_calculations_shared_ownership"

2
app/services/feature_toggle.rb

@ -1,6 +1,6 @@
class FeatureToggle class FeatureToggle
def self.allow_future_form_use? def self.allow_future_form_use?
Rails.env.development? || Rails.env.review? Rails.env.development? || Rails.env.review? || Rails.env.staging?
end end
def self.bulk_upload_duplicate_log_check_enabled? def self.bulk_upload_duplicate_log_check_enabled?

76
app/services/storage/s3_service.rb

@ -1,7 +1,5 @@
module Storage module Storage
class S3Service < StorageService class S3Service < StorageService
include TimecopHelper
attr_reader :configuration attr_reader :configuration
def initialize(config_service, instance_name) def initialize(config_service, instance_name)
@ -13,79 +11,61 @@ module Storage
end end
def list_files(folder) def list_files(folder)
without_timecop do @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder)
@client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder) .flat_map { |response| response.contents.map(&:key) }
.flat_map { |response| response.contents.map(&:key) }
end
end end
def folder_present?(folder) def folder_present?(folder)
without_timecop do response = @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder, max_keys: 1)
response = @client.list_objects_v2(bucket: @configuration.bucket_name, prefix: folder, max_keys: 1) response.key_count == 1
response.key_count == 1
end
end end
def get_presigned_url(file_name, duration, response_content_disposition: nil) def get_presigned_url(file_name, duration, response_content_disposition: nil)
without_timecop do Aws::S3::Presigner
Aws::S3::Presigner .new({ client: @client })
.new({ client: @client }) .presigned_url(:get_object, bucket: @configuration.bucket_name, key: file_name, expires_in: duration, response_content_disposition:)
.presigned_url(:get_object, bucket: @configuration.bucket_name, key: file_name, expires_in: duration, response_content_disposition:)
end
end end
def get_file_io(file_name) def get_file_io(file_name)
without_timecop do @client.get_object(bucket: @configuration.bucket_name, key: file_name)
@client.get_object(bucket: @configuration.bucket_name, key: file_name) .body
.body
end
end end
def get_file(file_name) def get_file(file_name)
without_timecop do @client.get_object(bucket: @configuration.bucket_name, key: file_name)
@client.get_object(bucket: @configuration.bucket_name, key: file_name) .body.read
.body.read
end
end end
def write_file(file_name, data, content_type: nil) def write_file(file_name, data, content_type: nil)
without_timecop do if content_type.nil?
if content_type.nil? @client.put_object(
@client.put_object( body: data,
body: data, bucket: @configuration.bucket_name,
bucket: @configuration.bucket_name, key: file_name,
key: file_name, )
) else
else @client.put_object(
@client.put_object( body: data,
body: data, bucket: @configuration.bucket_name,
bucket: @configuration.bucket_name, key: file_name,
key: file_name, content_type:,
content_type:, )
)
end
end end
end end
def get_file_metadata(file_name) def get_file_metadata(file_name)
without_timecop do @client.head_object(bucket: @configuration.bucket_name, key: file_name)
@client.head_object(bucket: @configuration.bucket_name, key: file_name)
end
end end
def file_exists?(file_name) def file_exists?(file_name)
without_timecop do @client.head_object(bucket: @configuration.bucket_name, key: file_name)
@client.head_object(bucket: @configuration.bucket_name, key: file_name) true
true
end
rescue Aws::S3::Errors::NotFound rescue Aws::S3::Errors::NotFound
false false
end end
def delete_file(file_name) def delete_file(file_name)
without_timecop do @client.delete_object(bucket: @configuration.bucket_name, key: file_name)
@client.delete_object(bucket: @configuration.bucket_name, key: file_name)
end
end end
private private

4
config/initializers/timecop.rb

@ -1,4 +0,0 @@
if Rails.env.staging?
require "timecop"
Timecop.travel(Time.zone.local(2026, 4, 1))
end

2
config/locales/forms/2026/sales/sale_information.en.yml

@ -153,7 +153,7 @@ en:
value_shared_ownership_staircase: value_shared_ownership_staircase:
check_answer_label: "Full purchase price" check_answer_label: "Full purchase price"
check_answer_prompt: "" check_answer_prompt: ""
hint_text: "Enter the full purchase price paid for the equity bought in this staircasing transaction (this is equal to the value of the share bought by the purchaser)." hint_text: "Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser in the current and all previous transactions)."
question_text: "What was the full purchase price for this staircasing transaction?" question_text: "What was the full purchase price for this staircasing transaction?"
equity: equity:

2
config/locales/validations/sales/sale_information.en.yml

@ -76,7 +76,7 @@ en:
mortgage_not_used: "The cash deposit is %{deposit}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same." mortgage_not_used: "The cash deposit is %{deposit}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same."
mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage equity stake purchased (%{equity}) is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same." mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage equity stake purchased (%{equity}) is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same."
mortgage_not_used_socialhomebuy: "The cash deposit (%{deposit}) and cash discount (%{cashdis}) added together is %{deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought (%{equity}) is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same." mortgage_not_used_socialhomebuy: "The cash deposit (%{deposit}) and cash discount (%{cashdis}) added together is %{deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought (%{equity}) is %{expected_shared_ownership_deposit_value}.</br></br>These two amounts should be the same."
staircasing_mortgage: # this key staircasing_mortgage:
mortgage_used: "The mortgage (%{mortgage}) and cash deposit (%{deposit}) added together is %{mortgage_and_deposit_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.</br></br>These two amounts should be the same." mortgage_used: "The mortgage (%{mortgage}) and cash deposit (%{deposit}) added together is %{mortgage_and_deposit_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.</br></br>These two amounts should be the same."
mortgage_not_used: "The cash deposit is %{deposit}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.</br></br>These two amounts should be the same." mortgage_not_used: "The cash deposit is %{deposit}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought is %{stairbought_part_of_value}.</br></br>These two amounts should be the same."
mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.</br></br>These two amounts should be the same." mortgage_used_socialhomebuy: "The mortgage amount (%{mortgage}), cash deposit (%{deposit}), and cash discount (%{cashdis}) added together is %{mortgage_deposit_and_discount_total}.</br></br>The full purchase price (%{value}) multiplied by the percentage bought (%{stairbought}) is %{stairbought_part_of_value}.</br></br>These two amounts should be the same."

2
spec/models/form/sales/questions/value_spec.rb

@ -32,7 +32,7 @@ RSpec.describe Form::Sales::Questions::Value, type: :model do
end end
it "has correct width" do it "has correct width" do
expect(question.width).to eq(5) expect(question.width).to eq(10)
end end
it "has correct prefix" do it "has correct prefix" do

Loading…
Cancel
Save