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