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

Программист 1С v7.7 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При разработке отчетов по материальным счетам (например, 10.3 «Топливо») в платформе 1С:Предприятие 7.7 программисты часто сталкиваются с задачей: необходимо одновременно увидеть начальный остаток материалов на складе, общий приход от поставщиков, конечный остаток и детальную расшифровку — на какие именно склады и в каком количестве было оформлено внутреннее перемещение. Попытка решить эту задачу с помощью одного объекта БухгалтерскиеИтоги с подключением метода ИспользоватьКорСубконто() нередко приводит к неожиданным результатам: дебетовый оборот пропадает или становится нулевым, а конечное сальдо уходит в глубокий минус.

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

В чем причина искажения данных при вызове ИспользоватьКорСубконто

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

Ит.ИспользоватьКорСубконто(ВидыСубконто.МестаХранения, , 1);

Платформа накладывает жесткое условие на выборку проводок: в расчет оборотов включаются только те проводки, у корреспондирующего счета которых в плане счетов присутствует субконто типа МестаХранения. Выясним, как это отражается на типовых операциях:

  1. Внутреннее перемещение: проводка Дт 10.3 - Кт 10.3. И у дебетового, и у кредитового счета субконто «Места хранения» присутствует. Такие проводки попадают в кредитовый оборот корректно.
  2. Поступление от поставщика: проводка Дт 10.3 - Кт 60.1. У счета 60.1 субконто «Места хранения» отсутствует (там используются виды субконто «Контрагенты» и «Договоры»). В итоге платформа полностью исключает эти проводки из оборотов запроса.

В результате дебетовый оборот склада (ДО()) становится равным нулю. Конечное сальдо (СКД()), рассчитываемое как СНД + ДО - КО, вычисляется без учета поступлений, что искажает итоговый результат и делает остатки отрицательными. Кроме того, само понятие остатка в разрезе корреспондирующего субконто в бухгалтерском учете отсутствует — остатки существуют только по конкретному счету и его собственной аналитике.

Решение 1. Использование двух объектов БухгалтерскиеИтоги (базовый подход)

Рассмотрим самое надежное и быстрое в реализации решение: разделение задач получения общих остатков и детализации корреспонденций между двумя независимыми экземплярами БухгалтерскиеИтоги.

  1. Первый объект: запрашивает общие итоги по счету (сальдо на начало, общий дебетовый оборот, сальдо на конец) с отбором по складу-отправителю и номенклатуре.
  2. Второй объект: рассчитывает исключительно обороты перемещений (тип итогов 2), ограничивая корреспонденцию нужным счетом и выбирая склады-получатели через ИспользоватьКорСубконто().

Посмотрим на практическую реализацию этого метода:


Процедура Сформировать()
    Перем ИтОстатки, ИтКорр;
    
    Склад = ЗначениеИзСтроки("{""Справочник"",""МестаХранения"",""00001""}"); 
    
    // 1. Запрос общих остатков и оборотов (тип итогов 3)
    ИтОстатки = СоздатьОбъект("БухгалтерскиеИтоги");
    ИтОстатки.ИспользоватьСубконто(ВидыСубконто.МестаХранения, Склад, 2);
    ИтОстатки.ИспользоватьСубконто(ВидыСубконто.Материалы, , 1);
    ИтОстатки.ВыполнитьЗапрос(НачДата, КонДата, "10.3", , , 3, , "К");
    
    // 2. Запрос корреспонденции по перемещениям (тип итогов 2 - только обороты)
    ИтКорр = СоздатьОбъект("БухгалтерскиеИтоги");
    ИтКорр.ИспользоватьСубконто(ВидыСубконто.МестаХранения, Склад, 2);
    ИтКорр.ИспользоватьСубконто(ВидыСубконто.Материалы, , 1); 
    ИтКорр.ИспользоватьКорСубконто(ВидыСубконто.МестаХранения, , 1); 
    // Явно ограничиваем корр-счет счетом "10.3" для ускорения выборки
    ИтКорр.ВыполнитьЗапрос(НачДата, КонДата, "10.3", "10.3", , 2, , "К");
    
    // Обход данных по счетам и материалам
    ИтОстатки.ВыбратьСчета();
    Пока ИтОстатки.ПолучитьСчет() = 1 Цикл
        
        // Позиционируем второй объект на этот же счет
        ИтКорр.ПолучитьСчет(ИтОстатки.Счет);
        
        ИтОстатки.ВыбратьСубконто(2, , , , , "Наименование");
        Пока ИтОстатки.ПолучитьСубконто(2) = 1 Цикл
            
            Сообщить("Материал: " + ИтОстатки.Субконто(2) + 
                     " | Нач. ост: " + ИтОстатки.СНД(3) + 
                     " | Приход: " + ИтОстатки.ДО(3) + 
                     " | Кон. ост: " + ИтОстатки.СКД(3));
            
            // Позиционируем объект корреспонденций на текущий материал
            Если ИтКорр.ПолучитьСубконто(2, , ИтОстатки.Субконто(2)) = 1 Тогда
                ИтКорр.ВыбратьКорСубконто(1);
                Пока ИтКорр.ПолучитьКорСубконто(1) = 1 Цикл
                    Сообщить("    Перемещено на склад: " + ИтКорр.КорСубконто(1) + 
                             " - Количество: " + ИтКорр.КорКО(3));
                КонецЦикла;
            КонецЕсли;
            
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

Обратим внимание на метод точечного позиционирования ИтКорр.ПолучитьСубконто(2, , ИтОстатки.Субконто(2)). Вместо медленного вложенного цикла перебора мы сразу переходим к нужной позиции номенклатуры во втором объекте, что существенно ускоряет формирование отчета.

Решение 2. Использование объекта Запрос («Черный запрос»)

Если требуется объединить расчет в рамках одного источника данных без создания двух объектов бухгалтерских итогов, разберем использование встроенного языка запросов 1С 7.7. Объект Запрос позволяет гибко разделить расчет общего движения и специфической корреспонденции при помощи условий в переменных:


Процедура СформироватьЧерезЗапрос()
    Перем ТекстЗапроса, Запрос;
    
    Запрос = СоздатьОбъект("Запрос");
    ТекстЗапроса = 
    "//{{ЗАПРОС(ОтчетПоТопливу)
    |Период с НачДата по КонДата;
    |Склад = БухгалтерскиеИтоги.Субконто(1);
    |Материал = БухгалтерскиеИтоги.Субконто(2);
    |КорСклад = БухгалтерскиеИтоги.КорСубконто(1);
    |КоррСчет = БухгалтерскиеИтоги.КорСчет;
    |
    |НачОст = БухгалтерскиеИтоги.СНД(, 3);
    |ПриходВсего = БухгалтерскиеИтоги.ДО(, 3);
    |КонОст = БухгалтерскиеИтоги.СКД(, 3);
    |РасходПеремещение = БухгалтерскиеИтоги.КорКО(, 3);
    |
    |Функция ОстНач = Сумма(НачОст);
    |Функция ВсегоПриход = Сумма(ПриходВсего);
    |Функция ОстКон = Сумма(КонОст);
    |Функция Перемещение = Сумма(РасходПеремещение) когда (КоррСчет = СчетПоКоду(""10.3""));
    |
    |Группировка Материал без групп упорядочить по Материал.Наименование;
    |Группировка КорСклад без групп;
    |
    |Условие(Склад = ВыбСклад);
    |//}}ЗАПРОС
    ";
    
    Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
        Возврат;
    КонецЕсли;
    
    Пока Запрос.Группировка(1) = 1 Цикл
        Сообщить("Материал: " + Запрос.Материал + 
                 " | Нач: " + Запрос.ОстНач + 
                 " | Приход: " + Запрос.ВсегоПриход + 
                 " | Кон: " + Запрос.ОстКон);
                 
        Пока Запрос.Группировка(2) = 1 Цикл
            Если ПустоеЗначение(Запрос.КорСклад) = 0 Тогда
                Сообщить("    На склад: " + Запрос.КорСклад + " Передано: " + Запрос.Перемещение);
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

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

← На главную