Связанные табличные части (управляемые формы)






У нас есть 2 связанные табличные части, и нам надо, чтобы по текущей строке в одной из них мы видели только определенные строки во второй. Были бы у нас динамические списки, мы бы взяли событие «При активизации строки» и стандартный механизм отборов СКД, которая лежит в основе списка. Но вот с табличными частями так не получится. Тут нам надо будет написать несколько строк кода и использовать «ОтборСтрок», доступный для таблицы формы. Тестировалось на платформе 8.3.13.1644, будет работать и на более ранних версиях платформы.

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

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

Конфигурация состоит из двух справочников: "Контрагенты" и "Товары" и одного документа "Поступление товаров". Данный документ имеет 2 соответствующие табличные части и предназначен для получения товаров от разных клиентов в одном документе.

Визуально форма выглядит так:

Мы хотим сделать так, чтобы клиенту было удобно и он выбирая клиента видел только те товары, которые приходят от него.

В качестве ключа связи мы будем использовать само значение контрагента. При этом можно в качестве ключа связи использовать произвольные ключи, уникальные в пределах документа или любые ссылочные элементы, например договора контрагентов — все зависит только от вашей необходимости.

Для нашей левой табличной части "Контрагенты" нам надо добавить следующие обработчики событий:

Нам надо при активизации строки показывать только товары, принадлежащие выбранному контрагенту (События "При активизации строки" и "При окончании редактирования") и так же отработать ситуацию удаления контрагента — нам надо удалить все товары со второй табличной части.

&НаКлиенте
Процедура КонтрагентыПриАктивизацииСтроки(Элемент)
ТекДанные = Элемент.ТекущиеДанные;
УстановитьОтборПоКлючу(ТекДанные,Элементы.Товары,НаименованиеКлючаСвязи);
КонецПроцедуры

&НаКлиенте
Процедура КонтрагентыПередУдалением(Элемент, Отказ)
ОбщаяПроцедураУдалитьСтроки(Элемент.ТекущиеДанные,Объект.Товары,НаименованиеКлючаСвязи);
КонецПроцедуры

&НаКлиенте
Процедура КонтрагентыПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
ТекДанные = Элемент.ТекущиеДанные;

ТекНаименованиеКлюча = НаименованиеКлючаСвязи;

Если ТекДанные[ТекНаименованиеКлюча] <> ТекДанные[ТекНаименованиеКлюча + "Начальный"] Тогда

ПерезаполнитьЗначениеКлюча(ТекДанные[ТекНаименованиеКлюча+"Начальный"],ТекДанные[ТекНаименованиеКлюча],"Товары",ТекНаименованиеКлюча);

ТекДанные[ТекНаименованиеКлюча + "Начальный"] = ТекДанные[ТекНаименованиеКлюча];

КонецЕсли;

УстановитьОтборПоКлючу(ТекДанные,Элементы.Товары,ТекНаименованиеКлюча);
КонецПроцедуры

Сами процедуры обработки:

&НаКлиенте
Процедура УстановитьОтборПоКлючу(ТекДанные,ТекЭлем,НаименованиеКлюча)
Если ТекДанные = Неопределено Тогда
Возврат;
КонецЕсли;

// Создаем структуру отбора
Отбор = Новый Структура;
Отбор.Вставить(НаименованиеКлюча, ТекДанные[НаименованиеКлюча]);
// Задаем фиксированную структуру отбора для таблицы формы
ТекЭлем.ОтборСтрок = Новый ФиксированнаяСтруктура(Отбор);
КонецПроцедуры

&НаКлиенте
Процедура ОбщаяПроцедураУдалитьСтроки(ТекДанные,ТекЭлем,НаименованиеКлюча)
Если ТекДанные <> Неопределено Тогда
МассивСтрок = ТекЭлем.НайтиСтроки(Новый Структура (НаименованиеКлюча,ТекДанные[НаименованиеКлюча]));
Для Каждого СтрМассива ИЗ МассивСтрок Цикл
ТекЭлем.Удалить(СтрМассива);
КонецЦикла;
КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ПерезаполнитьЗначениеКлюча (ЗначениеКлючаНачальный,ЗначениеКлюча,НаименованиеТабЧасти,НаименованиеКлюча)
Если ЗначениеЗаполнено(ЗначениеКлючаНачальный) Тогда
ТекЭлем = Объект[НаименованиеТабЧасти];
МассивСтрок = ТекЭлем.НайтиСтроки(Новый Структура (НаименованиеКлюча,ЗначениеКлючаНачальный));
Для Каждого СтрМассива ИЗ МассивСтрок Цикл
СтрМассива[НаименованиеКлюча] = ЗначениеКлюча;
КонецЦикла;
КонецЕсли;
КонецПроцедуры

Для правой табличной части "Товары" нам также надо обработать несколько событий:

Мы должны отклонить выбор номенклатуры если у нас нет или не выбран контрагент и автоматически заполнять значение ключа связи — в нашем случае это ссылка на контрагента. Сами процедуры:

&НаКлиенте
Процедура ТоварыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа, Параметр)
Если Элементы.Контрагенты.ТекущиеДанные = Неопределено Тогда
Отказ = Истина;
КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ТоварыПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)
Если НоваяСтрока И НЕ Копирование Тогда
Элемент.ТекущиеДанные[НаименованиеКлючаСвязи] = Элементы.Контрагенты.ТекущиеДанные[НаименованиеКлючаСвязи];
КонецЕсли;
КонецПроцедуры

Ну и в основном для вопросов отладки нам надо посмотреть все товары всех клиентов, для этого добавляем команду по очистке отборов и размещаем ее в интерфейсе с ограничением по правам (если требуется). Процедура простейшая:

&НаКлиенте
Процедура ОчиститьОтбор(Команда)
СнятьОтборСЭлементов(Элементы.Товары);
КонецПроцедуры

UPD 1. 26.01.2024

Для того, чтобы учесть возможность смены самого контрагента, мы добавили в форме реквизит табличной части :

Сделали его заполнение при открытии формы и обрабатываем его изменение в коде:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//Определим ключ связи
НаименованиеКлючаСвязи = "Контрагент";

ДозаполнитьТабЧасть();
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
ДозаполнитьТабЧасть();
КонецПроцедуры

&НаСервере
Процедура ДозаполнитьТабЧасть ()
Для Каждого СтрТаб ИЗ Объект.Контрагенты Цикл
СтрТаб[НаименованиеКлючаСвязи+"Начальный"] = СтрТаб[НаименованиеКлючаСвязи];
КонецЦикла;
КонецПроцедуры

Для большей универсальности стал использовать реквизит формы "НаименованиеКлючаСвязи", который устанавливаю 1 раз и использую потом везде.

При этом хочу обратить ваше внимание вопрос повторности контрагентов остается открытым — т.е. при выборе слева одного контрагента 2 раза система не сможет различить номенклатуру по строкам. Вам либо надо контролировать, чтобы информация слева была уникальная и/или неизменной.

Для презентации того, как можно учесть и данный случай, я добавил в конфигурацию еще один документ "ПродажаТовара", в котором в качестве ключа связи испльзуется уникальный индекс — простое число, которое уникально для каждой строки слева и привязка идет непосредственно к нему:

Механизм реализации такой абсолютно такой же.

2 Comments

  1. ltfriend

    Изменили контрагента и имеем несвязанные строки номенклатуры, которые ни кто не увидит и которые так и будут «болтаться» вечно в документе.

    Reply
  2. Kim1C

    (1) Да, согласен, не продумал. Исправил статью и конфигурацию и добавил возможность менять контрагента

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *