From d01762a069d20e6fa70e54854f1be6e070c4b9de Mon Sep 17 00:00:00 2001 From: Christian Lautier <15379878+maatinito@users.noreply.github.com> Date: Thu, 14 Sep 2023 11:24:29 -1000 Subject: [PATCH] Fix DN number validation on submit, closes #5 --- app/controllers/users/dossiers_controller.rb | 14 ++++---- .../controllers/numero_dn_controller.ts | 2 ++ app/models/champs/numero_dn_champ.rb | 32 ++++++------------- app/models/dossier.rb | 4 +-- app/validators/numero_dn_validator.rb | 9 +++--- .../shared/champs/numero_dn/_status.html.haml | 8 ++--- config/locales/en.yml | 24 +++++++++++++- config/locales/fr.yml | 17 ++++++++-- config/locales/models/champs/champs.en.yml | 10 ------ config/locales/models/champs/champs.fr.yml | 10 ------ 10 files changed, 67 insertions(+), 63 deletions(-) delete mode 100644 config/locales/models/champs/champs.en.yml delete mode 100644 config/locales/models/champs/champs.fr.yml diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index dce5670a70e..28eff9d04a2 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -571,22 +571,24 @@ def format_errors(errors:) errors.map do |active_model_error| case active_model_error.class.name when "ActiveModel::NestedError" - append_anchor_link(active_model_error.full_message, active_model_error.inner_error.base) + append_anchor_link(active_model_error.inner_error) when "ActiveModel::Error" - append_anchor_link(active_model_error.full_message, active_model_error.base) + append_anchor_link(active_model_error) else # "String" active_model_error end end end - def append_anchor_link(str_error, model) - return str_error.full_message if !model.is_a?(Champ) + def append_anchor_link(error) + model = error.base + str_error = error.full_message + return str_error if !model.is_a?(Champ) + # attribute = error.attribute != :value ? ":" + error.attribute.to_s.gsub('_',' ') : nil route_helper = @dossier.editing_fork? ? :modifier_dossier_path : :brouillon_dossier_path - [ - "Le champ « #{model.libelle.truncate(200)} » #{str_error}", + t('views.users.dossiers.label_champ', champ: model.libelle.truncate(200), message: str_error), helpers.link_to(t('views.users.dossiers.fix_champ'), public_send(route_helper, anchor: model.labelledby_id), class: 'error-anchor') ].join(", ") rescue # case of invalid type de champ on champ diff --git a/app/javascript/controllers/numero_dn_controller.ts b/app/javascript/controllers/numero_dn_controller.ts index 6fd64912fd6..3948180034d 100644 --- a/app/javascript/controllers/numero_dn_controller.ts +++ b/app/javascript/controllers/numero_dn_controller.ts @@ -16,7 +16,9 @@ export class NumeroDnController extends ApplicationController { connect(): void { this.onTarget(this.dnTarget, 'input', () => this.debounce(this.load, 200)); this.onTarget(this.ddnTarget, 'input', () => this.debounce(this.load, 200)); + this.load(); } + private load(): void { if (!this.dnTarget?.validity?.patternMismatch) { if (this.ddnTarget.checkValidity()) { diff --git a/app/models/champs/numero_dn_champ.rb b/app/models/champs/numero_dn_champ.rb index 0ca90e26341..901d8453bbb 100644 --- a/app/models/champs/numero_dn_champ.rb +++ b/app/models/champs/numero_dn_champ.rb @@ -21,33 +21,23 @@ # type_de_champ_id :integer # class Champs::NumeroDnChamp < Champ - validates_with NumeroDnValidator + store_accessor :value_json, :numero_dn, :date_de_naissance - def numero_dn - if value.present? - values[0] - else - '' - end - end - - def date_de_naissance - tab = values - tab.present? ? tab[1] : nil - end + validates_with NumeroDnValidator, if: -> { validation_context != :brouillon } def numero_dn=(value) value = value.to_s.rjust(7, "0") if value.present? - pack_value(value, date_de_naissance) + super(value) end def date_de_naissance=(value) value = begin - Time.zone.parse(value).to_date.iso8601 + Time.zone.parse(value).to_date.iso8601 rescue nil - end + end pack_value(numero_dn, value) + super(value) end def displayed_date_de_naissance @@ -76,20 +66,16 @@ def for_api end def blank? - value.blank? || values.any?(&:blank?) + value.blank? end def search_terms - values + [numero_dn, date_de_naissance] end private - def values - value.present? ? JSON.parse(value) : nil - end - def pack_value(numero_dn, date_de_naissance) - self.value = JSON.generate([numero_dn, date_de_naissance]) + self.value = numero_dn.blank? || date_de_naissance.blank? ? nil : JSON.generate([numero_dn, date_de_naissance]) end end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 3beeaa99235..9c57cf417d0 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -94,9 +94,9 @@ class Dossier < ApplicationRecord # We have to remove champs in a particular order - champs with a reference to a parent have to be # removed first, otherwise we get a foreign key constraint error. has_many :champs_to_destroy, -> { order(:parent_id) }, class_name: 'Champ', inverse_of: false, dependent: :destroy - has_many :champs_public, -> { root.public_ordered }, class_name: 'Champ', inverse_of: false + has_many :champs_public, -> { root.public_ordered }, class_name: 'Champ', inverse_of: false, validate: false has_many :champs_private, -> { root.private_ordered }, class_name: 'Champ', inverse_of: false - has_many :champs_public_all, -> { public_only }, class_name: 'Champ', inverse_of: false + has_many :champs_public_all, -> { public_only }, class_name: 'Champ', inverse_of: false, validate: false has_many :champs_private_all, -> { private_only }, class_name: 'Champ', inverse_of: false has_many :prefilled_champs_public, -> { root.public_only.prefilled }, class_name: 'Champ', inverse_of: false diff --git a/app/validators/numero_dn_validator.rb b/app/validators/numero_dn_validator.rb index 29b6a4a5a0b..8524d215a6c 100644 --- a/app/validators/numero_dn_validator.rb +++ b/app/validators/numero_dn_validator.rb @@ -11,13 +11,12 @@ def validate(record) when 'true' # everything is good when 'false' - record.errors[record.type_de_champ.libelle] << "La date de naissance ne correspond pas à ce numéro DN." + record.errors.add(:date_de_naissance, :inconsistent_date) else - record.errors[record.type_de_champ.libelle] << "Le numéro de DN est inconnu de la CPS." + record.errors.add(:value, :unknown_dn) end - rescue => e - # if CPS is not accessible, let user continue - Rails.logger.error('Unable to contact CPS:' + e.message) + rescue + record.errors.add(:value, :service_unavailable) end end end diff --git a/app/views/shared/champs/numero_dn/_status.html.haml b/app/views/shared/champs/numero_dn/_status.html.haml index 24356c7b329..06ca8c2bd37 100644 --- a/app/views/shared/champs/numero_dn/_status.html.haml +++ b/app/views/shared/champs/numero_dn/_status.html.haml @@ -1,15 +1,15 @@ - case status - when :bad_dn - = t('messages.numero_dn.bad_dn') + .fr-error-text.mb-4= t('messages.numero_dn.bad_dn') - when :bad_dn_format - = t('messages.numero_dn.bad_dn_format') + .fr-error-text.mb-4= t('messages.numero_dn.bad_dn_format') - when :bad_ddn_format - = t('messages.numero_dn.bad_ddn_format') + .fr-error-text.mb-4= t('messages.numero_dn.bad_ddn_format') - when :bad_ddn - = t('messages.numero_dn.bad_ddn') + .fr-error-text.mb-4= t('messages.numero_dn.bad_ddn') - when :network_error = t('errors.messages.cps_network_error') diff --git a/config/locales/en.yml b/config/locales/en.yml index 05765fe9bc3..820484224e3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -12,6 +12,7 @@ # # To use a different locale, set it with `I18n.locale`: # +# # I18n.locale = :es # # This would use the information in config/locales/es.yml. @@ -401,6 +402,7 @@ en: detail_one: "To complete a procedure, contact your administration and ask for the link to the procedure." detail_two: "This one should look like" fix_champ: "fill in this field" + label_champ: "« %{champ} » field %{message}" archived_dossier: "Your file will be kept %{duree_conservation_dossiers_dans_ds} more months" identite: identity_data: Identity data @@ -530,6 +532,13 @@ en: submit: publish: Publish reopen: Reopen + messages: + numero_dn: + bad_dn_format: DN number must be 6 to 7 characters long. + bad_dn: Unknown DN number. + bad_ddn_format: Fill in the date of birth. + bad_ddn: Date of birth doesn't match the DN number. + good_dn: DN number and date of birth are correct. activerecord: models: user: @@ -617,6 +626,11 @@ en: attributes: value: format: "%{message}" + champ: + attributes: + value: + format: '%{message}' + missing: must be filled "champs/cnaf_champ": attributes: numero_allocataire: @@ -657,12 +671,20 @@ en: not_in_departement_epci_codes: "must be a valid EPCI code of the matching department" value: not_in_departement_epci_names: "must be a valid EPCI name of the matching department" + "champs/numero_dn_champ": + attributes: + date_de_naissance: + format: "%{message}" + inconsistent_date: ", date of birth doesn't match the DN number" + value: + unknown_dn: "has unknown DN number" + service_unavailable: "service unavailable. Please, try again later." "champs/dossier_link_champ": attributes: value: not_integerable: "must be an integer" errors: - format: "Field « %{attribute} » %{message}" + format: "« %{attribute} » attribute %{message}674" messages: dossier_not_found: "The file does not exist or you do not have access to it." # # dossier_map_not_activated: "The file does not have access to the map." diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 95cdcb42ea8..8f844f4053a 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -403,6 +403,7 @@ fr: detail_one: "Pour remplir une démarche, contactez votre administration en lui demandant le lien de la démarche." detail_two: "Celui ci doit ressembler à" fix_champ: "corriger l’erreur" + label_champ: "Le champ « %{champ} » %{message}" archived_dossier: "Votre dossier sera conservé %{duree_conservation_dossiers_dans_ds} mois supplémentaire" identite: identity_data: Données d’identité @@ -625,7 +626,11 @@ fr: attributes: value: format: "%{message}" - + champ: + attributes: + value: + format: '%{message}' + missing: doit être rempli "champs/cnaf_champ": attributes: numero_allocataire: @@ -666,12 +671,20 @@ fr: not_in_departement_epci_codes: "doit être un code d'EPCI du département correspondant" value: not_in_departement_epci_names: "doit être un nom d'EPCI du département correspondant" + "champs/numero_dn_champ": + attributes: + date_de_naissance: + format: "%{message}" + inconsistent_date: ", la date de naissance n'est pas en accord avec le numéro DN" + value: + unknown_dn: "a un numéro DN inconnu" + service_unavailable: "ne peut être vérifié. Réssayez plus tard s'il vous plait." "champs/dossier_link_champ": attributes: value: not_integerable: "doit être un entier" errors: - format: "Le champ « %{attribute} » %{message}" + format: "l'attribut « %{attribute} » %{message}" messages: saml_not_authorized: "Vous n’êtes pas autorisé à accéder à ce service." dossier_not_found: "Le dossier n’existe pas ou vous n’y avez pas accès." diff --git a/config/locales/models/champs/champs.en.yml b/config/locales/models/champs/champs.en.yml deleted file mode 100644 index ead7030628d..00000000000 --- a/config/locales/models/champs/champs.en.yml +++ /dev/null @@ -1,10 +0,0 @@ -fr: - activerecord: - errors: - models: - champ: - attributes: - value: - format: '%{message}' - missing: must be filled - diff --git a/config/locales/models/champs/champs.fr.yml b/config/locales/models/champs/champs.fr.yml deleted file mode 100644 index 090aabf5549..00000000000 --- a/config/locales/models/champs/champs.fr.yml +++ /dev/null @@ -1,10 +0,0 @@ -fr: - activerecord: - errors: - models: - champ: - attributes: - value: - format: '%{message}' - missing: doit être rempli -