Skip to content

Commit

Permalink
[CRIMAPP-1403] Update payment fieldset form validation (#1307)
Browse files Browse the repository at this point in the history
* Update payment fieldset form validation

* Fix failing specs

* Fix linting error

* Fix failing spec

* Refactor

* Code coverage fix
  • Loading branch information
hiboabd authored Jan 14, 2025
1 parent 8bc6c88 commit 5a907e2
Show file tree
Hide file tree
Showing 19 changed files with 156 additions and 381 deletions.
19 changes: 19 additions & 0 deletions app/forms/concerns/steps/payment_fieldset_validation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Steps
module PaymentFieldsetValidation
extend ActiveSupport::Concern

def validate_frequency
errors.add(:frequency, :blank, payment_type: payment_type_label) if frequency.blank?
return unless frequencies.exclude?(frequency)

errors.add(:frequency, :inclusion,
payment_type: payment_type_label&.capitalize)
end

def validate_amount
errors.add(:amount, :blank, payment_type: payment_type_label) if amount.blank?
errors.add(:amount, :not_a_number, payment_type: payment_type_label) if Type::Pence.new.serialize(amount).nil?
errors.add(:amount, :greater_than, payment_type: payment_type_label) if amount.to_i <= 0
end
end
end
30 changes: 8 additions & 22 deletions app/forms/steps/income/income_benefit_fieldset_form.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
module Steps
module Income
class IncomeBenefitFieldsetForm < Steps::BaseFormObject
include Steps::PaymentFieldsetValidation

attribute :id, :string
attribute :payment_type, :string
attribute :amount, :pence
attribute :frequency, :string
attribute :details, :string

validate { presence_with_payment_type :amount }
validate { presence_with_payment_type :frequency }

validates :amount, numericality: {
greater_than: 0
}

validate :validate_amount
validate :validate_frequency
validates :payment_types, presence: true, inclusion: { in: :payment_types }
validates :frequency, inclusion: { in: :frequencies }

validate :details_only_when_other?

# Needed for `#fields_for` to render the uuids as hidden fields
Expand Down Expand Up @@ -51,24 +46,15 @@ def details_only_when_other?
if (payment_type == IncomeBenefitType::OTHER.to_s) && details.blank?
errors.add(:details, :blank)
elsif (payment_type != IncomeBenefitType::OTHER.to_s) && details.present?
errors.add(:details, :invalid)
errors.add(:details, :invalid, payment_type: payment_type_label)
end
end

def presence_with_payment_type(attribute)
return if send(attribute).present?

payment_type_str = I18n.t(
def payment_type_label
I18n.t(
payment_type,
scope: [:helpers, :label, :steps_income_income_benefits_form, :types_options]
)
payment_type_str&.downcase! if payment_type == IncomeBenefitType::OTHER.to_s

errors.add(
attribute,
:blank,
payment_type: payment_type_str
)
)&.downcase!
end
end
end
Expand Down
27 changes: 7 additions & 20 deletions app/forms/steps/income/income_payment_fieldset_form.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
module Steps
module Income
class IncomePaymentFieldsetForm < Steps::BaseFormObject
include Steps::PaymentFieldsetValidation

attribute :id, :string
attribute :payment_type, :string
attribute :amount, :pence
attribute :frequency, :string
attribute :details, :string

validate { presence_with_payment_type :amount }
validate { presence_with_payment_type :frequency }

validates :amount, numericality: {
greater_than: 0
}

validate :validate_amount
validate :validate_frequency
validates :payment_types, presence: true, inclusion: { in: :payment_types }
validates :frequency, inclusion: { in: :frequencies }

validate :details_only_when_other?

def payment_types
Expand Down Expand Up @@ -51,23 +46,15 @@ def details_only_when_other?
if (payment_type == IncomePaymentType::OTHER.to_s) && details.blank?
errors.add(:details, :blank)
elsif (payment_type != IncomePaymentType::OTHER.to_s) && details.present?
errors.add(:details, :invalid)
errors.add(:details, :invalid, payment_type: payment_type_label)
end
end

def presence_with_payment_type(attribute)
return if send(attribute).present?

payment_type_str = I18n.t(
def payment_type_label
I18n.t(
payment_type,
scope: [:helpers, :label, :steps_income_income_payments_form, :types_options]
)&.downcase!

errors.add(
attribute,
:blank,
payment_type: payment_type_str
)
end
end
end
Expand Down
28 changes: 7 additions & 21 deletions app/forms/steps/income/partner/income_benefit_fieldset_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,17 @@ module Steps
module Income
module Partner
class IncomeBenefitFieldsetForm < Steps::BaseFormObject
include Steps::PaymentFieldsetValidation

attribute :id, :string
attribute :payment_type, :string
attribute :amount, :pence
attribute :frequency, :string
attribute :details, :string

validate { presence_with_payment_type :amount }
validate { presence_with_payment_type :frequency }

validates :amount, numericality: {
greater_than: 0
}

validate :validate_amount
validate :validate_frequency
validates :payment_types, presence: true, inclusion: { in: :payment_types }
validates :frequency, inclusion: { in: :frequencies }

validate :details_only_when_other?

# Needed for `#fields_for` to render the uuids as hidden fields
Expand Down Expand Up @@ -56,20 +51,11 @@ def details_only_when_other?
end
end

def presence_with_payment_type(attribute)
return if send(attribute).present?

payment_type_str = I18n.t(
def payment_type_label
I18n.t(
payment_type,
scope: [:helpers, :label, :steps_income_income_benefits_form, :types_options]
)
payment_type_str&.downcase! if payment_type == IncomeBenefitType::OTHER.to_s

errors.add(
attribute,
:blank,
payment_type: payment_type_str
)
)&.downcase!
end
end
end
Expand Down
27 changes: 7 additions & 20 deletions app/forms/steps/income/partner/income_payment_fieldset_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,17 @@ module Steps
module Income
module Partner
class IncomePaymentFieldsetForm < Steps::BaseFormObject
include Steps::PaymentFieldsetValidation

attribute :id, :string
attribute :payment_type, :string
attribute :amount, :pence
attribute :frequency, :string
attribute :details, :string

validate { presence_with_payment_type :amount }
validate { presence_with_payment_type :frequency }

validates :amount, numericality: {
greater_than: 0
}

validate :validate_amount
validate :validate_frequency
validates :payment_types, presence: true, inclusion: { in: :payment_types }
validates :frequency, inclusion: { in: :frequencies }

validate :details_only_when_other?

def payment_types
Expand Down Expand Up @@ -52,23 +47,15 @@ def details_only_when_other?
if (payment_type == IncomePaymentType::OTHER.to_s) && details.blank?
errors.add(:details, :blank)
elsif (payment_type != IncomePaymentType::OTHER.to_s) && details.present?
errors.add(:details, :invalid)
errors.add(:details, :invalid, payment_type: payment_type_label)
end
end

def presence_with_payment_type(attribute)
return if send(attribute).present?

payment_type_str = I18n.t(
def payment_type_label
I18n.t(
payment_type,
scope: [:helpers, :label, :steps_income_income_payments_form, :types_options]
)&.downcase!

errors.add(
attribute,
:blank,
payment_type: payment_type_str
)
end
end
end
Expand Down
17 changes: 11 additions & 6 deletions app/forms/steps/outgoings/outgoing_payment_fieldset_form.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
module Steps
module Outgoings
class OutgoingPaymentFieldsetForm < Steps::BaseFormObject
include Steps::PaymentFieldsetValidation

attribute :id, :string
attribute :payment_type, :string
attribute :amount, :pence
attribute :frequency, :string
attribute :case_reference, :string

validates :amount, numericality: {
greater_than: 0
}

validate :validate_amount
validate :validate_frequency
validates :payment_types, presence: true, inclusion: { in: :payment_types }
validates :frequency, presence: true, inclusion: { in: :frequencies }

validate :case_ref_when_legal_aid_contribution?

# Needed for `#fields_for` to render the uuids as hidden fields
Expand Down Expand Up @@ -51,6 +49,13 @@ def case_ref_when_legal_aid_contribution?
errors.add(:case_reference, :invalid)
end
end

def payment_type_label
I18n.t(
payment_type,
scope: [:helpers, :label, :steps_outgoings_outgoings_payments_form, :types_options]
)&.downcase!
end
end
end
end
38 changes: 38 additions & 0 deletions app/validators/base_payments_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
class BasePaymentsValidator < ActiveModel::Validator
attr_reader :record

def validate(record)
@record = record

record.types.each do |type|
next if type == 'none'

payment = record.public_send(type)
add_errors(payment) unless payment.valid?
end

return unless record.types.empty?

record.errors.add(:base, :none_selected) if has_no_payments?
end

# :nocov:
def has_no_payments?
raise 'must be implemented in subclasses'
end
# :nocov:

private

def add_errors(payment)
payment.errors.each do |error|
attr_name = "#{payment.payment_type.dasherize}-#{error.attribute}"
record.errors.add(attr_name, error.type, message: error.message)

# We define the attribute getter as it doesn't really exist
record.define_singleton_method(attr_name) do
payment.public_send(error.attribute)
end
end
end
end
57 changes: 3 additions & 54 deletions app/validators/income_benefits_validator.rb
Original file line number Diff line number Diff line change
@@ -1,56 +1,5 @@
class IncomeBenefitsValidator < ActiveModel::Validator
attr_reader :record

def validate(record)
@record = record

record.types.each_with_index do |type, index|
next if type == 'none'

income_benefit = record.public_send(type)
add_indexed_errors(income_benefit, index) unless income_benefit.valid?
end

return unless record.types.empty?

record.errors.add(:base, :none_selected) if record.has_no_income_benefits.blank?
end

private

def add_indexed_errors(income_benefit, index)
income_benefit.errors.each do |error|
attr_name = indexed_attribute(index, income_benefit, error.attribute)

record.errors.add(
attr_name,
error.type,
message: error_message(income_benefit, error)
)

# We define the attribute getter as it doesn't really exist
record.define_singleton_method(attr_name) do
income_benefit.public_send(error.attribute)
end
end
end

def indexed_attribute(_index, income_benefit, attr)
"#{income_benefit.payment_type.dasherize}-#{attr}"
end

# `activemodel.errors.models.steps/income/income_benefit_fieldset_form.summary.x.y`
def error_message(obj, error)
payment_type = I18n.t(
obj.payment_type,
scope: [:helpers, :label, :steps_income_income_benefits_form, :types_options]
)
payment_type&.downcase! if obj.payment_type == IncomeBenefitType::OTHER.to_s

I18n.t(
"#{obj.model_name.i18n_key}.summary.#{error.attribute}.#{error.type}",
scope: [:activemodel, :errors, :models],
payment_type: payment_type
)
class IncomeBenefitsValidator < BasePaymentsValidator
def has_no_payments?
record.has_no_income_benefits.blank?
end
end
Loading

0 comments on commit 5a907e2

Please sign in to comment.