В процессе разработки на платформе 1С:Предприятие 8.2 с использованием обычных форм программисты часто сталкиваются с задачей контроля количества вводимых данных. Типичный сценарий: при сканировании товара необходимо ввести строго определенное количество серийных номеров. Однако возникает проблема — если пользователь ошибочно ввел номер, а затем удалил строку стандартными средствами (нажав на «крестик» или клавишу Del), система продолжает считать, что лимит исчерпан, и выдает ошибку: «Серийных номеров введено больше...».
В данной статье мы подробно разберем причины возникновения этой ситуации и разработаем механизмы корректного пересчета данных при изменении состава табличной части.
Проанализируем ситуацию: почему визуальное удаление строки не приводит к обновлению логики программы? В обычных формах 1С работа с табличными полями строится на событиях. Если логика проверки количества завязана на переменную-счетчик, которая инкрементируется (увеличивается) только в момент добавления строки, то при удалении строки этот счетчик остается неизменным. Система «помнит» старое значение, так как событие удаления никак не задействовано в коде.
Разберем основные технические причины рассинхронизации:
Количество(). Программист хранит текущее число введенных номеров в переменной модуля формы, обновляя её только при нажатии кнопки «Ввод номера».ПриУдалении, программная логика контроля просто не узнает о том, что данных стало меньше.Рассмотрим наиболее надежный и универсальный способ решения проблемы. Вместо того чтобы пытаться поймать каждое отдельное действие (добавление, копирование, удаление), мы обратимся к событию табличной части ПриИзменении. Это событие срабатывает при любом изменении состава или данных строк.
Посмотрим на пример реализации кода, который будет вызываться автоматически:
Процедура СерийныеНомераПриИзменении(Элемент)
// Пересчитываем фактическое количество строк в таблице
ФактическоеКоличество = СерийныеНомера.Количество();
// Обновляем отображение или внутренний счетчик
ЭлементыФормы.НадписьКоличество.Заголовок = "Введено номеров: " + Строка(ФактическоеКоличество);
// Выполняем проверку лимита
Если ФактическоеКоличество > НужноВвести Тогда
Сообщить("Внимание: количество серийных номеров превышает количество товара!");
КонецЕсли;
КонецПроцедуры
Преимущество этого метода: нам не нужно беспокоиться о том, каким именно способом была удалена строка — через контекстное меню, горячие клавиши или программно. Любое изменение состава таблицы вызовет этот код.
Если логика работы требует выполнения специфических действий именно в момент удаления (например, очистка связанных данных в других таблицах или регистрах), нам следует рассмотреть использование специализированных событий табличного поля. Разберем по шагам, как это работает.
Событие ПередУдалением позволяет остановить процесс, если удаление недопустимо. Событие ПриУдалении срабатывает, когда строка уже исключена из коллекции.
Процедура СерийныеНомераПередУдалением(Элемент, Отказ)
// Пример: запретим удаление, если документ уже проведен
Если Ссылка.Проведен Тогда
Отказ = Истина;
Сообщить("Нельзя удалять номера в проведенном документе!");
КонецЕсли;
КонецПроцедуры
Процедура СерийныеНомераПриУдалении(Элемент)
// Вызываем общую функцию обновления итогов
ОбновитьСчетчикСерийныхНомеров();
КонецПроцедуры
Проанализируем ситуацию, описанную в сообщениях форума: пользователь нажимает на «крестик». Это действие гарантированно вызывает ПриУдалении. Если в этой процедуре прописать принудительный пересчет, ошибка «Серийных номеров введено больше» исчезнет, так как при следующем вводе система увидит актуальное (уменьшенное) количество строк.
Часто программисты создают переменную типа ТекущееКоличествоСН в модуле формы. Это «плохая практика» (антипаттерн) в 1С. Выясним причину: переменная живет своей жизнью, а табличная часть — своей. Чтобы избежать рассинхронизации, всегда обращайтесь напрямую к объекту коллекции.
Вместо проверки:
// Плохой код
Если ТекущийСчетчик > МаксКоличество Тогда ...
Используйте прямую проверку по табличной части:
// Хороший код
Если Объект.СерийныеНомера.Количество() > Объект.Товары.Итог("Количество") Тогда
Предупреждение("Превышено допустимое количество серийных номеров!");
КонецЕсли;
Метод Количество() всегда возвращает точное число строк, существующих в памяти в данный момент, независимо от того, как они туда попали или как были удалены.
Рассмотрим ситуацию, когда серийные номера привязаны к конкретной строке товара (например, через КлючСвязи). Если вы удаляете товар из основной таблицы, его серийные номера во второй таблице часто остаются «сиротами», если не прописан механизм их очистки. Это тоже может приводить к ошибкам переполнения.
Для корректной работы реализуем следующий алгоритм в обработчике удаления строки товара:
КлючСвязи удаляемой строки товара.
Процедура ТоварыПриУдалении(Элемент)
ТекущиеДанные = ЭлементыФормы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Поиск и удаление подчиненных серийных номеров
МассивСтрокДляУдаления = СерийныеНомера.НайтиСтроки(Новый Структура("КлючСвязи", ТекущиеДанные.КлючСвязи));
Для Каждого СтрокаСН Из МассивСтрокДляУдаления Цикл
СерийныеНомера.Удалить(СтрокаСН);
КонецЦикла;
КонецПроцедуры
Мы выяснили, что ошибка «Серийных номеров введено больше» в 1С 8.2 на обычных формах чаще всего вызвана тем, что алгоритм проверки полагается на статические данные или переменные, которые не обновляются при интерактивном удалении строк пользователем.
Подведем итог: для исправления ошибки необходимо использовать событие ПриИзменении табличной части или комбинацию событий ПриУдалении и ПослеДобавления. Самым надежным способом является динамический подсчет строк методом Количество() непосредственно в момент выполнения проверки, без использования промежуточных переменных-счетчиков.