когда нечего делать, а творческая душа требует реализации и хочется что-то сделать или написать, то я пишу сюда или делаю что-то на этом сайте. Кому интересна web-разработка, wordpress и то что рядом с этим, то заходите на мой сайт и читайте всякое...
Валидация данных юридического лица. Formik, Yup, React, TypeScript
Йо-йо! Очень часто приходиться валидировать разные формы. Вот и мне недавно пришлось создать форму регистрации поставщика. У такой формы множество полей и у каждого поля есть свои правила валидации. В этой статье я расскажу как «победил» такую форму, какие сложности я встретил и поделюсь тонкостями валидации данных юридических лиц.
Появилась библиотека валидации данных юр. лиц. Переходите по ссылке
TL;DR;
// Устанавливай
npm i @utkonos/entrepreneur
// Читай документацию
https://github.com/utkonos-ru/utk-entrepreneur
Самая первая сложность — это валидация множества полей. Часто можно просто проверить пару поля и выдать ошибку или дать возможность отправить форму. Но в случае с формой данных юр. лица нужно проверить множество полей и если не иметь системы то код становиться огромным и не читаемым.
Вторая сложность — большая вероятность ошибки при вводе данных. Есть такие поля как ИНН, КПП, расчётный счёт и т.д. Они представляют из себя длинную последовательность цифр. Есть большая вероятность ошибки.
Третья сложность зависимость данных друг от друга. Такая сложность встретилась при проверке расчётного и корреспондентского счёта. Их правильность зависит от БИК.
Вероятность ошибки при вводе данных юр. лица исключается с помощью вычисления контрольных сумм. Дело в том, что есть специальные формулы, которые нужны для создания правильного, например, ИНН. И есть обратные формулы вычисления контрольных сумм в которых у каждого числа есть вес и сумма весов после преобразования должна быть равна какому-то значению.
Контрольные суммы. Валидация
Когда я писал свой код я нашёл несколько полезных ссылок, перейдя на которые вы сможете найти некоторые функции вычисления контрольных сумм на разных языках программирования:
На всех этих ссылках я не нашёл полного списка функций, которые мне были нужны (или некоторые мне нужно было разделить) и я написал свои версии. Мои версии на TypeScript, но их легко переделать в JavaScript убрав типы.
Кроме самих функций мне нужен интерфейс, который делает следующие задачи: Принимает объект с данными, проверяет правильность ввода данных, выводит текст ошибки, в зависимости от типа ошибки, возвращает валидны ли данные в объекте.
C такой задачей справляется библиотека yup. Yup умеет проверять и преобразовавать значения форм или переданных значений. В этой статье будет рассказано про проверку переданных значений.
Давайте рассмотрим пример валидации ИНН в составе объекта данных. У нас уже есть функция isINNIndividual (для валидации ИНН ИП). Давайте создадим схему валидации в Yup:
import * as yup from 'yup'
export const validShape = yup.object().shape({
...
inn: yup
.number()
.test('innValid', 'Неверный ИНН', value => isINNIndividual(value))
.required(),
....
})
Давайте разберём строку с операциями валидации ИНН.
inn: yup
.number() // Проверяет как число, преобразует в число
// Метод test принимает некое название теста, описание ошибки и функцию, которая возвращает true или false в зависимости от переданного значения
.test('innValid', 'Неверный ИНН', value => isINNIndividual(value))
.required(), // Поле обязательное
Передавая в нашу схему объект нам будут возвращаться различные ошибки (если они будут). Но есть небольшая проблема — yup возвращает нам данные в не очень удобном виде. Хотелось бы иметь удобный интерфейс для работы с ошибками… и такой есть.
Создание форм с помощью Formik c валидацией через Yup
Что такое формик? Это либа, которая помогает нам работать с формами, валидацией данных, изменения значений формы. И Formik отлично подходит для работы с Yup.
Будьте внимательны в функции isINNIndividual мы ожидаем на входе число и правило у нас первое yup.number(), а в checkOKPO мы ожидаем строку и правило там .string().
Прошу заметить, что в моём примере Input — это компонент, который просто добавляет красивости на UI и выводит ошибки. Вы можете сделать такой самостоятельно.
В данном примере есть функция handleChange, которая приходит к нам из Formik. У неё есть особенности: на вход она принимает событие и необязательный параметр — детей формы, у изменяемого поля обязательно должен присутствовать атрибут name равный ключу объекта с данными переданными в initialValues.
Это бы простой пример для типичного случая, но есть специфический случай — валидность одного поля зависит от другого как в случае с БИК, рассчётныйм и корр. счетами. В Fromik, не будет преобразований, но вот в Yup…
Yup, методы, декларирование типов для методов в Yup
В этом разделе будут рассмотрены сразу несколько моментов: валидация данных в зависимости от других полей, декларирование методов в Yup c TypeScript и использование таких методов.
И так.. начнём с самого начала. Представим, что у нас есть следующая схема валидации:
validationShapeEntrepreneur = yup.object().shape({
bik: yup
.string()
.test('bikwe', 'bikwe', value => checkBIK(value)) // Валидация БИК
.required(),
accountNumber: yup
.string()
.checkPaymentMethod(yup.ref('bik')) // Метод, который мы создадим и предадим данный из БИК
.required(),
correspAccountNum: yup
.string()
.checkCorrespondentMethod(yup.ref('bik')) // Метод, который мы создадим и предадим данный из БИК
.required()
})
Нам нужно создать метод, который будет проверять расчётный счёт и корреспондентский счёт. Давайте создадим их:
function checkPayment(this, ref, msg) {
return this.test({
name: 'checkPaymentMethod',
exclusive: false,
message: msg || 'accountNumber', // Сообщение об ошибке
params: { reference: ref.path},
test: function(value){
return checkPaymetAccount(value, this.resolve(ref)) // Функция валидации
}
})
}
function checkCorrespondent(this, ref, msg) {
return this.test({
name: 'correspAccountNum',
exclusive: false,
message: msg || 'correspAccountNum', // Сообщение об ошибке
params: { reference: ref.path},
test: function(value){
return checkCorrespondentAccount(value, this.resolve(ref)) // Функция валидации
}
})
}
yup.addMethod(yup.string, 'checkPaymentMethod', checkPayment) // Добавление метода к YUP
yup.addMethod(yup.string, 'checkCorrespondentMethod', checkCorrespondent) // Добавление метода к YUP
В функции валидации передаётся 2 значения: значение поля (например, расчётного счёта) и значение другого поля.
Добавление методов к Yup в TypeScript
В простом JavaScript будет работать и так, но не в TypeScript. Для него нужно сделать некоторые изменений:
Т.к. у нас функции валидации ожидают строку то для интерфейса StringShema мы добавляем наши методы. Если бы мы ожидали число или другой тип данных то нам нужно было бы объявить методы для соответствующего интерфейса, например NumberSchema. Из названия были у нас в
yup.addMethod(yup.string, 'checkPaymentMethod', checkPayment) // второй параметр
Я давно хочу развить видеоверсию, но пока этого не получается из-за нехватки ресурсов. Сейчас я собираю деньги на новый компьютер и микрофон. Поддержи xaklant и ты увидишь полезные видео быстрее.