Как исправить ошибку пересчета количества серийных номеров при удалении строк из табличной части в 1С 8.2

Программист Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки на платформе 1С:Предприятие 8.2 с использованием обычных форм программисты часто сталкиваются с задачей контроля количества вводимых данных. Типичный сценарий: при сканировании товара необходимо ввести строго определенное количество серийных номеров. Однако возникает проблема — если пользователь ошибочно ввел номер, а затем удалил строку стандартными средствами (нажав на «крестик» или клавишу Del), система продолжает считать, что лимит исчерпан, и выдает ошибку: «Серийных номеров введено больше...».

В данной статье мы подробно разберем причины возникновения этой ситуации и разработаем механизмы корректного пересчета данных при изменении состава табличной части.

Анализ причины возникновения ошибки

Проанализируем ситуацию: почему визуальное удаление строки не приводит к обновлению логики программы? В обычных формах 1С работа с табличными полями строится на событиях. Если логика проверки количества завязана на переменную-счетчик, которая инкрементируется (увеличивается) только в момент добавления строки, то при удалении строки этот счетчик остается неизменным. Система «помнит» старое значение, так как событие удаления никак не задействовано в коде.

Разберем основные технические причины рассинхронизации:

  1. Использование локальных переменных вместо метода Количество(). Программист хранит текущее число введенных номеров в переменной модуля формы, обновляя её только при нажатии кнопки «Ввод номера».
  2. Отсутствие обработчиков событий удаления. Стандартные кнопки командной панели (удаление строки) работают на уровне платформы. Если для табличного поля не прописана процедура ПриУдалении, программная логика контроля просто не узнает о том, что данных стало меньше.
  3. Кэширование данных. В некоторых случаях итоги по таблице рассчитываются один раз при открытии или добавлении, но не актуализируются при интерактивном взаимодействии пользователя с формой.

Решение №1: Использование обработчика события ПриИзменении

Рассмотрим наиболее надежный и универсальный способ решения проблемы. Вместо того чтобы пытаться поймать каждое отдельное действие (добавление, копирование, удаление), мы обратимся к событию табличной части ПриИзменении. Это событие срабатывает при любом изменении состава или данных строк.

Посмотрим на пример реализации кода, который будет вызываться автоматически:


Процедура СерийныеНомераПриИзменении(Элемент)
    // Пересчитываем фактическое количество строк в таблице
    ФактическоеКоличество = СерийныеНомера.Количество();
    
    // Обновляем отображение или внутренний счетчик
    ЭлементыФормы.НадписьКоличество.Заголовок = "Введено номеров: " + Строка(ФактическоеКоличество);
    
    // Выполняем проверку лимита
    Если ФактическоеКоличество > НужноВвести Тогда
        Сообщить("Внимание: количество серийных номеров превышает количество товара!");
    КонецЕсли;
КонецПроцедуры

Преимущество этого метода: нам не нужно беспокоиться о том, каким именно способом была удалена строка — через контекстное меню, горячие клавиши или программно. Любое изменение состава таблицы вызовет этот код.

Решение №2: Настройка событий ПередУдалением и ПриУдалении

Если логика работы требует выполнения специфических действий именно в момент удаления (например, очистка связанных данных в других таблицах или регистрах), нам следует рассмотреть использование специализированных событий табличного поля. Разберем по шагам, как это работает.

Событие ПередУдалением позволяет остановить процесс, если удаление недопустимо. Событие ПриУдалении срабатывает, когда строка уже исключена из коллекции.


Процедура СерийныеНомераПередУдалением(Элемент, Отказ)
    // Пример: запретим удаление, если документ уже проведен
    Если Ссылка.Проведен Тогда
        Отказ = Истина;
        Сообщить("Нельзя удалять номера в проведенном документе!");
    КонецЕсли;
КонецПроцедуры

Процедура СерийныеНомераПриУдалении(Элемент)
    // Вызываем общую функцию обновления итогов
    ОбновитьСчетчикСерийныхНомеров();
КонецПроцедуры

Проанализируем ситуацию, описанную в сообщениях форума: пользователь нажимает на «крестик». Это действие гарантированно вызывает ПриУдалении. Если в этой процедуре прописать принудительный пересчет, ошибка «Серийных номеров введено больше» исчезнет, так как при следующем вводе система увидит актуальное (уменьшенное) количество строк.

Решение №3: Отказ от хранения счетчика в переменной

Часто программисты создают переменную типа ТекущееКоличествоСН в модуле формы. Это «плохая практика» (антипаттерн) в 1С. Выясним причину: переменная живет своей жизнью, а табличная часть — своей. Чтобы избежать рассинхронизации, всегда обращайтесь напрямую к объекту коллекции.

Вместо проверки:


// Плохой код
Если ТекущийСчетчик > МаксКоличество Тогда ...

Используйте прямую проверку по табличной части:


// Хороший код
Если Объект.СерийныеНомера.Количество() > Объект.Товары.Итог("Количество") Тогда
    Предупреждение("Превышено допустимое количество серийных номеров!");
КонецЕсли;

Метод Количество() всегда возвращает точное число строк, существующих в памяти в данный момент, независимо от того, как они туда попали или как были удалены.

Связь между таблицами «Товары» и «Серийные номера»

Рассмотрим ситуацию, когда серийные номера привязаны к конкретной строке товара (например, через КлючСвязи). Если вы удаляете товар из основной таблицы, его серийные номера во второй таблице часто остаются «сиротами», если не прописан механизм их очистки. Это тоже может приводить к ошибкам переполнения.

Для корректной работы реализуем следующий алгоритм в обработчике удаления строки товара:

  1. Получаем КлючСвязи удаляемой строки товара.
  2. Находим все строки в таблице серийных номеров с таким же ключом.
  3. Программно удаляем их в цикле.
  4. Обновляем визуальное состояние формы.

Процедура ТоварыПриУдалении(Элемент)
    ТекущиеДанные = ЭлементыФормы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Поиск и удаление подчиненных серийных номеров
    МассивСтрокДляУдаления = СерийныеНомера.НайтиСтроки(Новый Структура("КлючСвязи", ТекущиеДанные.КлючСвязи));
    Для Каждого СтрокаСН Из МассивСтрокДляУдаления Цикл
        СерийныеНомера.Удалить(СтрокаСН);
    КонецЦикла;
КонецПроцедуры

Заключение

Мы выяснили, что ошибка «Серийных номеров введено больше» в 1С 8.2 на обычных формах чаще всего вызвана тем, что алгоритм проверки полагается на статические данные или переменные, которые не обновляются при интерактивном удалении строк пользователем.

Подведем итог: для исправления ошибки необходимо использовать событие ПриИзменении табличной части или комбинацию событий ПриУдалении и ПослеДобавления. Самым надежным способом является динамический подсчет строк методом Количество() непосредственно в момент выполнения проверки, без использования промежуточных переменных-счетчиков.

← На главную