В процессе разработки в системе 1С (на примере конфигурации «Далион») часто возникает задача контроля данных при записи документа. Одной из типичных ситуаций является проверка соответствия фактически собранного товара («КоличествоФакт») запланированному объему («Количество»). Если эти значения не совпадают, система должна проинформировать об этом пользователя.
В этой статье мы разберем, почему стандартные подходы начинающих программистов могут работать некорректно, проанализируем различные способы решения задачи и выясним, как сделать проверку максимально эффективной и быстрой.
Рассмотрим ситуацию, когда разработчик пытается получить данные через два независимых запроса и сравнить их результаты. Проблема заключается в том, что результат выполнения метода Выполнить().Выбрать() возвращает объект ВыборкаИзРезультатаЗапроса, а не конкретное числовое значение. Сравнение двух объектов выборок (даже если данные внутри них одинаковые) всегда будет давать результат «Истина» или «Ложь» в зависимости от ссылочной идентичности самих объектов, а не их содержимого.
Кроме того, выполнение запроса ко всей таблице документа без фильтрации по конкретной ссылке приведет к тому, что система будет анализировать строки всех накладных, существующих в базе данных, что недопустимо с точки зрения производительности и логики.
Наиболее правильным способом проверки через запрос является использование одного запроса с условием расхождения прямо в тексте SQL-запроса. Это позволяет переложить логику сравнения на сторону сервера базы данных. Проанализируем пример кода:
Процедура ПриЗаписи(Отказ)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РасходнаяНакладнаяТовары.НомерСтроки КАК НомерСтроки
|ИЗ
| Документ.РасходнаяНакладная.Товары КАК РасходнаяНакладнаяТовары
|ГДЕ
| РасходнаяНакладнаяТовары.Ссылка = &Ссылка
| И ЕСТЬNULL(РасходнаяНакладнаяТовары.Количество, 0) <> ЕСТЬNULL(РасходнаяНакладнаяТовары.КоличествоФакт, 0)";
Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Сообщить("Обратите внимание, документ собран с расхождением!");
КонецЕсли;
КонецПроцедуры
Почему это решение лучше:
&Ссылка, чтобы проверять данные только текущего документа.Пустой() = Истина).ЕСТЬNULL гарантирует, что если одна из колонок не заполнена, система корректно сравнит её как ноль, не вызывая ошибок исполнения.Если проверка происходит в модуле объекта (например, в процедуре ПередЗаписью или ПриЗаписи), данные табличной части уже загружены в оперативную память. В этом случае обращение к базе данных через запрос может быть избыточным. Рассмотрим, как реализовать проверку через перебор строк коллекции Товары.
Проанализируем следующий алгоритм:
Для Каждого СтрокаТЧ Из Товары Цикл
Если СтрокаТЧ.Количество <> СтрокаТЧ.КоличествоФакт Тогда
ТекстСообщения = СтрШаблон("В строке №%1 обнаружено расхождение: План (%2), Факт (%3)",
СтрокаТЧ.НомерСтроки, СтрокаТЧ.Количество, СтрокаТЧ.КоличествоФакт);
Сообщить(ТекстСообщения);
КонецЕсли;
КонецЦикла;
Этот метод позволяет не просто вывести общее предупреждение, но и указать пользователю на конкретные строки, где допущена ошибка. Для работы в управляемых формах (современный «Далион») рекомендуется использовать объект СообщениеПользователю, чтобы привязать текст к конкретному полю на экране.
В программных продуктах линейки «Далион» работа с расхождениями часто завязана на использовании ТСД (терминалов сбора данных). Выясним несколько нюансов, которые помогут сделать решение более профессиональным:
1. Место проверки: Если расхождение является критическим, логичнее размещать код в процедуре ОбработкаПроведения. Это позволит запретить проведение документа, если данные не верны, установив параметр Отказ = Истина.
2. Визуальное выделение: Вместо простого Сообщить(), попробуем использовать метод, который подсветит ошибку в интерфейсе:
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Количество не совпадает с фактом!";
Сообщение.Поле = "Товары[" + ИндексСтроки + "].КоличествоФакт";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
3. Статусы документа: Проверьте, нет ли в вашей версии «Далиона» встроенного статуса «Проверен» или «Собран». Иногда логичнее выводить предупреждение только при попытке установить финальный статус документа, разрешая промежуточные сохранения с расхождениями.
Мы рассмотрели несколько подходов к решению задачи. Для простых проверок «на лету» лучше всего подходит прямой перебор табличной части в оперативной памяти. Если же необходимо проверить данные в массовом порядке или в сложном отчете — используйте оптимизированные запросы с обязательной фильтрацией по ссылке и обработкой NULL-значений.
Помните, что качественный программный код не только находит ошибку, но и помогает пользователю её исправить, предоставляя детализированную информацию о месте и причине расхождения.