Как вывести цену прихода в отчете по продажам в 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

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

Почему прямой запрос к расходным и приходным накладным возвращает нули

Проанализируем механику работы объекта Запрос в 1С:Предприятии 7.7 при обращении к документам. В отличие от современных реляционных баз данных и платформы 1С 8, во встроенном языке запросов 7.7 отсутствует конструкция соединения таблиц (LEFT JOIN).

Когда в тексте запроса одновременно указываются поля из разных документов, например Документ.РасходнаяНакладная.Колич и Документ.ПриходнаяНакладная.Цена0, механизм запросов платформы выполняет последовательный обход документов по хронологической оси. При этом записи не объединяются по товарным позициям в рамках одной строки: для строк расходных документов поля приходных накладных остаются пустыми (или равными нулю), а для приходных — пустыми остаются поля расхода.

Кроме того, если реквизит табличной части (например, Цена0) выбирается без функции агрегации и без группировки по конкретному документу, в переменную запроса попадает значение только из последней обработанной строки группы. Если последним был документ реализации, значение закупочной цены неизбежно окажется равным нулю.

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

Способ 1. Получение себестоимости и цен из регистров оперативного учета

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


Процедура Сформировать()
    Перем Запрос, Таб;
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = "
    |Период с ДатаНач по ДатаКон;
    |Товар = Регистр.Продажи.Номенклатура;
    |Количество = Регистр.Продажи.Количество;
    |СуммаПрод = Регистр.Продажи.ПродСтоимость;
    |Себестоимость = Регистр.Продажи.Себестоимость;
    |Группировка Товар упорядочить по Товар.Наименование;
    |Функция ИтКол = Расход(Количество);
    |Функция ИтСум = Расход(СуммаПрод);
    |Функция ИтСеб = Расход(Себестоимость);
    |";
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат;
    КонецЕсли;
    
    Таб = СоздатьОбъект("Таблица");
    Таб.ВывестиСекцию("Шапка");
    
    Пока Запрос.Группировка("Товар") = 1 Цикл
        Если Запрос.ИтКол <> 0 Тогда
            СрЦенаПродажи = Запрос.ИтСум / Запрос.ИтКол;
            СрЦенаПрихода = Запрос.ИтСеб / Запрос.ИтКол;
            Таб.ВывестиСекцию("Строка");
        КонецЕсли;
    КонецЦикла;
    
    Таб.ВывестиСекцию("Подвал");
    Таб.Показать("Отчет по продажам");
КонецПроцедуры

В данном случае средняя закупочная цена проданного товара рассчитывается как отношение общей себестоимости списания к количеству проданных единиц (Запрос.ИтСеб / Запрос.ИтКол).

Способ 2. Использование двух запросов и объекта ТаблицаЗначений

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

Разберем пошаговый алгоритм реализации:

  1. Первым запросом выбираем данные по продажам из документа РасходнаяНакладная и выгружаем результат в таблицу значений ТЗ_Продажи.
  2. Вторым запросом выбираем данные по поступлениям из документа ПриходнаяНакладная (или регистра остатков) и выгружаем в таблицу ТЗ_Приход.
  3. В таблице приходов рассчитываем среднюю цену закупки как отношение итоговой суммы прихода к количеству.
  4. Обходим таблицу продаж и с помощью метода НайтиЗначение() подтягиваем цену поступления для каждой номенклатурной позиции.

Процедура СформироватьЧерезТЗ()
    Перем ЗапросПрод, ЗапросПрих, ТЗ_Прод, ТЗ_Прих, Таб;
    
    // 1. Запрос по продажам
    ЗапросПрод = СоздатьОбъект("Запрос");
    ТекстПрод = "
    |Период с ДатаНач по ДатаКон;
    |Товар = Документ.РасходнаяНакладная.Товар;
    |КолПрод = Документ.РасходнаяНакладная.Колич;
    |СумПрод = Документ.РасходнаяНакладная.Сумма;
    |Фирма = Документ.РасходнаяНакладная.Фирма;
    |Группировка Товар упорядочить по Товар.Наименование;
    |Условие (Фирма = ВыбФ);
    |Функция ИтКолПрод = Сумма(КолПрод);
    |Функция ИтСумПрод = Сумма(СумПрод);
    |";
    
    Если ЗапросПрод.Выполнить(ТекстПрод) = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ТЗ_Прод = СоздатьОбъект("ТаблицаЗначений");
    ЗапросПрод.Выгрузить(ТЗ_Прод);
    
    // 2. Запрос по поступлениям
    ЗапросПрих = СоздатьОбъект("Запрос");
    ТекстПрих = "
    |Период с ДатаНач по ДатаКон;
    |Товар = Документ.ПриходнаяНакладная.Товар;
    |КолПрих = Документ.ПриходнаяНакладная.Колич;
    |СумПрих = Документ.ПриходнаяНакладная.Сумма;
    |Фирма = Документ.ПриходнаяНакладная.Фирма;
    |Группировка Товар;
    |Условие (Фирма = ВыбФ);
    |Функция ИтКолПрих = Сумма(КолПрих);
    |Функция ИтСумПрих = Сумма(СумПрих);
    |";
    
    Если ЗапросПрих.Выполнить(ТекстПрих) = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ТЗ_Прих = СоздатьОбъект("ТаблицаЗначений");
    ЗапросПрих.Выгрузить(ТЗ_Прих);
    
    // 3. Вывод данных в отчет
    Таб = СоздатьОбъект("Таблица");
    Таб.ВывестиСекцию("Отчет");
    
    ТЗ_Прод.ВыбратьСтроки();
    Пока ТЗ_Прод.ПолучитьСтроку() = 1 Цикл
        Товар = ТЗ_Прод.Товар;
        КолПрод = ТЗ_Прод.ИтКолПрод;
        СумПрод = ТЗ_Прод.ИтСумПрод;
        СрЦенаПрод = ?(КолПрод <> 0, СумПрод / КолПрод, 0);
        
        // Поиск поступления товара
        СрЦенаПрих = 0;
        НомСтр = 0;
        Если ТЗ_Прих.НайтиЗначение(Товар, НомСтр, "Товар") = 1 Тогда
            ТЗ_Прих.ПолучитьСтрокуПоНомеру(НомСтр);
            Если ТЗ_Прих.ИтКолПрих <> 0 Тогда
                СрЦенаПрих = ТЗ_Прих.ИтСумПрих / ТЗ_Прих.ИтКолПрих;
            КонецЕсли;
        КонецЕсли;
        
        Таб.ВывестиСекцию("Строка");
    КонецЦикла;
    
    Таб.ВывестиСекцию("Подвал");
    Таб.Опции(0, 0, 0, 0);
    Таб.Показать("", "");
КонецПроцедуры

Способ 3. Получение цены из периодических реквизитов или справочника цен

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

  1. Если цена хранится в периодическом реквизите справочника Номенклатура: ЦенаПрихода = Запрос.Товар.ЦенаПрихода.Получить(ДатаКон);
  2. Если в конфигурации используется подчиненный справочник цен (например, Справочник.Цены):
    
    СпрЦены = СоздатьОбъект("Справочник.Цены");
    СпрЦены.ИспользоватьВладельца(Запрос.Товар);
    Если СпрЦены.НайтиПоРеквизиту("КатегорияЦены", Константа.ЗакупочнаяКатегорияЦены, 0) = 1 Тогда
        ЦенаПрихода = СпрЦены.Цена.Получить(ДатаКон);
    Иначе
        ЦенаПрихода = 0;
    КонецЕсли;
    

Важный нюанс: при выборе любого из способов убедитесь, что в коде предусмотрена проверка деления на ноль перед расчетом средних цен (Если Количество <> 0 Тогда).

← На главную