В практике разработки на платформе 1С часто возникает задача, когда список доступных для выбора элементов справочника должен зависеть от их состояния в определенный момент времени. Типичный пример — выбор транспортного средства (ТС) в документе, где пользователю должны предлагаться только «Годные» машины. Сложность заключается в том, что состояние ТС — это не статичная характеристика, а периодическая величина, которая меняется со временем (вчера машина была годна, сегодня — в ремонте, завтра — снова годна).
В этой статье мы подробно разберем, как реализовать такой механизм, используя управляемые формы, регистры сведений и программные фильтры.
Прежде чем приступать к коду, проанализируем, где должны храниться данные. Если мы просто добавим реквизит Состояние в справочник ТранспортныеСредства, мы сможем видеть только текущий статус. Это не позволит нам корректно оформить документ «задним числом» или будущей датой.
Для решения задачи нам понадобится Периодический регистр сведений (например, СостоянияТС). Его структура должна быть следующей:
ТС (тип СправочникСсылка.ТранспортныеСредства).Состояние (тип ПеречислениеСсылка.СостоянияТС со значениями Годен, ВРемонте, НеГоден).Рассмотрим наиболее гибкий способ — программную установку отбора в момент, когда пользователь нажимает на кнопку выбора в поле документа. Мы перехватим это действие, определим список подходящих ТС на дату документа и ограничим список выбора.
Разберем алгоритм по шагам:
НачалоВыбора для реквизита ТС.СрезПоследних регистра сведений.Пример программного кода для реализации этого метода:
&НаКлиенте
Процедура ТСНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартное открытие формы
// Получаем дату документа, на которую нужно проверить состояние
ДатаОценки = Объект.Дата;
// Получаем список годных ТС через серверную функцию
СписокГодныхТС = ПолучитьСписокГодныхТСНаСервере(ДатаОценки);
// Формируем параметры для открытия формы выбора
ПараметрыВыбора = Новый Структура;
ПараметрыВыбора.Вставить("Отбор", Новый Структура("Ссылка", СписокГодныхТС));
ПараметрыВыбора.Вставить("ЗакрыватьПриВыборе", Истина);
// Открываем форму выбора справочника с наложенным фильтром
ОткрытьФорму("Справочник.ТранспортныеСредства.ФормаВыбора", ПараметрыВыбора, Элемент);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСписокГодныхТСНаСервере(ДатаОценки)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СостоянияТССрезПоследних.ТС КАК ТС
|ИЗ
| РегистрСведений.СостоянияТС.СрезПоследних(&Период, ) КАК СостоянияТССрезПоследних
|ГДЕ
| СостоянияТССрезПоследних.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияТС.Годен)";
Запрос.УстановитьПараметр("Период", ДатаОценки);
РезультатЗапроса = Запрос.Выполнить();
Возврат РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("ТС");
КонецФункции
Важный нюанс: использование конструкции Отбор.Ссылка с видом сравнения ВСписке (который автоматически применяется, если передать массив в структуру отбора) позволяет пользователю видеть только те объекты, которые прошли проверку.
Если нам нужно, чтобы отбор работал более «нативно» или если список ТС очень велик (массивы ссылок могут замедлять работу), проанализируем другой вариант — модификацию запроса в самой форме выбора справочника.
В этом случае мы передаем дату документа в форму выбора как параметр, а в форме выбора настраиваем ДинамическийСписок. Рассмотрим реализацию:
ПриСозданииНаСервере принимаем параметр даты.Пример кода в форме выбора справочника:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем, передана ли дата для фильтрации
Если Параметры.Свойство("ДатаОтбора") Тогда
ТекстЗапроса =
"ВЫБРАТЬ
| СправочникТС.Ссылка,
| СправочникТС.Наименование
|ИЗ
| Справочник.ТранспортныеСредства КАК СправочникТС
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СостоянияТС.СрезПоследних(&ДатаСреза, ) КАК Состояния
| ПО СправочникТС.Ссылка = Состояния.ТС
|ГДЕ
| Состояния.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияТС.Годен)";
Список.ТекстЗапроса = ТекстЗапроса;
Список.Параметры.УстановитьЗначениеПараметра("ДатаСреза", Параметры.ДатаОтбора);
КонецЕсли;
КонецПроцедуры
Чтобы этот код сработал, в документе при открытии формы выбора нужно просто передать параметр ДатаОтбора.
Разберем ситуацию, на которую часто указывают опытные разработчики: что произойдет, если пользователь сначала выбрал ТС на 1-е число месяца (когда оно было годно), а затем изменил дату документа на 15-е число (когда ТС уже в ремонте)?
В этом случае данные в документе станут неактуальными. Чтобы этого избежать, необходимо реализовать проверку в событии ПриИзменении даты документа или в обработчике ПередЗаписью.
Проанализируем пример проверки при изменении даты:
&НаКлиенте
Процедура ДатаПриИзменении(Элемент)
ПроверитьАктуальностьТС();
КонецПроцедуры
&НаСервере
Процедура ПроверитьАктуальностьТС()
Если НЕ ЗначениеЗаполнено(Объект.ТС) Тогда
Возврат;
КонецЕсли;
// Проверяем состояние выбранного ТС на новую дату
АктуальноеСостояние = РегистрыСведений.СостоянияТС.СрезПоследних(Объект.Дата, Новый Структура("ТС", Объект.ТС));
Если АктуальноеСостояние.Количество() > 0 Тогда
Если АктуальноеСостояние[0].Состояние <> ПредопределенноеЗначение("Перечисление.СостоянияТС.Годен") Тогда
Объект.ТС = Справочники.ТранспортныеСредства.ПустаяСсылка();
Сообщить("Выбранное транспортное средство не пригодно на новую дату документа! Поле очищено.");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Мы рассмотрели комплексный подход к решению задачи. Основные выводы:
Выяснив эти принципы, вы сможете реализовывать любые сложные отборы, будь то остатки товаров на складах, статусы сотрудников или доступность оборудования.