Как исключить движения по межскладским перемещениям из расхода в отчете по оборотам товара в 1С 7.7?

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

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

Понимание сути проблемы и исходного запроса

Прежде чем перейти к решению, проанализируем исходную задачу и структуру запроса. У нас есть запрос, который обращается к регистру остатков для получения еженедельного прихода и расхода товара на складе. Стандартный регистр остатков в 1С 7.7 по своей природе предназначен для хранения текущих остатков и позволяет получать обороты (приход/расход) за период. Однако, когда мы пытаемся отфильтровать движения по типу документа-регистратора, возникают нюансы. В нашем случае, документ "Межскладская_расход_приход" может формировать как приход, так и расход, и нам требуется исключить из отчета только движения, являющиеся расходом по этому типу документа.

Исходный запрос выглядит следующим образом:


Запрос2 = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|с ВыбНачПериода по ВыбКонПериода;
|Обрабатывать НеПомеченныеНаУдаление;
|Склад      = Регистр.Остатки.Склад;
|Товар      = Регистр.Остатки.ТМЦ;
|Остаток = Регистр.Остатки.Остаток;
|_Док       = Регистр.Остатки.ТекущийДокумент;
|Условие (Склад в ВыбСклад);
|Функция ОстатокПриход = Приход(Остаток);
|Функция ОстатокРасход = Расход(Остаток);
|Группировка Товар Без групп;
|Группировка Неделя Все;";

Первоначальная попытка использовать простое условие


|Условие ((_Док.Вид()<>__вид));
не сработала бы корректно, поскольку оно отфильтровало бы все движения (и приход, и расход) по документу "Межскладская_расход_приход", в то время как наша задача — исключить только расход, оставляя приход по таким документам, если он существует, и, конечно, все остальные виды приходов и расходов.

Решение 1: Условная агрегация в запросе 1С 7.7

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


Приход()
и

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

Расход()
, чтобы она не учитывала движения от документа "Межскладская_расход_приход".

Пошаговая модификация запроса

  1. Определяем документ-регистратор: В запросе у нас уже есть поле
    
    _Док = Регистр.Остатки.ТекущийДокумент;
    
    , которое позволяет обращаться к документу, сформировавшему движение регистра. Это поле мы будем использовать в нашем условии.
  2. Применяем условие к функции Расход(): Мы добавим ключевое слово
    
    КОГДА
    
    в определение функции
    
    ОстатокРасход
    
    . Это ключевое слово позволяет установить условие, при котором будет выполняться агрегатная функция.

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


|Функция ОстатокПриход = Приход(Остаток);
|Функция ОстатокРасход = Расход(Остаток) КОГДА (_Док.Вид() <> "Межскладская_расход_приход");

В данном случае, функция


Приход(Остаток)
будет рассчитываться для всех движений, как и раньше. А вот функция

Расход(Остаток)
будет учитывать значение

Остаток
только в тех записях регистра, где вид документа-регистратора (

_Док.Вид()
) не равен "Межскладская_расход_приход". Таким образом, расход по межскладским перемещениям будет полностью исключен из агрегации "Расход" в отчете, не затрагивая при этом другие приходы или расходы.

Полный текст запроса с учетом изменений:


Запрос2 = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|с ВыбНачПериода по ВыбКонПериода;
|Обрабатывать НеПомеченныеНаУдаление; // Важно: используйте это условие осторожно, см. ниже
|Склад      = Регистр.Остатки.Склад;
|Товар      = Регистр.Остатки.ТМЦ;
|Остаток = Регистр.Остатки.Остаток;
|_Док       = Регистр.Остатки.ТекущийДокумент;
|Условие (Склад в ВыбСклад);
|Функция ОстатокПриход = Приход(Остаток);
|Функция ОстатокРасход = Расход(Остаток) КОГДА (_Док.Вид() <> ""Межскладская_расход_приход"");
|Группировка Товар Без групп;
|Группировка Неделя Все;";

Важный момент: Мы обращаемся к виду документа с помощью функции


_Док.Вид()
. Название типа документа ("Межскладская_расход_приход") должно быть передано в виде строкового литерала, заключенного в двойные кавычки. Внутри текста запроса, который сам заключен в двойные кавычки, внутренние кавычки должны быть удвоены (экранированы), как показано в примере:

""Межскладская_расход_приход""
.

Решение 2: Программная фильтрация после выгрузки в ТаблицуЗначений

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


ТаблицуЗначений
и затем программно отфильтровать или обработать нужные записи.

Пошаговый алгоритм

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

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

    Архитектурные рекомендации и важные предостережения

    При работе с отчетами по оборотам и остаткам, особенно в старых версиях 1С, таких как 7.7, важно учитывать некоторые особенности и лучшие практики.

    Проектирование регистров: добавление реквизита "ВидДвижения"

    Для более удобной и эффективной фильтрации данных в будущем, особенно при появлении новых "хитрых" отчетов, мы рекомендуем рассмотреть возможность добавления в регистр специального реквизита, например, ВидДвижения. Этот реквизит должен заполняться при проведении документа и явно классифицировать тип операции:

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

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

    
    |Функция ОстатокРасход = Расход(Остаток) КОГДА (Регистр.Остатки.ВидДвижения <> Перечисление.ВидыДвиженийТовара.Перемещение);
    

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

    Влияние фильтрации на расчет конечных остатков

    Когда вы фильтруете приход или расход в запросе, как мы это сделали для

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

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

    1. Рассчитывать конечный остаток вручную:
      
      КонечныйОстаток = НачОстаток + ОстатокПриход - ОстатокРасход
      
      , где
      
      ОстатокПриход
      
      и
      
      ОстатокРасход
      
      уже учитывают вашу фильтрацию. Однако
      
      НачОстаток
      
      при этом также должен быть рассчитан с учетом той же логики фильтрации движений, что значительно усложняет задачу.
    2. Использовать отдельный запрос для остатков: Выполнить один запрос для получения корректного начального остатка (без фильтрации движений), а другой — для оборотов с фильтрацией. Затем объединить данные программно.
    3. Выполнить расчеты после выгрузки в ТаблицуЗначений: Как было описано в Решении 2, после получения всех данных в
      
      ТаблицуЗначений
      
      , можно произвести все необходимые вычисления.

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

    Использование "Обрабатывать НеПомеченныеНаУдаление"

    В вашем исходном запросе присутствует строка

    
    |Обрабатывать НеПомеченныеНаУдаление;
    
    . При работе с регистрами в 1С 7.7, движения в них формируются только проведенными документами. Документы, помеченные на удаление, но еще не удаленные, могут быть как проведенными, так и непроведенными. Однако, если документ проведен и помечен на удаление, его движения все равно остаются в регистре до фактического удаления. Обычно, регистры не хранят информацию о статусе "помечен на удаление" для самого регистратора.

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

    
    _Док.ПометкаУдаления()
    
    либо в функции запроса (если она поддерживает такие условия), либо программно после выгрузки. Чаще всего,
    
    Обрабатывать НеПомеченныеНаУдаление
    
    применяется к выборке самих документов, а не к движениям регистров.

    Заключение

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

    
    КОГДА
    
    в функциях
    
    Приход()
    
    или
    
    Расход()
    
    .

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