В платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с задачей фильтрации документов в журнале по наличию подчиненных объектов. Классический пример: необходимо вывести в журнале только те документы РасходнаяНакладная, на основании которых уже был введен и проведен документ ПриходныйКассовыйОрдер (ПКО).
Поскольку штатный механизм отборов в 1С 7.7 имеет существенные ограничения, решить эту задачу «в лоб» стандартным методом УстановитьОтбор() не получится. В этой статье мы подробно разберем причины ограничений платформы и рассмотрим несколько проверенных практических способов реализации такого отбора.
Прежде чем перейти к решениям, проанализируем, почему задача вызывает трудности на уровне платформы:
УстановитьОтбор() не поддерживает работу со списком значений. Мы можем отобрать документы только по одному конкретному значению реквизита.Этот способ основан на добавлении дополнительного реквизита в документ-родитель и его последующей перезаписи при проведении подчиненного документа. Разберем этот алгоритм по шагам:
РасходнаяНакладная и добавим новый реквизит ЕстьПКО (тип: Число, длина: 1). Обязательно установим для него свойство «Отбор по реквизиту».ПКО (процедура ОбработкаПроведения()) напишем код, который будет находить документ-основание и записывать в него признак наличия подчиненного документа:
// При проведении ПКО находим документ-родитель
ДокОснование = ТекущийДокумент().ДокументОснование;
Если ДокОснование.Выбран() = 1 Тогда
// Создаем объект для изменения реквизита без нарушения блокировок
ДокРодитель = СоздатьОбъект("Документ.Расходная");
Если ДокРодитель.НайтиДокумент(ДокОснование) = 1 Тогда
ДокРодитель.ЕстьПКО = 1;
ДокРодитель.Записать();
КонецЕсли;
КонецЕсли;
ПКО необходимо выполнить обратную операцию — сбросить флаг ЕстьПКО в значение 0.РасходнаяНакладная при открытии устанавливаем отбор:
Процедура ПриОткрытии()
УстановитьОтбор("ЕстьПКО", 1);
КонецПроцедуры
Важное предупреждение: Данный метод имеет критический недостаток. Если документ РасходнаяНакладная в момент проведения ПКО будет открыт другим пользователем на редактирование, то попытка программной записи ДокРодитель.Записать() вызовет ошибку блокировки. Ниже мы рассмотрим, как обойти эту проблему.
Если мы хотим обойтись без изменения метаданных и избежать потенциальных блокировок, рассмотрим вариант замены стандартной формы журнала на обработку с элементом управления ТаблицаЗначений. Данный способ отлично подходит для работы с небольшими и средними периодами выборки документов.
Алгоритм реализации выглядит следующим образом:
ТабДокументов. Позиционируем на форме поля выбора периода (дата начала и дата окончания).
Процедура СформироватьЖурнал()
ТабДокументов.Очистить();
ТабДокументов.НоваяКолонка("Документ", "Документ.Расходная");
ТабДокументов.НоваяКолонка("Дата", "Дата");
ТабДокументов.НоваяКолонка("Сумма", "Число");
ДокПКО = СоздатьОбъект("Документ.ПКО");
ДокПКО.ВыбратьДокументы(ДатаНач, ДатаКон);
Пока ДокПКО.ПолучитьДокумент() = 1 Цикл
// Проверяем, что ПКО проведен и имеет основание нужного типа
Если (ДокПКО.Проведен() = 1) И (ДокПКО.ДокументОснование.Вид() = "Расходная") Тогда
Родитель = ДокПКО.ДокументОснование;
// Исключаем дублирование документов в таблице
СтрокаНомер = 0;
Если ТабДокументов.НайтиЗначение(Родитель, СтрокаНомер, "Документ") = 0 Тогда
ТабДокументов.НоваяСтрока();
ТабДокументов.Документ = Родитель;
ТабДокументов.Дата = Родитель.ДатаДок;
ТабДокументов.Сумма = Родитель.Итог("Сумма");
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ПриВыбореСтрокиТаблицы()
ТекущийДок = "";
Если ТабДокументов.ПолучитьЗначение(ТабДокументов.ТекущаяСтрока(), "Документ", ТекущийДок) = 1 Тогда
// Открываем форму документа в режиме только просмотра
ОткрытьФорму(ТекущийДок, , 1);
КонецЕсли;
КонецПроцедуры
Иногда лучшим техническим решением является пересмотр самой постановки задачи. Вместо того чтобы пытаться переделать сложный журнал расходных документов, мы можем предложить пользователям работать «от обратного».
Выясним у заказчика, для чего нужен этот отбор. Если цель — увидеть, по каким расходным накладным уже получена оплата, то гораздо логичнее открыть журнал документов ПКО. В этом журнале достаточно вывести графу «Документ-основание». Таким образом, пользователь сразу будет видеть список оплат и привязанные к ним накладные без написания сложного программного кода.
Для крупных информационных баз на платформе «1С:Предприятие 7.7 SQL» наиболее эффективным решением будет использование внешней компоненты 1С++. Прямой SQL-запрос к системной таблице подчиненности _1SCRDOC отработает за доли секунды даже на миллионах записей.
Связи документов в SQL-версии хранятся в таблице _1SCRDOC, где PARENTID — это идентификатор родительского документа (наша Расходная), а CHILDID — идентификатор подчиненного (ПКО). С помощью класса ODBCRecordset мы можем выбрать все уникальные PARENTID и мгновенно вывести их в виртуальное табличное поле на форме.
Если мы все же выбрали Решение 1 с записью флага отбора, нам необходимо защитить систему от конфликтов блокировок файлов, когда один пользователь проводит ПКО, а у второго в этот момент открыта форма соответствующей Расходной накладной.
Для минимизации этой проблемы переключим глобальный режим открытия объектов в системе:
Shift + Enter).Записать() для этого документа из транзакции проведения ПКО другого пользователя.ОткрытьФорму():
// Третий параметр "1" указывает системе открыть форму в режиме "Только просмотр"
ОткрытьФорму(ДокументСсылка, , 1);
Используя комбинацию этих подходов, мы можем обойти любые технологические ограничения устаревшей платформы 1С 7.7 и обеспечить быструю, надежную и комфортную работу пользователей.