В процессе разработки и кастомизации конфигураций на платформе «1С:Предприятие 8» программисты часто сталкиваются с необходимостью валидации данных перед записью объекта. Особое место в этом процессе занимают операции, вводимые вручную — документы типа ДокументОбъект.ОперацияБух. Специфика этого документа заключается в том, что он не имеет собственных табличных частей для хранения проводок. Все движения записываются напрямую в регистр бухгалтерии.
В этой статье мы подробно разберем, как проверить наличие определенного счета в дебете (или кредите) незаписанной ручной операции непосредственно в модуле формы, проанализируем типичные ошибки разработчиков и рассмотрим правильные архитектурные подходы для реализации этой задачи как на клиенте, так и на сервере.
Перед тем как перейти к написанию кода, давайте разберем, как устроен документ «ОперацияБух» (в некоторых конфигурациях — «Операция»). В отличие от накладных или платежных поручений, этот документ выполняет роль исключительно «оболочки» или регистратора. На форме документа отображается таблица проводок, которая связана напрямую с набором записей регистра бухгалтерии через реквизит формы. Обычно путь к данным этой таблицы имеет вид Объект.Движения.Хозрасчетный.
Когда пользователь добавляет строки в таблицу на форме, они еще не существуют в базе данных (СУБД). Данные находятся исключительно в оперативной памяти клиентского приложения в виде специального объекта платформы — ДанныеФормыКоллекция. Именно поэтому стандартные запросы к базе данных или создание нового набора записей через РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей() в этот момент абсолютно бесполезны: они вернут пустой результат.
В процессе обсуждения подобных задач на форумах разработчики нередко приходят к решению использовать свойство табличного поля формы напрямую. Например, обращаются к Элементы.Хозрасчетный.ТекущиеДанные на клиенте.
Проанализируем, почему этот подход содержит критическую логическую ошибку. Свойство ТекущиеДанные возвращает строку, на которой в текущий момент времени находится курсор пользователя. Рассмотрим сценарий:
ТекущиеДанные, она проверит только пятую строку, вернет значение «Ложь» и пропустит документ, несмотря на то, что во второй строке нужный счет присутствует.Использовать Элементы.Хозрасчетный.ТекущиеДанные допускается исключительно в интерактивных событиях при изменении конкретной строки (например, в обработчике события ПриИзменении реквизита строки таблицы), но категорически запрещено применять для проверки документа в целом.
Если нам необходимо проверить наличие счета в дебете на клиенте (например, перед вызовом серверных процедур для оптимизации трафика), мы можем использовать тот факт, что коллекция Объект.Движения.Хозрасчетный полностью доступна на клиенте. Тип данных ДанныеФормыКоллекция позволяет обходить свои элементы в цикле Для Каждого.
Рассмотрим пример реализации клиентской функции:
&НаКлиенте
Функция ПроверитьНаличиеСчетаВДебетеНаКлиенте(ИскомыйСчет)
// ИскомыйСчет — ссылка на элемент плана счетов "Хозрасчетный"
Если НЕ ЗначениеЗаполнено(ИскомыйСчет) Тогда
Возврат Ложь;
КонецЕсли;
// Обходим коллекцию незаписанных движений на форме
Для Каждого СтрокаПроводки Из Объект.Движения.Хозрасчетный Цикл
// Сравнение ссылок на клиенте выполняется мгновенно
Если СтрокаПроводки.СчетДт = ИскомыйСчет Тогда
Возврат Истина; // Счет найден
КонецЕсли;
КонецЦикла;
Возврат Ложь; // Счет не найден во всей коллекции
КонецФункции
Этот способ является наиболее производительным для простых проверок «по ссылке», так как он не требует контекстного вызова сервера и не нагружает сеть передачей данных формы.
Бывают ситуации, когда простой проверки ссылки на клиентской стороне недостаточно. Например, нам необходимо проверить, входит ли счет дебета в определенную группу счетов (использовать метод ПринадлежитИерархии), проанализировать его виды субконто или сопоставить аналитику. В этом случае проверку необходимо выполнять на сервере.
Для оптимизации поиска на сервере мы можем преобразовать коллекцию формы в полноценную таблицу значений. Это позволит нам использовать быстрый поиск платформы без написания ручных циклов. Разберем этот метод по шагам:
&НаСервере
Функция ПроверитьСчетНаСервере(ИмяСчетаСтрокой)
// Получаем ссылку на счет из плана счетов
НайденныйСчет = ПланыСчетов.Хозрасчетный.НайтиПоКоду(ИмяСчетаСтрокой);
Если НайденныйСчет.Пустая() Тогда
Возврат Ложь;
КонецЕсли;
// Шаг 1. Выгружаем данные формы (коллекцию движений) в реальную таблицу значений
ТаблицаПроводок = Объект.Движения.Хозрасчетный.Выгрузить();
// Шаг 2. Используем быстрый поиск строк по структуре отбора
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("СчетДт", НайденныйСчет);
НайденныеСтроки = ТаблицаПроводок.НайтиСтроки(ПараметрыОтбора);
// Шаг 3. Анализируем результат
Если НайденныеСтроки.Количество() > 0 Тогда
// Здесь мы также можем обойти найденные строки для дополнительного анализа субконто
Возврат Истина;
КонецЕсли;
Возврат Ложь;
КонецФункции
При реализации доработок для формы ручной операции обязательно учитывайте следующие технические нюансы:
ПутьКДанным у элемента таблицы. Если там указан другой путь, обращайтесь именно к этому реквизиту.Объект.Движения.Хозрасчетный.Записывать должно иметь значение Истина. Если вы программно добавляете проводки на форме, обязательно устанавливайте этот флаг.СубконтоДт1 у строки, где выбран счет без субконто, платформа не вызовет ошибку, но вернет Неопределено. Всегда делайте проверку на доступность видов субконто для конкретного счета.Таким образом, мы рассмотрели надежные и архитектурно правильные способы проверки незаписанных движений ручной операции на управляемой форме 1С, избегая ловушек с использованием текущих данных интерфейса.