Как получить счета на оплату с их актуальными статусами в 1С:Бухгалтерия без дублирования строк?

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

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

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

Архитектурное заблуждение: как устроен регистр «Статусы документов»

Когда разработчик видит дублирование строк при соединении со статусами документов, первой мыслью часто становится предположение, что в регистре сведений хранится история изменений и по одному счету существует несколько записей. На форумах нередко советуют выбирать срез последних или группировать по максимальной дате. Но в типовой конфигурации 1С:БП 3.0 этот подход приведет к ошибкам.

Давайте проанализируем структуру регистра сведений СтатусыДокументов:

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

Настоящая причина дублирования строк

Разберем ситуацию, когда разработчик связывает три таблицы: Документ.СчетНаОплатуПокупателю, Документ.РеализацияТоваровУслуг и регистр РегистрСведений.СтатусыДокументов. Источником дублей в данном случае выступает связь «один ко многим» между счетом и документами реализации.

На один выставленный счет на оплату менеджеры могут выписать несколько накладных или актов (например, при частичной или поэтапной отгрузке товаров). Когда мы делаем прямое левое соединение:


ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг 
    ПО (РеализацияТоваровУслуг.СчетНаОплатуПокупателю = СчетНаОплатуПокупателю1.Ссылка)

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

Решение проблемы с помощью правильного построения запроса

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

Вариант А. Вывод счета, его статуса и только последней реализации

Если нам необходимо показать в одной строке счет, его текущий статус и только самый последний (актуальный) документ реализации, связь с таблицей реализаций следует реализовать через предварительно сгруппированный подзапрос. Мы выберем максимальную ссылку реализации по каждому счету-основанию.

Рассмотрим детально структуру такого запроса:


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

Почему этот запрос работает правильно? Мы изолировали таблицу реализаций внутри подзапроса и применили группировку СГРУППИРОВАТЬ ПО совместно с агрегатной функцией МАКСИМУМ(Реализация.Ссылка). Это гарантирует, что для каждого счета из подзапроса вернется строго одна запись (наиболее поздняя по времени создания ссылка), исключая дублирование строк на уровне основного соединения.

Вариант Б. Вывод реестра счетов и их состояний (без вывода физических документов реализации)

В конфигурации 1С:БП 3.0 регистр СтатусыДокументов хранит не только статус оплаты, но и статус отгрузки (в ресурсе ДополнительныйСтатус). Если бизнес-логика вашего отчета не требует вывода конкретного номера и даты акта или накладной, то соединение с таблицей РеализацияТоваровУслуг вообще не требуется.

Проанализируем более легкий и производительный вариант запроса:


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

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

Программное получение статуса счета в коде

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

Выясним, как использовать этот метод программно:


ПараметрыДокумента = РегистрыСведений.СтатусыДокументов.ПолучитьСтатусыДокумента(СсылкаНаСчет, ОрганизацияСсылка);

Если ПараметрыДокумента <> Неопределено Тогда
    ТекущийСтатусОплаты = ПараметрыДокумента.Статус;
    ТекущийСтатусОтгрузки = ПараметрыДокумента.ДополнительныйСтатус;
КонецЕсли;

Использование типовых процедур и функций БСП позволяет избежать ошибок при обновлении конфигурации, если разработчики фирмы 1С решат изменить внутреннюю структуру хранения данных регистра.

Полезные советы по устранению расхождений в статусах счетов

Часто пользователи обращаются к программистам с жалобами на то, что «счет фактически оплачен или отгружен, но в программе его статус отображается как "Не оплачен"». Проанализируем основные причины такого поведения системы:

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

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

← На главную