Как выгрузить остатки по регистрам и бухгалтерским итогам на нужную дату в 1С 7.7

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

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

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

---

Часть 1. Вывод остатков регистра накопления в макет

Рассмотрим стандартную ситуацию: нам необходимо получить остатки по регистру ОстаткиТМЦ на определенную дату (например, на конец дня 31.12.2025) и вывести их в макет. Типичная ошибка при написании подобного кода выглядит так: вызывается временный расчет, но в макет выводится только шапка таблицы, а сами строки остаются пустыми или вызывают ошибки инициализации переменных.

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

В платформе 1С 7.7 существуют два метода временного расчета:

  1. РассчитатьРегистрыНа(<Граница>) — выполняет расчет остатков на начало указанной даты или перед указанным документом. Если передать дату 31.12.2025, то движения документов, проведенных этой датой, учтены не будут.
  2. РассчитатьРегистрыПо(<Граница>) — рассчитывает остатки на конец указанной даты (включая все секунды суток) или на момент после проведения документа. Для получения корректных остатков на конец дня необходимо использовать именно этот метод.

Ниже представлен исправленный, полностью рабочий алгоритм выгрузки остатков по регистру накопления:


Процедура Сформировать()
    Перем Таб, ОблШапка, ОблСтрока, РегТМЦ, ДатаОстатков;
    Перем Счет, ТМЦ, Склад, Партия, Количество, Сумма; // Переменные для макета
    
    ДатаОстатков = Дата(2025, 12, 31);
    
    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("Остатки");
    
    // Получаем секции макета
    ОблШапка  = Таб.ПолучитьСекцию("Шапка");          
    ОблСтрока = Таб.ПолучитьСекцию("Строка");
    
    // Выводим шапку в таблицу
    Таб.ВывестиСекцию(ОблШапка);
    
    // Инициализируем регистр и включаем временный расчет
    РегТМЦ = СоздатьОбъект("Регистр.ОстаткиТМЦ");
    РегТМЦ.ВременныйРасчет(1);
    
    // Рассчитываем итоги ПО указанную дату включительно (на конец дня)
    РассчитатьРегистрыПо(ДатаОстатков);
    
    // Выбираем полученные итоги
    РегТМЦ.ВыбратьИтоги();
    Пока РегТМЦ.ПолучитьИтог() = 1 Цикл
        // Явно заполняем переменные, которые указаны в ячейках секции "Строка" как выражения
        Счет       = РегТМЦ.Счет;
        ТМЦ        = РегТМЦ.Товар; // или РегТМЦ.Номенклатура, в зависимости от конфигурации
        Склад      = РегТМЦ.Склад;
        Партия     = РегТМЦ.Партия;
        Количество = РегТМЦ.Количество;
        Сумма      = РегТМЦ.Сумма;
        
        // Выводим заполненную строку в макет
        Таб.ВывестиСекцию(ОблСтрока);
    КонецЦикла;
    
    Таб.ТолькоПросмотр(1);
    Таб.Показать("Остатки по регистру ОстаткиТМЦ на " + (ДатаОстатков));
КонецПроцедуры

---

Часть 2. Проблема «незакрытых» регистров в 1С 7.7

При работе с регистрами в 1С 7.7 разработчики часто сталкиваются со скрытой угрозой — так называемыми незакрытыми регистрами. Проанализируем ситуацию подробнее.

Физически каждый регистр остатков в файловой версии (DBF) состоит из двух основных таблиц:

Если при поступлении товара были заполнены все измерения (например, Товар, Склад, Партия), а при списании по какой-то причине (ошибка в коде проведения, незаполненная аналитика) измерение Партия оказалось пустым, возникает следующая проблема:

  1. Положительное движение запишется по аналитике: [Товар1, Склад1, ДокументПоступления] = +1.
  2. Отрицательное движение запишется по аналитике: [Товар1, Склад1, <Пусто>] = -1.

С точки зрения общего остатка по товару и складу у вас будет чистый ноль. Однако для СУБД это две абсолютно разные записи. Они никогда не схлопнутся автоматически. Система будет бесконечно переносить эти «встречные» записи из месяца в месяц в таблицу остатков RG*.dbf.

Чем это опасно?
В файловых базах 1С 7.7 действует жесткое ограничение операционной системы и СУБД DBF — размер любого файла базы данных не может превышать 2 ГБ. Из-за незакрытых измерений таблица итогов начинает расти лавинообразно. Это приводит к существенному замедлению работы отчетов, долгому открытию периодов, а при достижении лимита в 2 ГБ — к аварийному завершению работы программы и разрушению индексов базы данных.

Как диагностировать проблему:

---

Часть 3. Получение остатков по бухгалтерским счетам с субконто

Если при переносе данных вам понадобилось выгрузить остатки по бухгалтерским счетам (например, по счету 60 «Расчеты с поставщиками и подрядчиками») со всеми субконто (Контрагенты, Договоры), стандартный механизм регистров не подойдет. Здесь необходимо использовать объект БухгалтерскиеИтоги.

Разберем по шагам рабочий код, который обходит бухгалтерские итоги по счету 60, извлекает значения субконто и реквизиты договоров (номер и дату) через механизм попытки-исключения, так как виды субконто на разных счетах могут отличаться:


Процедура ВыгрузитьБухИтоги()
    Перем Таб, ОблШапка, ОблСтрока, БухИтоги, Ит, ДатаОстатков;
    Перем Счет, Субконто1, Субконто2, Договор, НомерДоговора, ДатаДоговора, СуммаДт, СуммаКт;
    
    ДатаОстатков = Дата(2025, 12, 31);
    
    Таб = СоздатьОбъект("Таблица");
    Таб.ИсходнаяТаблица("ОстаткиБух");
    
    ОблШапка  = Таб.ПолучитьСекцию("Шапка");
    ОблСтрока = Tab.ПолучитьСекцию("Строка");
    Таб.ВывестиСекцию(ОблШапка);
    
    // Инициализируем основной объект бухгалтерских итогов
    БухИтоги = СоздатьОбъект("БухгалтерскиеИтоги");
    
    // Включаем субсчета: первый параметр - уровень детализации, второй - признак активности
    БухИтоги.ВключатьСубсчета(-1, 0);
    
    // Выполняем запрос по счету 60 на дату остатков
    // Обратите внимание на последний параметр "1" - он означает получение только остатков (без оборотов)
    БухИтоги.ВыполнитьЗапрос(, ДатаОстатков, "60", , , , , 1);
    
    // Создаем вспомогательный объект для детальной выборки по субконто
    Ит = СоздатьОбъект("БухгалтерскиеИтоги");
    
    БухИтоги.ВыбратьСчета(1);
    Пока БухИтоги.ПолучитьСчет(0) = 1 Цикл
        Счет = БухИтоги.Счет;
        
        // Настраиваем вспомогательный объект на работу с субконто текущего счета
        Для к = 1 По Счет.КоличествоСубконто() Цикл
            Ит.ИспользоватьСубконто(Счет.ВидСубконто(к), , 1, 0);
        КонецЦикла;
        
        // Выполняем запрос по конкретному счету с установленными субконто
        Ит.ВыполнитьЗапрос(, ДатаОстатков, Счет, , , , , 1);
        
        // Начинаем обход по первому субконто (например, Контрагенты)
        Ит.ВыбратьСубконто(1);
        Пока Ит.ПолучитьСубконто(1) = 1 Цикл  
            
            // Начинаем обход по второму субконто (например, Договоры)
            Ит.ВыбратьСубконто(2);
            Пока Ит.ПолучитьСубконто(2) = 1 Цикл
                
                Субконто1 = Ит.Субконто(1); 
                Субконто2 = Ит.Субконто(2);
                
                // Сбрасываем значения реквизитов перед чтением
                Договор       = ПолучитьПустоеЗначение("Справочник.Договоры");
                НомерДоговора = "";
                ДатаДоговора  = "";
                
                // Используем Попытку, так как у разных счетов виды субконто могут не иметь данных реквизитов
                Попытка
                    // Предполагаем, что второе субконто - это договор или документ расчетов
                    Договор       = Ит.Субконто(2);
                    НомерДоговора = Договор.Наименование;
                    ДатаДоговора  = Договор.ДатаДоговора;
                Исключение
                    // Если реквизиты отсутствуют, код продолжит работу без аварийной остановки
                КонецПопытки;
                
                // Получаем дебетовое и кредитовое сальдо конечные
                СуммаДт = Ит.СКД(); 
                СуммаКт = Ит.СКК();
                
                // Выводим строку, если есть ненулевые остатки
                Если (СуммаДт <> 0) Или (СуммаКт <> 0) Тогда
                    Таб.ВывестиСекцию(ОблСтрока);
                КонецЕсли;
                
            КонецЦикла; 
        КонецЦикла;    
    КонецЦикла;
    
    Таб.ТолькоПросмотр(1);
    Таб.Показать("Бухгалтерские остатки по счету 60");
КонецПроцедуры

---

Часть 4. Советы по оптимизации алгоритмов выгрузки

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

← На главную