Merge pull request #10242 from demarches-simplifiees/US/fix-decimal-number-validator
Correctif(annotations privées): ETQ instructeur, je ne pouvais modifier une annotation quand un usager avait saisi des valeur de champs incorrectes
This commit is contained in:
commit
4da36531d4
28 changed files with 231 additions and 146 deletions
|
@ -74,8 +74,8 @@ class Migrations::BatchUpdatePaysValuesJob < ApplicationJob
|
||||||
def perform(ids)
|
def perform(ids)
|
||||||
ids.each do |id|
|
ids.each do |id|
|
||||||
pays_champ = Champs::PaysChamp.find(id)
|
pays_champ = Champs::PaysChamp.find(id)
|
||||||
next if pays_champ.valid?
|
|
||||||
|
|
||||||
|
next if pays_champ.valid?(pays_champ.public? ? :champs_public_value : :champs_private_value)
|
||||||
code = APIGeoService.country_code(pays_champ.value)
|
code = APIGeoService.country_code(pays_champ.value)
|
||||||
value = if code.present?
|
value = if code.present?
|
||||||
APIGeoService.country_name(code)
|
APIGeoService.country_name(code)
|
||||||
|
|
|
@ -5,7 +5,11 @@ class Champs::BooleanChamp < Champ
|
||||||
before_validation :set_value_to_nil, if: -> { value.blank? }
|
before_validation :set_value_to_nil, if: -> { value.blank? }
|
||||||
before_validation :set_value_to_false, unless: -> { ([nil, TRUE_VALUE, FALSE_VALUE]).include?(value) }
|
before_validation :set_value_to_false, unless: -> { ([nil, TRUE_VALUE, FALSE_VALUE]).include?(value) }
|
||||||
|
|
||||||
validates :value, inclusion: [TRUE_VALUE, FALSE_VALUE], allow_nil: true, allow_blank: false
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
|
validates :value, inclusion: [TRUE_VALUE, FALSE_VALUE],
|
||||||
|
allow_nil: true,
|
||||||
|
allow_blank: false,
|
||||||
|
if: :validate_champ_value?
|
||||||
|
|
||||||
def true?
|
def true?
|
||||||
value == TRUE_VALUE
|
value == TRUE_VALUE
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
class Champs::CiviliteChamp < Champ
|
class Champs::CiviliteChamp < Champ
|
||||||
validates :value, inclusion: ["M.", "Mme"], allow_nil: true, allow_blank: false
|
validates :value, inclusion: ["M.", "Mme"],
|
||||||
|
allow_nil: true,
|
||||||
|
allow_blank: false,
|
||||||
|
if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
|
|
||||||
def legend_label?
|
def legend_label?
|
||||||
true
|
true
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Champs::CnafChamp < Champs::TextChamp
|
class Champs::CnafChamp < Champs::TextChamp
|
||||||
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/cnaf-input-validation.middleware.ts
|
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/cnaf-input-validation.middleware.ts
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :numero_allocataire, format: { with: /\A\d{1,7}\z/ }, if: -> { code_postal.present? && validate_champ_value? }
|
validates :numero_allocataire, format: { with: /\A\d{1,7}\z/ }, if: -> { code_postal.present? && validate_champ_value? }
|
||||||
validates :code_postal, format: { with: /\A\w{5}\z/ }, if: -> { numero_allocataire.present? && validate_champ_value? }
|
validates :code_postal, format: { with: /\A\w{5}\z/ }, if: -> { numero_allocataire.present? && validate_champ_value? }
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Champs::DecimalNumberChamp < Champ
|
||||||
message: -> (object, _data) {
|
message: -> (object, _data) {
|
||||||
"« #{object.libelle} » " + object.errors.generate_message(:value, :not_a_number)
|
"« #{object.libelle} » " + object.errors.generate_message(:value, :not_a_number)
|
||||||
}
|
}
|
||||||
}
|
}, if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
|
|
||||||
def for_export
|
def for_export
|
||||||
processed_value
|
processed_value
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Champs::DepartementChamp < Champs::TextChamp
|
class Champs::DepartementChamp < Champs::TextChamp
|
||||||
store_accessor :value_json, :code_region
|
store_accessor :value_json, :code_region
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :value_in_departement_names, unless: -> { value.nil? }
|
validate :value_in_departement_names, unless: -> { value.nil? }
|
||||||
validate :external_id_in_departement_codes, unless: -> { external_id.nil? }
|
validate :external_id_in_departement_codes, unless: -> { external_id.nil? }
|
||||||
before_save :store_code_region
|
before_save :store_code_region
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Champs::DgfipChamp < Champs::TextChamp
|
class Champs::DgfipChamp < Champs::TextChamp
|
||||||
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/dgfip-input-validation.middleware.ts
|
# see https://github.com/betagouv/api-particulier/blob/master/src/presentation/middlewares/dgfip-input-validation.middleware.ts
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :numero_fiscal, format: { with: /\A\w{13,14}\z/ }, if: -> { reference_avis.present? && validate_champ_value? }
|
validates :numero_fiscal, format: { with: /\A\w{13,14}\z/ }, if: -> { reference_avis.present? && validate_champ_value? }
|
||||||
validates :reference_avis, format: { with: /\A\w{13,14}\z/ }, if: -> { numero_fiscal.present? && validate_champ_value? }
|
validates :reference_avis, format: { with: /\A\w{13,14}\z/ }, if: -> { numero_fiscal.present? && validate_champ_value? }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Champs::DossierLinkChamp < Champ
|
class Champs::DossierLinkChamp < Champ
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :value_integerable, if: -> { value.present? }, on: :prefill
|
validate :value_integerable, if: -> { value.present? }, on: :prefill
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -5,6 +5,7 @@ class Champs::DropDownListChamp < Champ
|
||||||
OTHER = '__other__'
|
OTHER = '__other__'
|
||||||
delegate :options_without_empty_value_when_mandatory, to: :type_de_champ
|
delegate :options_without_empty_value_when_mandatory, to: :type_de_champ
|
||||||
|
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :value_is_in_options, unless: -> { value.blank? || drop_down_other? }
|
validate :value_is_in_options, unless: -> { value.blank? || drop_down_other? }
|
||||||
|
|
||||||
def render_as_radios?
|
def render_as_radios?
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class Champs::EmailChamp < Champs::TextChamp
|
class Champs::EmailChamp < Champs::TextChamp
|
||||||
include EmailSanitizableConcern
|
include EmailSanitizableConcern
|
||||||
before_validation -> { sanitize_email(:value) }
|
before_validation -> { sanitize_email(:value) }
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :value, allow_blank: true, format: { with: StrictEmailValidator::REGEXP }, if: :validate_champ_value?
|
validates :value, allow_blank: true, format: { with: StrictEmailValidator::REGEXP }, if: :validate_champ_value?
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
class Champs::EngagementJuridiqueChamp < Champ
|
class Champs::EngagementJuridiqueChamp < Champ
|
||||||
# cf: https://communaute.chorus-pro.gouv.fr/documentation/creer-un-engagement/#1522314752186-a34f3662-0644b5d1-16c22add-8ea097de-3a0a
|
# cf: https://communaute.chorus-pro.gouv.fr/documentation/creer-un-engagement/#1522314752186-a34f3662-0644b5d1-16c22add-8ea097de-3a0a
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates_with ExpressionReguliereValidator,
|
validates_with ExpressionReguliereValidator,
|
||||||
expression_reguliere: /([A-Z]|[0-9]|\-|\_|\+|\/)+/,
|
expression_reguliere: /([A-Z]|[0-9]|\-|\_|\+|\/)+/,
|
||||||
expression_reguliere_error_message: "Le numéro d'EJ ne peut contenir que des caractères alphanumérique et les caractères spéciaux suivant : “-“ ; “_“ ; “+“ ; “/“",
|
expression_reguliere_error_message: "Le numéro d'EJ ne peut contenir que des caractères alphanumérique et les caractères spéciaux suivant : “-“ ; “_“ ; “+“ ; “/“",
|
||||||
if: -> { validation_context != :brouillon }
|
if: :validate_champ_value?
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@ class Champs::EpciChamp < Champs::TextChamp
|
||||||
before_validation :on_departement_change
|
before_validation :on_departement_change
|
||||||
before_validation :on_epci_name_changes
|
before_validation :on_epci_name_changes
|
||||||
|
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :code_departement_in_departement_codes, unless: -> { code_departement.nil? }
|
validate :code_departement_in_departement_codes, unless: -> { code_departement.nil? }
|
||||||
validate :external_id_in_departement_epci_codes, unless: -> { code_departement.nil? || external_id.nil? }
|
validate :external_id_in_departement_epci_codes, unless: -> { code_departement.nil? || external_id.nil? }
|
||||||
validate :value_in_departement_epci_names, unless: -> { code_departement.nil? || external_id.nil? || value.nil? }
|
validate :value_in_departement_epci_names, unless: -> { code_departement.nil? || external_id.nil? || value.nil? }
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
class Champs::ExpressionReguliereChamp < Champ
|
class Champs::ExpressionReguliereChamp < Champ
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates_with ExpressionReguliereValidator, if: :validate_champ_value?
|
validates_with ExpressionReguliereValidator, if: :validate_champ_value?
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Champs::IbanChamp < Champ
|
class Champs::IbanChamp < Champ
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates_with IbanValidator, if: :validate_champ_value?
|
validates_with IbanValidator, if: :validate_champ_value?
|
||||||
after_validation :format_iban
|
after_validation :format_iban
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ class Champs::IntegerNumberChamp < Champ
|
||||||
# i18n-tasks-use t('errors.messages.not_an_integer')
|
# i18n-tasks-use t('errors.messages.not_an_integer')
|
||||||
"« #{object.libelle} » " + object.errors.generate_message(:value, :not_an_integer)
|
"« #{object.libelle} » " + object.errors.generate_message(:value, :not_an_integer)
|
||||||
}
|
}
|
||||||
}
|
}, if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
|
|
||||||
def for_export
|
def for_export
|
||||||
processed_value
|
processed_value
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Champs::MultipleDropDownListChamp < Champ
|
class Champs::MultipleDropDownListChamp < Champ
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :values_are_in_options, if: -> { value.present? }
|
validate :values_are_in_options, if: -> { value.present? }
|
||||||
|
|
||||||
def options?
|
def options?
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
class Champs::PaysChamp < Champs::TextChamp
|
class Champs::PaysChamp < Champs::TextChamp
|
||||||
validates :value, inclusion: APIGeoService.countries.pluck(:name), allow_nil: true, allow_blank: false
|
with_options if: :validate_champ_value? do
|
||||||
validates :external_id, inclusion: APIGeoService.countries.pluck(:code), allow_nil: true, allow_blank: false
|
validates :external_id, inclusion: APIGeoService.countries.pluck(:code), allow_nil: true, allow_blank: false
|
||||||
|
validates :value, inclusion: APIGeoService.countries.pluck(:name), allow_nil: true, allow_blank: false
|
||||||
|
end
|
||||||
|
|
||||||
|
# def value=(code) can reset champs to nil if value is empty, in case of prefill
|
||||||
|
# we do not want to try to save the champ with an nil value
|
||||||
|
with_options if: -> { validation_context == :prefill } do
|
||||||
|
validates :external_id, inclusion: APIGeoService.countries.pluck(:code), allow_nil: false, allow_blank: false
|
||||||
|
validates :value, inclusion: APIGeoService.countries.pluck(:name), allow_nil: false, allow_blank: false
|
||||||
|
end
|
||||||
|
|
||||||
def for_export
|
def for_export
|
||||||
[name, code]
|
[name, code]
|
||||||
|
@ -26,8 +35,13 @@ class Champs::PaysChamp < Champs::TextChamp
|
||||||
self.external_id = nil
|
self.external_id = nil
|
||||||
super(nil)
|
super(nil)
|
||||||
elsif code != value
|
elsif code != value
|
||||||
self.external_id = APIGeoService.country_code(code)
|
self.external_id = APIGeoService.country_code(code) # lookup by code which is a country name
|
||||||
super(code)
|
|
||||||
|
if self.external_id # if we match a country code, lookup for country name with code
|
||||||
|
super(APIGeoService.country_name(self.external_id, locale: 'FR'))
|
||||||
|
else # if we did not match any country code, external_id is nil as well as value
|
||||||
|
super(nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,8 @@ class Champs::PhoneChamp < Champs::TextChamp
|
||||||
possible: true,
|
possible: true,
|
||||||
allow_blank: true,
|
allow_blank: true,
|
||||||
message: I18n.t(:not_a_phone, scope: 'activerecord.errors.messages')
|
message: I18n.t(:not_a_phone, scope: 'activerecord.errors.messages')
|
||||||
}, unless: -> { Phonelib.valid_for_countries?(value, DEFAULT_COUNTRY_CODES) }
|
},
|
||||||
|
if: -> { (validate_champ_value? || validation_context == :prefill) && !Phonelib.valid_for_countries?(value, DEFAULT_COUNTRY_CODES) }
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
return '' if value.blank?
|
return '' if value.blank?
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class Champs::PieceJustificativeChamp < Champ
|
class Champs::PieceJustificativeChamp < Champ
|
||||||
FILE_MAX_SIZE = 200.megabytes
|
FILE_MAX_SIZE = 200.megabytes
|
||||||
|
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :piece_justificative_file,
|
validates :piece_justificative_file,
|
||||||
size: { less_than: FILE_MAX_SIZE },
|
size: { less_than: FILE_MAX_SIZE },
|
||||||
if: -> { !type_de_champ.skip_pj_validation }
|
if: -> { !type_de_champ.skip_pj_validation }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Champs::RegionChamp < Champs::TextChamp
|
class Champs::RegionChamp < Champs::TextChamp
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validate :value_in_region_names, unless: -> { value.nil? }
|
validate :value_in_region_names, unless: -> { value.nil? }
|
||||||
validate :external_id_in_region_codes, unless: -> { external_id.nil? }
|
validate :external_id_in_region_codes, unless: -> { external_id.nil? }
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class Champs::RNAChamp < Champ
|
class Champs::RNAChamp < Champ
|
||||||
include RNAChampAssociationFetchableConcern
|
include RNAChampAssociationFetchableConcern
|
||||||
|
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :value, allow_blank: true, format: {
|
validates :value, allow_blank: true, format: {
|
||||||
with: /\AW[0-9A-Z]{9}\z/, message: I18n.t(:not_a_rna, scope: 'activerecord.errors.messages')
|
with: /\AW[0-9A-Z]{9}\z/, message: I18n.t(:not_a_rna, scope: 'activerecord.errors.messages')
|
||||||
}, if: :validate_champ_value?
|
}, if: :validate_champ_value?
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class Champs::TitreIdentiteChamp < Champ
|
class Champs::TitreIdentiteChamp < Champ
|
||||||
FILE_MAX_SIZE = 20.megabytes
|
FILE_MAX_SIZE = 20.megabytes
|
||||||
ACCEPTED_FORMATS = ['image/png', 'image/jpeg']
|
ACCEPTED_FORMATS = ['image/png', 'image/jpeg']
|
||||||
|
# TODO: if: -> { validate_champ_value? || validation_context == :prefill }
|
||||||
validates :piece_justificative_file, content_type: ACCEPTED_FORMATS, size: { less_than: FILE_MAX_SIZE }
|
validates :piece_justificative_file, content_type: ACCEPTED_FORMATS, size: { less_than: FILE_MAX_SIZE }
|
||||||
|
|
||||||
def main_value_name
|
def main_value_name
|
||||||
|
|
|
@ -940,14 +940,18 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
|
|
||||||
describe "#update_annotations" do
|
describe "#update_annotations" do
|
||||||
let(:procedure) do
|
let(:procedure) do
|
||||||
create(:procedure, :published, types_de_champ_private: [
|
create(:procedure, :published, types_de_champ_public:, types_de_champ_private:, instructeurs: instructeurs)
|
||||||
|
end
|
||||||
|
let(:types_de_champ_private) do
|
||||||
|
[
|
||||||
{ type: :multiple_drop_down_list },
|
{ type: :multiple_drop_down_list },
|
||||||
{ type: :linked_drop_down_list },
|
{ type: :linked_drop_down_list },
|
||||||
{ type: :datetime },
|
{ type: :datetime },
|
||||||
{ type: :repetition, children: [{}] },
|
{ type: :repetition, children: [{}] },
|
||||||
{ type: :drop_down_list, options: [:a, :b, :other] }
|
{ type: :drop_down_list, options: [:a, :b, :other] }
|
||||||
], instructeurs: instructeurs)
|
]
|
||||||
end
|
end
|
||||||
|
let(:types_de_champ_public) { [] }
|
||||||
let(:dossier) { create(:dossier, :en_construction, :with_populated_annotations, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, :with_populated_annotations, procedure: procedure) }
|
||||||
let(:another_instructeur) { create(:instructeur) }
|
let(:another_instructeur) { create(:instructeur) }
|
||||||
let(:now) { Time.zone.parse('01/01/2100') }
|
let(:now) { Time.zone.parse('01/01/2100') }
|
||||||
|
@ -958,24 +962,105 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
let(:champ_repetition) { dossier.champs_private.fourth }
|
let(:champ_repetition) { dossier.champs_private.fourth }
|
||||||
let(:champ_drop_down_list) { dossier.champs_private.fifth }
|
let(:champ_drop_down_list) { dossier.champs_private.fifth }
|
||||||
|
|
||||||
before do
|
context 'when no invalid champs_public' do
|
||||||
expect(controller.current_instructeur).to receive(:mark_tab_as_seen).with(dossier, :annotations_privees)
|
context "with new values for champs_private" do
|
||||||
another_instructeur.follow(dossier)
|
before do
|
||||||
Timecop.freeze(now)
|
expect(controller.current_instructeur).to receive(:mark_tab_as_seen).with(dossier, :annotations_privees)
|
||||||
patch :update_annotations, params: params, format: :turbo_stream
|
another_instructeur.follow(dossier)
|
||||||
|
Timecop.freeze(now)
|
||||||
|
patch :update_annotations, params: params, format: :turbo_stream
|
||||||
|
|
||||||
champ_multiple_drop_down_list.reload
|
champ_multiple_drop_down_list.reload
|
||||||
champ_linked_drop_down_list.reload
|
champ_linked_drop_down_list.reload
|
||||||
champ_datetime.reload
|
champ_datetime.reload
|
||||||
champ_repetition.reload
|
champ_repetition.reload
|
||||||
champ_drop_down_list.reload
|
champ_drop_down_list.reload
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
Timecop.return
|
||||||
|
end
|
||||||
|
let(:params) do
|
||||||
|
{
|
||||||
|
procedure_id: procedure.id,
|
||||||
|
dossier_id: dossier.id,
|
||||||
|
dossier: {
|
||||||
|
champs_private_attributes: {
|
||||||
|
'0': {
|
||||||
|
id: champ_multiple_drop_down_list.id,
|
||||||
|
value: ['', 'val1', 'val2']
|
||||||
|
},
|
||||||
|
'1': {
|
||||||
|
id: champ_datetime.id,
|
||||||
|
value: '2019-12-21T13:17'
|
||||||
|
},
|
||||||
|
'2': {
|
||||||
|
id: champ_linked_drop_down_list.id,
|
||||||
|
primary_value: 'primary',
|
||||||
|
secondary_value: 'secondary'
|
||||||
|
},
|
||||||
|
'3': {
|
||||||
|
id: champ_repetition.champs.first.id,
|
||||||
|
value: 'text'
|
||||||
|
},
|
||||||
|
'4': {
|
||||||
|
id: champ_drop_down_list.id,
|
||||||
|
value: '__other__',
|
||||||
|
value_other: 'other value'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(champ_multiple_drop_down_list.value).to eq('["val1","val2"]')
|
||||||
|
expect(champ_linked_drop_down_list.primary_value).to eq('primary')
|
||||||
|
expect(champ_linked_drop_down_list.secondary_value).to eq('secondary')
|
||||||
|
expect(champ_datetime.value).to eq(Time.zone.parse('2019-12-21T13:17:00').iso8601)
|
||||||
|
expect(champ_repetition.champs.first.value).to eq('text')
|
||||||
|
expect(champ_drop_down_list.value).to eq('other value')
|
||||||
|
expect(dossier.reload.last_champ_private_updated_at).to eq(now)
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
}
|
||||||
|
|
||||||
|
it 'updates the annotations' do
|
||||||
|
Timecop.travel(now + 1.hour)
|
||||||
|
expect(instructeur.followed_dossiers.with_notifications).to eq([])
|
||||||
|
expect(another_instructeur.followed_dossiers.with_notifications).to eq([dossier.reload])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "without new values for champs_private" do
|
||||||
|
let(:params) do
|
||||||
|
{
|
||||||
|
procedure_id: procedure.id,
|
||||||
|
dossier_id: dossier.id,
|
||||||
|
dossier: {
|
||||||
|
champs_private_attributes: {},
|
||||||
|
champs_public_attributes: {
|
||||||
|
'0': {
|
||||||
|
id: champ_multiple_drop_down_list.id,
|
||||||
|
value: ['', 'val1', 'val2']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(dossier.reload.last_champ_private_updated_at).to eq(nil)
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
after do
|
context 'with invalid champs_public (DecimalNumberChamp)' do
|
||||||
Timecop.return
|
let(:types_de_champ_public) do
|
||||||
end
|
[
|
||||||
|
{ type: :decimal_number }
|
||||||
context "with new values for champs_private" do
|
]
|
||||||
|
end
|
||||||
let(:params) do
|
let(:params) do
|
||||||
{
|
{
|
||||||
procedure_id: procedure.id,
|
procedure_id: procedure.id,
|
||||||
|
@ -983,72 +1068,22 @@ describe Instructeurs::DossiersController, type: :controller do
|
||||||
dossier: {
|
dossier: {
|
||||||
champs_private_attributes: {
|
champs_private_attributes: {
|
||||||
'0': {
|
'0': {
|
||||||
id: champ_multiple_drop_down_list.id,
|
|
||||||
value: ['', 'val1', 'val2']
|
|
||||||
},
|
|
||||||
'1': {
|
|
||||||
id: champ_datetime.id,
|
id: champ_datetime.id,
|
||||||
value: '2019-12-21T13:17'
|
value: '2024-03-30T07:03'
|
||||||
},
|
|
||||||
'2': {
|
|
||||||
id: champ_linked_drop_down_list.id,
|
|
||||||
primary_value: 'primary',
|
|
||||||
secondary_value: 'secondary'
|
|
||||||
},
|
|
||||||
'3': {
|
|
||||||
id: champ_repetition.champs.first.id,
|
|
||||||
value: 'text'
|
|
||||||
},
|
|
||||||
'4': {
|
|
||||||
id: champ_drop_down_list.id,
|
|
||||||
value: '__other__',
|
|
||||||
value_other: 'other value'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it {
|
it 'update champs_private' do
|
||||||
expect(champ_multiple_drop_down_list.value).to eq('["val1","val2"]')
|
too_long_float = '3.1415'
|
||||||
expect(champ_linked_drop_down_list.primary_value).to eq('primary')
|
dossier.champs_public.first.update_column(:value, too_long_float)
|
||||||
expect(champ_linked_drop_down_list.secondary_value).to eq('secondary')
|
patch :update_annotations, params: params, format: :turbo_stream
|
||||||
expect(champ_datetime.value).to eq(Time.zone.parse('2019-12-21T13:17:00').iso8601)
|
champ_datetime.reload
|
||||||
expect(champ_repetition.champs.first.value).to eq('text')
|
expect(champ_datetime.value).to eq(Time.zone.parse('2024-03-30T07:03:00').iso8601)
|
||||||
expect(champ_drop_down_list.value).to eq('other value')
|
|
||||||
expect(dossier.reload.last_champ_private_updated_at).to eq(now)
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
}
|
|
||||||
|
|
||||||
it 'updates the annotations' do
|
|
||||||
Timecop.travel(now + 1.hour)
|
|
||||||
expect(instructeur.followed_dossiers.with_notifications).to eq([])
|
|
||||||
expect(another_instructeur.followed_dossiers.with_notifications).to eq([dossier.reload])
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "without new values for champs_private" do
|
|
||||||
let(:params) do
|
|
||||||
{
|
|
||||||
procedure_id: procedure.id,
|
|
||||||
dossier_id: dossier.id,
|
|
||||||
dossier: {
|
|
||||||
champs_private_attributes: {},
|
|
||||||
champs_public_attributes: {
|
|
||||||
'0': {
|
|
||||||
id: champ_multiple_drop_down_list.id,
|
|
||||||
value: ['', 'val1', 'val2']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it {
|
|
||||||
expect(dossier.reload.last_champ_private_updated_at).to eq(nil)
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#telecharger_pjs" do
|
describe "#telecharger_pjs" do
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
describe Migrations::BatchUpdatePaysValuesJob, type: :job do
|
describe Migrations::BatchUpdatePaysValuesJob, type: :job do
|
||||||
before do
|
|
||||||
pays_champ.save(validate: false)
|
|
||||||
end
|
|
||||||
|
|
||||||
subject { described_class.perform_now([pays_champ.id]) }
|
subject { described_class.perform_now([pays_champ.id]) }
|
||||||
|
|
||||||
context "the value is correct" do
|
context "the value is correct" do
|
||||||
let(:pays_champ) { build(:champ_pays, value: 'France', external_id: 'FR') }
|
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'France', external_id: 'FR') } }
|
||||||
|
|
||||||
it 'does not change it' do
|
it 'does not change it' do
|
||||||
subject
|
subject
|
||||||
|
@ -16,7 +12,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "the value is incorrect" do
|
context "the value is incorrect" do
|
||||||
let(:pays_champ) { build(:champ_pays, value: 'Incorrect') }
|
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Incorrect') } }
|
||||||
|
|
||||||
it 'updates value to nil' do
|
it 'updates value to nil' do
|
||||||
subject
|
subject
|
||||||
|
@ -26,7 +22,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "the value is easily cleanable" do
|
context "the value is easily cleanable" do
|
||||||
let(:pays_champ) { build(:champ_pays, value: 'Vietnam') }
|
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Vietnam') } }
|
||||||
|
|
||||||
it 'cleans the value' do
|
it 'cleans the value' do
|
||||||
subject
|
subject
|
||||||
|
@ -36,7 +32,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
|
||||||
end
|
end
|
||||||
|
|
||||||
context "the value is hard to clean" do
|
context "the value is hard to clean" do
|
||||||
let(:pays_champ) { build(:champ_pays, value: 'CHRISTMAS (ILE)') }
|
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'CHRISTMAS (ILE)') } }
|
||||||
|
|
||||||
it 'cleans the value' do
|
it 'cleans the value' do
|
||||||
subject
|
subject
|
||||||
|
|
|
@ -1,43 +1,54 @@
|
||||||
describe Champs::DecimalNumberChamp do
|
describe Champs::DecimalNumberChamp do
|
||||||
subject { build(:champ_decimal_number, value: value).tap(&:valid?) }
|
let(:champ) { build(:champ_decimal_number, value:) }
|
||||||
|
subject { champ.validate(:champs_public_value) }
|
||||||
|
|
||||||
describe '#valid?' do
|
describe 'validation' do
|
||||||
context 'when the value is integer number' do
|
context 'when the value is integer number' do
|
||||||
let(:value) { 2 }
|
let(:value) { 2 }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is decimal number' do
|
context 'when the value is decimal number' do
|
||||||
let(:value) { 2.6 }
|
let(:value) { 2.6 }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is not a number' do
|
context 'when the value is not a number' do
|
||||||
let(:value) { 'toto' }
|
let(:value) { 'toto' }
|
||||||
|
|
||||||
it { is_expected.to_not be_valid }
|
it 'is not valid and contains expected error' do
|
||||||
it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit comprendre maximum 3 chiffres après la virgule", "« #{subject.libelle} » n'est pas un nombre"]) }
|
expect(subject).to be_falsey
|
||||||
|
expect(champ.errors[:value]).to eq(["« #{champ.libelle} » doit comprendre maximum 3 chiffres après la virgule", "« #{champ.libelle} » n'est pas un nombre"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value has too many decimal' do
|
context 'when the value has too many decimal' do
|
||||||
let(:value) { '2.6666' }
|
let(:value) { '2.6666' }
|
||||||
|
|
||||||
it { is_expected.to_not be_valid }
|
it 'is not valid and contains expected error' do
|
||||||
it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit comprendre maximum 3 chiffres après la virgule"]) }
|
expect(subject).to be_falsey
|
||||||
|
expect(champ.errors[:value]).to eq(["« #{champ.libelle} » doit comprendre maximum 3 chiffres après la virgule"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is blank' do
|
context 'when the value is blank' do
|
||||||
let(:value) { '' }
|
let(:value) { '' }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is nil' do
|
context 'when the value is nil' do
|
||||||
let(:value) { nil }
|
let(:value) { nil }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the champ is private, value is invalid, but validation is public' do
|
||||||
|
let(:champ) { build(:champ_decimal_number, :private, value:) }
|
||||||
|
let(:value) { '2.6666' }
|
||||||
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,37 +1,42 @@
|
||||||
describe Champs::IntegerNumberChamp do
|
describe Champs::IntegerNumberChamp do
|
||||||
subject { build(:champ_integer_number, value: value).tap(&:valid?) }
|
let(:champ) { build(:champ_integer_number, value:) }
|
||||||
|
subject { champ.validate(:champs_public_value) }
|
||||||
|
|
||||||
describe '#valid?' do
|
describe '#valid?' do
|
||||||
context 'when the value is integer number' do
|
context 'when the value is integer number' do
|
||||||
let(:value) { 2 }
|
let(:value) { 2 }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is decimal number' do
|
context 'when the value is decimal number' do
|
||||||
let(:value) { 2.6 }
|
let(:value) { 2.6 }
|
||||||
|
|
||||||
it { is_expected.to_not be_valid }
|
it 'is not valid and contains errors' do
|
||||||
it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit être un nombre entier (sans chiffres après la virgule)"]) }
|
is_expected.to be_falsey
|
||||||
|
expect(champ.errors[:value]).to eq(["« #{champ.libelle} » doit être un nombre entier (sans chiffres après la virgule)"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is not a number' do
|
context 'when the value is not a number' do
|
||||||
let(:value) { 'toto' }
|
let(:value) { 'toto' }
|
||||||
|
|
||||||
it { is_expected.to_not be_valid }
|
it 'is not valid and contains errors' do
|
||||||
it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit être un nombre entier (sans chiffres après la virgule)"]) }
|
is_expected.to be_falsey
|
||||||
|
expect(champ.errors[:value]).to eq(["« #{champ.libelle} » doit être un nombre entier (sans chiffres après la virgule)"])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is blank' do
|
context 'when the value is blank' do
|
||||||
let(:value) { '' }
|
let(:value) { '' }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the value is nil' do
|
context 'when the value is nil' do
|
||||||
let(:value) { nil }
|
let(:value) { nil }
|
||||||
|
|
||||||
it { is_expected.to be_valid }
|
it { is_expected.to be_truthy }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,44 +1,45 @@
|
||||||
describe Champs::PhoneChamp do
|
describe Champs::PhoneChamp do
|
||||||
let(:phone_champ) { build(:champ_phone) }
|
let(:champ) { build(:champ_phone) }
|
||||||
|
# subject { champ }
|
||||||
|
|
||||||
describe '#valid?' do
|
describe '#validate' do
|
||||||
it do
|
it do
|
||||||
expect(champ_with_value(nil)).to be_valid
|
expect(champ_with_value(nil).validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0123456789 0123456789")).to_not be_valid
|
expect(champ_with_value("0123456789 0123456789").validate(:champs_public_value)).to_not be_truthy
|
||||||
expect(champ_with_value("01.23.45.67.89 01.23.45.67.89")).to_not be_valid
|
expect(champ_with_value("01.23.45.67.89 01.23.45.67.89").validate(:champs_public_value)).to_not be_truthy
|
||||||
expect(champ_with_value("3646")).to be_valid
|
expect(champ_with_value("3646").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0123456789")).to be_valid
|
expect(champ_with_value("0123456789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("01.23.45.67.89")).to be_valid
|
expect(champ_with_value("01.23.45.67.89").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0123 45.67.89")).to be_valid
|
expect(champ_with_value("0123 45.67.89").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0033 123-456-789")).to be_valid
|
expect(champ_with_value("0033 123-456-789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0033 123-456-789")).to be_valid
|
expect(champ_with_value("0033 123-456-789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0033(0)123456789")).to be_valid
|
expect(champ_with_value("0033(0)123456789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33-1.23.45.67.89")).to be_valid
|
expect(champ_with_value("+33-1.23.45.67.89").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33 - 123 456 789")).to be_valid
|
expect(champ_with_value("+33 - 123 456 789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33(0) 123 456 789")).to be_valid
|
expect(champ_with_value("+33(0) 123 456 789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33 (0)123 45 67 89")).to be_valid
|
expect(champ_with_value("+33 (0)123 45 67 89").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33 (0)1 2345-6789")).to be_valid
|
expect(champ_with_value("+33 (0)1 2345-6789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+33(0) - 123456789")).to be_valid
|
expect(champ_with_value("+33(0) - 123456789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+1(0) - 123456789")).to be_valid
|
expect(champ_with_value("+1(0) - 123456789").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+49 2109 87654321")).to be_valid
|
expect(champ_with_value("+49 2109 87654321").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("012345678")).to be_valid
|
expect(champ_with_value("012345678").validate(:champs_public_value)).to be_truthy
|
||||||
# DROM numbers should be valid
|
# DROM numbers should be valid
|
||||||
expect(champ_with_value("06 96 04 78 07")).to be_valid
|
expect(champ_with_value("06 96 04 78 07").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("05 94 22 31 31")).to be_valid
|
expect(champ_with_value("05 94 22 31 31").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("+594 5 94 22 31 31")).to be_valid
|
expect(champ_with_value("+594 5 94 22 31 31").validate(:champs_public_value)).to be_truthy
|
||||||
# polynesian numbers should not return errors in any way
|
# polynesian numbers should not return errors in any way
|
||||||
## landline numbers start with 40 or 45
|
## landline numbers start with 40 or 45
|
||||||
expect(champ_with_value("45187272")).to be_valid
|
expect(champ_with_value("45187272").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("40 473 500")).to be_valid
|
expect(champ_with_value("40 473 500").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("40473500")).to be_valid
|
expect(champ_with_value("40473500").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("45473500")).to be_valid
|
expect(champ_with_value("45473500").validate(:champs_public_value)).to be_truthy
|
||||||
## +689 is the international indicator
|
## +689 is the international indicator
|
||||||
expect(champ_with_value("+689 45473500")).to be_valid
|
expect(champ_with_value("+689 45473500").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("0145473500")).to be_valid
|
expect(champ_with_value("0145473500").validate(:champs_public_value)).to be_truthy
|
||||||
## polynesian mobile numbers start with 87, 88, 89
|
## polynesian mobile numbers start with 87, 88, 89
|
||||||
expect(champ_with_value("87473500")).to be_valid
|
expect(champ_with_value("87473500").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("88473500")).to be_valid
|
expect(champ_with_value("88473500").validate(:champs_public_value)).to be_truthy
|
||||||
expect(champ_with_value("89473500")).to be_valid
|
expect(champ_with_value("89473500").validate(:champs_public_value)).to be_truthy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,6 +62,6 @@ describe Champs::PhoneChamp do
|
||||||
end
|
end
|
||||||
|
|
||||||
def champ_with_value(number)
|
def champ_with_value(number)
|
||||||
phone_champ.tap { |c| c.value = number }
|
champ.tap { |c| c.value = number }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
describe Champs::EngagementJuridiqueChamp do
|
describe Champs::EngagementJuridiqueChamp do
|
||||||
describe 'validation' do
|
describe 'validation' do
|
||||||
let(:champ) { build(:champ_engagement_juridique, value: value) }
|
let(:champ) { build(:champ_engagement_juridique, value: value) }
|
||||||
subject { champ.valid? }
|
subject { champ.validate(:champs_public_value) }
|
||||||
|
|
||||||
context 'with [A-Z]' do
|
context 'with [A-Z]' do
|
||||||
let(:value) { "ABC" }
|
let(:value) { "ABC" }
|
||||||
|
|
Loading…
Reference in a new issue