/
frekke
/
mostlogistic
Обзор
Документация
Войти
/
frekke
/
mostlogistic
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
lib/validators.rb
173 строки
7 KB
frekke
fixes
31 янв 2026, 04:12
31 янв 2026, 04:12
3908992
Код
Авторство
О чём код?
# frozen_string_literal: true require 'date' module Validators DATE_FORMAT = '%d.%m.%Y' class ValidationResult attr_reader :success, :error, :value def initialize(success:, value: nil, error: nil) @success = success @value = value @error = error end def success? @success end end class << self # Валидация телефона с нормализацией def validate_phone(text) return ValidationResult.new(success: false, error: "❌ Телефон не может быть пустым") if text.nil? || text.strip.empty? # Убираем все лишнее: пробелы, скобки, тире normalized = text.gsub(/[^\d+]/, '') # Обработка разных форматов начала номера if normalized.match?(/^\+7\d{10}$/) # Уже в идеальном формате +79991234567 elsif normalized.match?(/^8\d{10}$/) normalized = normalized.sub(/^8/, '+7') elsif normalized.match?(/^7\d{10}$/) normalized = normalized.sub(/^7/, '+7') else return ValidationResult.new( success: false, error: "❌ Неверный формат телефона.\n💡 Примеры:\n • +79991234567\n • 89991234567" ) end ValidationResult.new(success: true, value: normalized) end # Валидация Telegram-тега def validate_telegram_tag(text) return ValidationResult.new(success: false, error: "❌ Telegram-тег не может быть пустым") if text.nil? || text.strip.empty? # Очищаем от лишних пробелов и лишних @ в начале cleaned = text.strip.gsub(/^@+/, '') # Проверяем формат (от 5 до 32 символов, буквы, цифры, подчёркивания) if cleaned.match?(/^[a-zA-Z0-9_]{5,32}$/) ValidationResult.new(success: true, value: "@#{cleaned}") else ValidationResult.new( success: false, error: "❌ Неверный формат тега.\n💡 Тег должен содержать от 5 до 32 символов (только латиница, цифры и _)." ) end end # Валидация даты def validate_date(text, allow_past: false) return ValidationResult.new(success: false, error: "❌ Дата не может быть пустой") if text.nil? || text.strip.empty? begin parsed_date = Date.strptime(text.strip, DATE_FORMAT) rescue ArgumentError, TypeError return ValidationResult.new( success: false, error: "❌ Неверный формат даты. Используйте: ДД.ММ.ГГГГ (например, 25.12.2025)" ) end unless allow_past if parsed_date < Date.today return ValidationResult.new( success: false, error: "❌ Дата не может быть в прошлом. Сегодня: #{Date.today.strftime(DATE_FORMAT)}" ) end end ValidationResult.new(success: true, value: parsed_date.strftime(DATE_FORMAT)) end # Валидация временного слота def validate_time_slot(text) return ValidationResult.new(success: false, error: "❌ Время не может быть пустым") if text.nil? || text.strip.empty? cleaned = text.strip # Поддержка разных видов тире unless cleaned.match?(/^\d{1,2}:\d{2}\s*[–\-—]\s*\d{1,2}:\d{2}$/) return ValidationResult.new(success: false, error: "❌ Формат времени: ЧЧ:ММ–ЧЧ:ММ") end parts = cleaned.scan(/(\d{1,2}):(\d{2})/) return ValidationResult.new(success: false, error: "❌ Ошибка формата времени") if parts.size != 2 h1, m1 = parts[0].map(&:to_i) h2, m2 = parts[1].map(&:to_i) if h1 > 23 || h2 > 23 || m1 > 59 || m2 > 59 return ValidationResult.new(success: false, error: "❌ Некорректные часы или минуты") end if (h1 * 60 + m1) >= (h2 * 60 + m2) return ValidationResult.new(success: false, error: "❌ Время начала должно быть раньше окончания") end normalized = "#{format('%02d', h1)}:#{format('%02d', m1)}–#{format('%02d', h2)}:#{format('%02d', m2)}" ValidationResult.new(success: true, value: normalized) end def validate_weight(text) return ValidationResult.new(success: false, error: "❌ Вес не может быть пустым") if text.nil? || text.strip.empty? cleaned = text.strip.gsub(',', '.') return ValidationResult.new(success: false, error: "❌ Вес должен быть числом") unless cleaned.match?(/^\d+(\.\d+)?$/) weight = cleaned.to_f return ValidationResult.new(success: false, error: "❌ Вес должен быть больше 0") if weight <= 0 return ValidationResult.new(success: false, error: "❌ Слишком большой вес (макс 25т)") if weight > 25000 value = weight == weight.to_i ? weight.to_i.to_s : weight.to_s ValidationResult.new(success: true, value: value) end def validate_address(text) return ValidationResult.new(success: false, error: "❌ Адрес не может быть пустым") if text.nil? || text.strip.empty? cleaned = text.strip return ValidationResult.new(success: false, error: "❌ Слишком короткий адрес") if cleaned.length < 5 ValidationResult.new(success: true, value: cleaned) end def validate_boxes_pallets(text) return ValidationResult.new(success: false, error: "❌ Поле не может быть пустым") if text.nil? || text.strip.empty? ValidationResult.new(success: true, value: text.strip) end def validate_date_sequence(pickup_date_str, delivery_date_str) return ValidationResult.new(success: true) if pickup_date_str.nil? || delivery_date_str.nil? p_date = Date.strptime(pickup_date_str, DATE_FORMAT) d_date = Date.strptime(delivery_date_str, DATE_FORMAT) if d_date < p_date return ValidationResult.new(success: false, error: "❌ Дата поставки не может быть раньше даты забора") end if (d_date - p_date).to_i > 31 return ValidationResult.new(success: false, error: "⚠️ Интервал между забором и поставкой не может превышать 31 день") end ValidationResult.new(success: true) rescue ArgumentError ValidationResult.new(success: false, error: "❌ Ошибка формата дат при сравнении") end def validate_supplier_name(text) return ValidationResult.new(success: false, error: "❌ Название не может быть пустым") if text.nil? || text.strip.empty? ValidationResult.new(success: true, value: text.strip) end def validate_warehouse(text) return ValidationResult.new(success: false, error: "❌ Склад не может быть пустым") if text.nil? || text.strip.empty? ValidationResult.new(success: true, value: text.strip) end end end