Как правильно проверить единицу измерения в табличной части документа на клиенте в 1С:ERP 2.5?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Торговля и дистрибуция
← На главную

При разработке и адаптации функционала в 1С:ERP 2.5 часто возникает необходимость валидации данных, вводимых пользователем. Одной из таких задач является проверка корректности единиц измерения или упаковок, указанных в табличной части документа. Эта задача кажется простой на первый взгляд, но имеет свои нюансы, связанные с клиент-серверным взаимодействием, особенностями хранения данных об упаковках и номенклатуре, а также рекомендованными механизмами проверки в типовых конфигурациях.

В этой статье мы подробно разберем, как эффективно решить эту проблему, используя различные подходы и учитывая специфику платформы 1С:Предприятие.

Особенности работы с единицами измерения и упаковками в 1С:ERP 2.5

Прежде чем перейти к методам проверки, давайте проанализируем, как устроена работа с единицами измерения и упаковками в 1С:ERP 2.5. Это поможет нам лучше понять, почему возникают те или иные сложности и какие данные нам нужно проверять.

  1. Гибкая настройка единиц измерения: В 1С:ERP 2.5 реализован комплексный подход к работе с единицами измерения номенклатуры. Для каждой позиции номенклатуры обязательно указывается Единица хранения — это основная единица, в которой ведется складской учет и хранятся остатки. Дополнительно может быть задана Единица для отчетов, используемая в аналитических отчетах.
  2. Использование упаковок: Функционал упаковок является мощным инструментом для удобного ввода количества товара в документах. Возможность использования упаковок включается функциональной опцией Упаковки номенклатуры. Для каждой упаковки может быть определена тара, что бывает полезно для учета многооборотной тары или специфических логистических процессов. Когда упаковки для позиции не заданы, то в документах отображается просто единица измерения.
  3. Коэффициенты пересчета: Критически важной является корректная настройка коэффициентов пересчета между различными единицами измерения (например, из "ящиков" в "штуки" или из "паллет" в "упаковки"). Неправильно заданные коэффициенты могут привести к серьезным расхождениям в складских остатках, ошибкам при отгрузке, некорректному расчету себестоимости и другим проблемам.
  4. Важность проверки настроек: Мы настоятельно рекомендуем перед началом работы с документами всегда проверять настройки единиц измерения и коэффициентов пересчета в карточке номенклатуры. Это позволит избежать многих проблем и путаницы, связанных с некорректными данными.

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

Решение 1: Проверка данных на сервере

Несмотря на то, что в табличной части формы документа отображается единица измерения, ее происхождение (из реквизита Упаковка или из Номенклатура.ЕдиницаИзмерения) и связанные с ней характеристики часто требуют обращения к серверу для получения актуальных и полных данных. Это особенно актуально, если данные на форме еще не записаны в объект базы данных или если для определения характеристики требуются сложные алгоритмы. Форумное обсуждение подтверждает, что "дергать сервер" часто является необходимым решением для получения таких сведений.

Причины обращения к серверу:

  1. Актуальность данных: Данные на клиенте могут быть неполными или устаревшими. Например, для определения, является ли единица измерения весовой или требует ли она обязательной упаковки, может потребоваться обращение к справочникам и регистрам на сервере.
  2. Сложная логика: Бизнес-логика проверки может быть сложной и требовать доступа к объектам базы данных, которые недоступны на клиенте.
  3. Производительность: Некоторые операции, выполняемые на сервере, могут быть быстрее, если они выполняются там, где находятся данные, минимизируя передачу данных по сети.

Как организовать взаимодействие с сервером:

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

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

Рассмотрим пример того, как мы можем собрать данные и передать их на сервер:


// В модуле формы на клиенте
&НаКлиенте
Процедура ПроверитьЕдиницыИзмеренияТабличнойЧасти()

    МассивДляПроверки = Новый Массив;

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

    РезультатПроверки = ПроверитьДанныеТабличнойЧастиНаСервере(МассивДляПроверки);

    Если РезультатПроверки.ЕстьОшибки Тогда
        // Обработайте ошибки, выведите сообщения пользователю
        Для Каждого Ошибка Из РезультатПроверки.СписокОшибок Цикл
            Сообщить(Ошибка);
        КонецЦикла;
    КонецЕсли;

КонецПроцедуры

// В модуле формы на сервере (без контекста)
&НаСервереБезКонтекста
Функция ПроверитьДанныеТабличнойЧастиНаСервере(МассивДанных)

    Результат = Новый Структура;
    Результат.Вставить("ЕстьОшибки", Ложь);
    Результат.Вставить("СписокОшибок", Новый Массив);

    Для Каждого ДанныеСтроки Из МассивДанных Цикл
        // Получаем полные объекты номенклатуры и упаковки
        НоменклатураОбъект = ДанныеСтроки.Номенклатура.ПолучитьОбъект();
        УпаковкаОбъект = Неопределено;
        Если ЗначениеЗаполнено(ДанныеСтроки.Упаковка) Тогда
            УпаковкаОбъект = ДанныеСтроки.Упаковка.ПолучитьОбъект();
        КонецЕсли;

        // Пример: Проверяем, что для весового товара всегда указана упаковка
        Если НоменклатураОбъект.ВидНоменклатуры.ЕдиницаИзмеренияЯвляетсяВесовой И Не ЗначениеЗаполнено(ДанныеСтроки.Упаковка) Тогда
            Результат.ЕстьОшибки = Истина;
            Результат.СписокОшибок.Добавить("Для номенклатуры " + НоменклатураОбъект.Наименование + " требуется указать упаковку, так как она весовая.");
        КонецЕсли;

        // Пример: Проверяем коэффициент пересчета для упаковки
        Если УпаковкаОбъект <> Неопределено И УпаковкаОбъект.Коэффициент = 0 Тогда
            Результат.ЕстьОшибки = Истина;
            Результат.СписокОшибок.Добавить("Для упаковки " + УпаковкаОбъект.Наименование + " номенклатуры " + НоменклатураОбъект.Наименование + " не задан коэффициент пересчета.");
        КонецЕсли;
        
        // Добавьте здесь вашу специфическую логику проверки
        
    КонецЦикла;

    Возврат Результат;

КонецФункции

Привилегированный режим:

В некоторых случаях для получения значения реквизита объекта на сервере нам может потребоваться привилегированный режим. Для этого используется функция ОбщегоНазначенияУТВызовСервера.ЗначениеРеквизитаОбъектаВПривилегированномРежиме. Она позволяет получить доступ к данным, которые могут быть недоступны в обычном режиме или напрямую с клиента из-за ограничений прав. Если вам нужно прочитать данные, к которым у пользователя нет прямых прав, используйте эту функцию.


// Пример использования привилегированного режима
// На сервере
&НаСервереБезКонтекста
Функция ПолучитьНастройкуНоменклатурыПривилегированно(СсылкаНаНоменклатуру)

    // Предполагаем, что "НастройкаНоменклатуры" - это какой-то реквизит,
    // для чтения которого нужны привилегированные права
    ЗначениеРеквизита = ОбщегоНазначенияУТВызовСервера.ЗначениеРеквизитаОбъектаВПривилегированномРежиме(
        СсылкаНаНоменклатуру,
        "КакойТоРеквизитТребующийПривилегии"
    );
    Возврат ЗначениеРеквизита;

КонецФункции

Решение 2: Использование события "ОбработкаПроверкиЗаполнения"

Одним из наиболее подходящих и рекомендуемых механизмов для реализации комплексных проверок заполнения реквизитов, включая табличные части, является событие ОбработкаПроверкиЗаполнения в модуле объекта документа.

ОбработкаПроверкиЗаполнения (модуль объекта документа):

Это событие вызывается платформой автоматически в следующих случаях:

  1. При интерактивной записи объекта (например, при нажатии кнопок "Записать", "Провести").
  2. При проведении документа.

Важно: Это событие не вызывается при программной записи объекта (например, при загрузке данных через обмены или создании документа в фоновом режиме). Это нужно учитывать при работе с обменами данными или другими автоматическими операциями.

Обработчик этого события получает параметры Отказ (булево, для отмены операции при обнаружении ошибки) и ПроверяемыеРеквизиты (массив имен реквизитов, которые подлежат проверке). Мы можем модифицировать этот массив, добавляя или удаляя реквизиты, а также реализовать собственную логику проверки.

Разберем по шагам, как мы можем использовать это событие для проверки единиц измерения в табличной части:

  1. Откройте модуль объекта вашего документа (например, "РеализацияТоваровУслуг").
  2. Перейдите к обработчику события ОбработкаПроверкиЗаполнения.
  3. Реализуйте цикл по строкам табличной части, внутри которого выполните необходимые проверки.

Посмотрим на пример кода:


// В модуле объекта документа
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    // Вызываем стандартные проверки, если они есть
    // Например, для УТ/ERP это может быть:
    // ОбщегоНазначенияУТ.ПроверитьЗаполнениеКоличества(ЭтотОбъект, ПроверяемыеРеквизиты, Отказ);

    // Проверяем каждую строку табличной части "Товары"
    Для Каждого СтрокаТЧ Из Товары Цикл
        Если СтрокаТЧ.Номенклатура.Пустая() Тогда
            СообщениеОбОшибке = Новый СообщениеПользователю;
            СообщениеОбОшибке.Текст = "В строке " + (СтрокаТЧ.НомерСтроки) + " не заполнена номенклатура!";
            СообщениеОбОшибке.Поле = "Товары[" + (СтрокаТЧ.НомерСтроки - 1) + "].Номенклатура";
            СообщениеОбОшибке.УстановитьДанные(ЭтотОбъект);
            СообщениеОбОшибке.Сообщить();
            Отказ = Истина;
        ИначеЕсли НЕ ЗначениеЗаполнено(СтрокаТЧ.Упаковка) Тогда
            // Если упаковка не заполнена, а для номенклатуры она обязательна
            // или если мы хотим проверить единицу измерения номенклатуры
            // Получаем объект номенклатуры для более детальной проверки
            НоменклатураОбъект = СтрокаТЧ.Номенклатура.ПолучитьОбъект();
            Если НоменклатураОбъект.ВидНоменклатуры.ЕдиницаИзмеренияЯвляетсяВесовой Тогда // Пример условия
                СообщениеОбОшибке = Новый СообщениеПользователю;
                СообщениеОбОшибке.Текст = "Для весовой номенклатуры '" + СтрокаТЧ.Номенклатура.Наименование + "' в строке " + (СтрокаТЧ.НомерСтроки) + " необходимо указать упаковку!";
                СообщениеОбОшибке.Поле = "Товары[" + (СтрокаТЧ.НомерСтроки - 1) + "].Упаковка";
                СообщениеОбОшибке.УстановитьДанные(ЭтотОбъект);
                СообщениеОбОшибке.Сообщить();
                Отказ = Истина;
            КонецЕсли;
        КонецЕсли;

        // Дополнительные проверки, например, на нулевое количество
        Если СтрокаТЧ.Количество = 0 Тогда
             СообщениеОбОшибке = Новый СообщениеПользователю;
             СообщениеОбОшибке.Текст = "Количество в строке " + (СтрокаТЧ.НомерСтроки) + " должно быть больше нуля!";
             СообщениеОбОшибке.Поле = "Товары[" + (СтрокаТЧ.НомерСтроки - 1) + "].Количество";
             СообщениеОбОшибке.УстановитьДанные(ЭтотОбъект);
             СообщениеОбОшибке.Сообщить();
             Отказ = Истина;
        КонецЕсли;

    КонецЦикла;

    Если Отказ Тогда
        Возврат;
    КонецЕсли;

КонецПроцедуры

ОбработкаПроверкиЗаполненияНаСервере (модуль формы документа):

Существует также аналогичное событие ОбработкаПроверкиЗаполненияНаСервере в модуле формы. Оно предназначено для проверки реквизитов, специфичных для формы и не относящихся к основному объекту документа. Если ваша логика проверки касается только реквизитов, которые существуют только на форме и не сохраняются в объект базы данных, то это событие будет подходящим. Однако для проверки данных табличной части документа, которые являются частью объекта, предпочтительнее использовать событие модуля объекта.

Решение 3: Использование стандартных функций проверки

В типовых конфигурациях 1С:УТ и 1С:ERP уже реализованы механизмы для стандартизированной проверки заполнения реквизитов количества и упаковок. Мы настоятельно рекомендуем использовать их, если они покрывают ваши требования.

ОбщегоНазначенияУТ.ПроверитьЗаполнениеКоличества:

Эта (или аналогичная) процедура является частью типовых механизмов и предназначена для проверки заполнения реквизитов Количество и КоличествоУпаковок в документах. Она уже содержит логику, учитывающую различные сценарии работы с единицами измерения и упаковками.

Рассмотрим пример, как мы можем вызвать эту процедуру:


// В модуле объекта документа (в событии ОбработкаПроверкиЗаполнения)
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    // Вызываем стандартную проверку из типовой библиотеки
    ОбщегоНазначенияУТ.ПроверитьЗаполнениеКоличества(ЭтотОбъект, ПроверяемыеРеквизиты, Отказ);

    Если Отказ Тогда
        Возврат; // Если стандартная проверка выявила ошибки, дальше не продолжаем
    КонецЕсли;

    // Далее можем добавить свою специфическую логику проверки,
    // если она не покрывается стандартной процедурой.
    // Например:
    Для Каждого СтрокаТЧ Из Товары Цикл
        // Ваши дополнительные проверки, если они нужны
        // ...
    КонецЦикла;

КонецПроцедуры

Если вам необходимо изменить логику работы такой стандартной процедуры, рекомендуется использовать механизмы расширений. Это позволит сохранить возможность обновлений конфигурации без потери ваших доработок. Не изменяйте типовые процедуры напрямую, если есть альтернатива в виде расширения или подписки на события.

Заключение

Мы выяснили, что проверка единиц измерения в табличной части документа на клиенте в 1С:ERP 2.5 — это задача, требующая внимательного подхода. Мы проанализировали особенности работы с единицами измерения и упаковками, а также рассмотрели основные методы реализации проверки:

  1. Проверка на сервере: Для получения актуальных и полных данных о номенклатуре и упаковках часто необходимо обращение к серверу. Оптимизируйте эти вызовы, передавая массив данных для проверки за один раз.
  2. Событие ОбработкаПроверкиЗаполнения: Это рекомендуемое место для комплексной валидации данных документа при интерактивной записи или проведении. Используйте его в модуле объекта для проверки данных табличных частей.
  3. Стандартные функции: Всегда отдавайте предпочтение типовым процедурам, таким как ОбщегоНазначенияУТ.ПроверитьЗаполнениеКоличества, и используйте расширения для их адаптации.

Применяя эти подходы, мы сможем обеспечить надежную и корректную проверку данных, минимизируя ошибки пользователей и поддерживая целостность информации в системе 1С:ERP 2.5.

← На главную