Как получить документ-основание «Счет на оплату» из документа «Поступление на расчетный счет» в 1С?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

В чем заключается ошибка при поиске через структуру подчиненности

Проанализируем типовую ошибку. При попытке вызвать функции вида ПолныеПрава.ПолучитьСписокПодчиненныхДокументов(...) или обратиться к критерию отбора по подчиненности, поиск ведется «сверху вниз». Критерий отбора проверяет, где текущий документ указан в качестве реквизита или основания в других объектах базы данных.

В типовых конфигурациях 1С логика взаимосвязи обратная:

  1. Документ СчетНаОплатуПокупателю создается первым и является ведущим документом (основанием).
  2. Документ ПоступлениеНаРасчетныйСчет вводится на основании счета. Следовательно, именно платежный документ хранит ссылку на выставленный счет, а не наоборот.
  3. Реквизит со ссылкой на счет располагается не в шапке документа поступления, а в его табличной части РасшифровкаПлатежа (поле СчетНаОплату). Это связано с тем, что одной платежкой покупатель может оплатить сразу несколько счетов или закрыть задолженность по нескольким договорам.

Поэтому обращение к подчиненным документам для ПоступлениеНаРасчетныйСчет не возвращает счет — подчиненным по отношению к счету является сам платеж.

Оптимальное решение: получение счета через запрос к табличной части

Разберем по шагам, как правильно составить запрос к базе данных. Чтобы отчет работал быстро и не создавал избыточной нагрузки на сервер, объединим получение данных шапки документа и его табличной части в единый запрос, избегая разыменования полей через точку в цикле (проблема N+1).

Посмотрим на пример правильного формирования запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Расшифровка.Ссылка КАК СсылкаНаДокумент,
    |	Расшифровка.Ссылка.Номер КАК НомерДокумента,
    |	Расшифровка.Ссылка.Дата КАК ДатаДокумента,
    |	Расшифровка.Ссылка.Организация КАК Организация,
    |	Расшифровка.Ссылка.Контрагент КАК Контрагент,
    |	Расшифровка.Ссылка.Ответственный КАК Ответственный,
    |	Расшифровка.СуммаПлатежа КАК СуммаПлатежа,
    |	Расшифровка.СчетНаОплату КАК СчетНаОплату,
    |	Расшифровка.СчетНаОплату.Дата КАК ДатаСчета,
    |	Расшифровка.СчетНаОплату.СуммаДокумента КАК СуммаСчета
    |ИЗ
    |	Документ.ПоступлениеНаРасчетныйСчет.РасшифровкаПлатежа КАК Расшифровка
    |ГДЕ
    |	Расшифровка.Ссылка.ПометкаУдаления = ЛОЖЬ
    |	И Расшифровка.Ссылка.Дата МЕЖДУ &НачДат И &КонДат
    |	И (&Организация = ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) ИЛИ Расшифровка.Ссылка.Организация = &Организация)
    |	И (&Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) ИЛИ Расшифровка.Ссылка.Контрагент = &Контрагент)
    |	И (&Ответственный = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) ИЛИ Расшифровка.Ссылка.Ответственный = &Ответственный)
    |
    |УПОРЯДОЧИТЬ ПО
    |	Расшифровка.Ссылка.Дата,
    |	Расшифровка.НомерСтроки";

Запрос.УстановитьПараметр("НачДат", НачалоДня(НачДата));
Запрос.УстановитьПараметр("КонДат", КонецДня(КонДата));
Запрос.УстановитьПараметр("Организация", ВбрОрганизация);
Запрос.УстановитьПараметр("Контрагент", ВбрКонтрагент);
Запрос.УстановитьПараметр("Ответственный", ВбрОтветственный);

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    НоваяСтрока = ТаблЗнач.Добавить();
    НоваяСтрока.ТекДок        = Выборка.СсылкаНаДокумент;
    НоваяСтрока.ДатаДок       = Выборка.ДатаДокумента;
    НоваяСтрока.НомерДок      = Выборка.НомерДокумента;
    НоваяСтрока.Организация   = Выборка.Организация;
    НоваяСтрока.Контрагент    = Выборка.Контрагент;
    НоваяСтрока.Ответственный = Выборка.Ответственный;
    НоваяСтрока.СуммаДок      = Выборка.СуммаПлатежа;
    
    Если ЗначениеЗаполнено(Выборка.СчетНаОплату) Тогда
        НоваяСтрока.Счет = Выборка.СчетНаОплату;
        НоваяСтрока.Оплата = Строка(Формат(Выборка.ДатаСчета, "ДЛФ=Д")) + " Сумма: " + Строка(Выборка.СуммаСчета);
    КонецЕсли;
КонецЦикла;

Важные замечания по коду:

  1. Обращение идет напрямую к таблице Документ.ПоступлениеНаРасчетныйСчет.РасшифровкаПлатежа, откуда сразу извлекается реквизит СчетНаОплату.
  2. Все реквизиты шапки (номер, дата, контрагент) и свойства счета (дата, сумма) выбираются непосредственно в запросе, что исключает обращение через точку в цикле и предотвращает отправку сотен одиночных неявных SQL-запросов.
  3. Учитывайте, что при оплате нескольких счетов одной платежкой запрос вернет несколько строк с одинаковой ссылкой документа поступления.

Как реализовать интерактивное открытие документа по двойному клику (расшифровку)

Рассмотрим, как обеспечить интерактивный переход к документу при работе с результирующей таблицей.

Вариант 1. Использование табличного документа (отчета):

При выводе ячеек в ТабличныйДокумент достаточно заполнить параметр расшифровки текущей области:


ОбластьСтрока.Параметры.ТекДок = Выборка.СсылкаНаДокумент;
ОбластьСтрока.Параметры.Счет   = Выборка.СчетНаОплату;

// Заполняем стандартную расшифровку ячейки ссылкой на документ
ОбластьСтрока.Области.ЯчейкаДокумента.Расшифровка = Выборка.СсылкаНаДокумент;
ОбластьСтрока.Области.ЯчейкаСчета.Расшифровка     = Выборка.СчетНаОплату;

ТабДок.Вывести(ОбластьСтрока);

В этом случае платформа 1С автоматически откроет нужную форму документа по двойному щелчку мыши без написания дополнительного кода.

Вариант 2. Использование таблицы значений на форме:

Если результат отображается в элементе управления формы (табличном поле):

  1. В свойствах элемента управления найдем событие Выбор и создадим обработчик.
  2. Внутри процедуры обработчика получим ссылку из текущей строки и откроем ее:

Процедура ТабличноеПолеВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    // Отменяем стандартное редактирование ячейки
    СтандартнаяОбработка = Ложь;
    
    // Получаем значение из выбранной колонки или строки
    Если Поле.Имя = "Счет" И ЗначениеЗаполнено(ВыбраннаяСтрока.Счет) Тогда
        ОткрытьЗначение(ВыбраннаяСтрока.Счет);
    ИначеЕсли ЗначениеЗаполнено(ВыбраннаяСтрока.ТекДок) Тогда
        ОткрытьЗначение(ВыбраннаяСтрока.ТекДок);
    КонецЕсли;
КонецПроцедуры

Для управляемых форм вместо процедуры ОткрытьЗначение используется клиентский метод ПоказатьЗначение(, ВыбраннаяСтрока.Счет).

← На главную