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