Как исправить ошибку выгрузки остатков по забалансовому счету 002.1 в 1С 7.7

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

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

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

Выявление ключевых причин сбоя в исходном коде

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

Ошибка 1. Несоответствие состава субконто на счете 002.1

В типовой конфигурации «1С:Бухгалтерия 7.7» забалансовый счет 002.1 имеет строго определенный набор субконто. Как правило, их всего три:

  1. Контрагенты
  2. Материалы (Номенклатура)
  3. Места хранения (Склады)

В исходном коде обработки мы видим попытку инициализировать сразу пять видов субконто:


Ит.ИспользоватьСубконто(ВидыСубконто.Материалы); // 1
Ит.ИспользоватьСубконто(ВидыСубконто.Контрагенты); // 2
Ит.ИспользоватьСубконто(ВидыСубконто.Договоры); // 3 - отсутствует на счете 002.1!
Ит.ИспользоватьСубконто(ВидыСубконто.ОбъектыСтроительства); // 4 - отсутствует на счете 002.1!
Ит.ИспользоватьСубконто(ВидыСубконто.МестаХранения); // 5

Выясним причину, почему это ломает весь алгоритм. Когда мы строим запрос с помощью метода ВыполнитьЗапрос() и указываем субконто, которых физически нет на выбранном счете, система 1С 7.7 на этих уровнях выборки возвращает пустое множество. Вложенные циклы Пока Ит.ПолучитьСубконто(3) = 1 и Пока Ит.ПолучитьСубконто(4) = 1 просто не выполняются, из-за чего выполнение программы прерывается, и код никогда не доходит до записи данных в DBF.

Ошибка 2. Путаница с индексами субконто при обращении к данным

В платформе 1С 7.7 метод Ит.Субконто(N) возвращает объект субконто по порядковому номеру его объявления в методах ИспользоватьСубконто(), а не по его физическому смыслу или настройкам в плане счетов.

Рассмотрим порядок инициализации в коде автора:

  1. Первым объявлено ВидыСубконто.Материалы
  2. Вторым объявлено ВидыСубконто.Контрагенты

При этом далее по тексту программы автор пытается получить значения следующим образом:


Контрагент = Ит.Subkonto(1); // Здесь фактически будет получен Материал!
Номенклатура = Ит.Subkonto(4); // Здесь произойдет ошибка, так как 4-го уровня не существует

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

Ошибка 3. Игнорирование забалансового учета (метод Опции)

По умолчанию объект БухгалтерскиеИтоги рассчитывает остатки и обороты только по балансовым счетам. Чтобы включить забалансовые счета (к которым относится 002.1) в расчеты, необходимо явно использовать метод Опции(). Посмотрим на синтаксис этого метода:

Опции(ПризнакЗабаланса, ПризнакОборотныхСубконто)

Где параметр ПризнакЗабаланса должен быть равен 1 (включать суммы по забалансовым счетам).

Важное правило: Метод Ит.Опции(1) должен вызываться строго ДО вызова метода Ит.ВыполнитьЗапрос(). Если вызвать его позже, итоги будут сформированы без забалансового учета, и выборка останется пустой.

Ошибка 4. Преждевременная фильтрация нулевых остатков

В исходном коде на каждом уровне вложенности циклов по субконто встречается условие:


Если (Ит.СКД("С") = 0) и (Ит.СКК("С") = 0) Тогда 
    Продолжить; 
КонецЕсли;

Проанализируем эту ситуацию. В 1С 7.7 на верхних уровнях группировки (например, по Контрагенту) остатки суммируются по всем подчиненным элементам. Если у одного контрагента числится один материал с остатком +1000 рублей, а второй — с остатком -1000 рублей (например, из-за пересортицы), то на уровне Контрагента общий итог будет равен нулю. Программа выполнит команду Продолжить на верхнем цикле и полностью пропустит этого контрагента, хотя детальные остатки по материалам у него есть. Проверку остатков нужно выполнять только на самом глубоком уровне детализации!

Ошибка 5. Избыточный обход по счетам

Если в параметрах метода ВыполнитьЗапрос() мы жестко передаем конкретный счет ("002.1"), то использование конструкции:


Ит.ВыбратьСчета();
Пока Ит.ПолучитьСчет() = 1 Цикл

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

Пошаговое руководство по созданию корректного алгоритма выгрузки

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

Шаг 1. Инициализация DBF-файла

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


ДБФ = СоздатьОбъект("XBase");
ДБФ.ДобавитьПоле("Shcet", "S", 15, );
ДБФ.ДобавитьПоле("StKod", "S", 9, );
ДБФ.ДобавитьПоле("KONTR", "S", 150, );
ДБФ.ДобавитьПоле("KontrIdent", "S", 150, );
ДБФ.ДобавитьПоле("MatKod", "S", 9, );
ДБФ.ДобавитьПоле("MatName", "S", 150, );
ДБФ.ДобавитьПоле("MatIdent", "S", 150, );
ДБФ.ДобавитьПоле("MatED", "S", 50, );
ДБФ.ДобавитьПоле("Sklad", "S", 100, );
ДБФ.ДобавитьПоле("SkladKOD", "S", 45, );
ДБФ.ДобавитьПоле("MOL", "S", 100, );
ДБФ.ДобавитьПоле("Summa", "N", 15, 2);
ДБФ.ДобавитьПоле("Kol", "N", 15, 5);

ДБФ.СоздатьФайл("D:\1cBases\temp\Обработки\002_1.DBF");

Шаг 2. Подготовка и выполнение бухгалтерского запроса

Создадим объект бухгалтерских итогов, установим опции забалансового учета и укажем верные субконто в строгом порядке: Контрагенты -> Материалы -> МестаХранения.


Ит = СоздатьОбъект("БухгалтерскиеИтоги");

// Включаем забалансовый учет ДО выполнения запроса
Ит.Опции(1, 0); 

// Инициализируем только существующие субконто счета 002.1
Ит.ИспользоватьСубконто(ВидыСубконто.Контрагенты);   // Будет соответствовать индексу 1
Ит.ИспользоватьСубконто(ВидыСубконто.Материалы);      // Будет соответствовать индексу 2
Ит.ИспользоватьСубконто(ВидыСубконто.МестаХранения);  // Будет соответствовать индексу 3

// Проверяем заполнение даты выгрузки
Если ПустоеЗначение(Дата1) = 1 Тогда
    Дата1 = РабочаяДата();
КонецЕсли;

СтрокаУслСчета = "002.1";

// Выполняем запрос по счету за указанный день
Если Ит.ВыполнитьЗапрос(Дата1, Дата1, СтрокаУслСчета) = 0 Тогда
    Сообщить("Ошибка выполнения запроса по счету " + СтрокаУслСчета, "!");
    Возврат;
КонецЕсли;

Шаг 3. Реализация циклов обхода субконто и выгрузки в DBF

Организуем трехступенчатый цикл обхода. Обратите внимание, что проверку на нулевые остатки мы перенесли в самый конец — непосредственно перед добавлением записи в DBF. Также учтем, что реквизит МОЛ (Материально ответственное лицо) у справочника Склады может быть периодическим, поэтому получать его значение нужно на конкретную дату.


// Начинаем выборку с 1-го уровня (Контрагенты)
Ит.ВыбратьСубконто(1);
Пока Ит.ПолучитьСубконто(1) = 1 Цикл
    Контрагент = Ит.Субконто(1);
    
    // Переходим на 2-й уровень (Материалы)
    Ит.ВыбратьСубконто(2);
    Пока Ит.ПолучитьСубконто(2) = 1 Цикл
        Номенклатура = Ит.Субконто(2);
        
        // Переходим на 3-й уровень (Места хранения / Склады)
        Ит.ВыбратьСубконто(3);
        Пока Ит.ПолучитьСубконто(3) = 1 Цикл
            Склад = Ит.Субконто(3);
            
            // Получаем детальные остатки по текущему разрезу аналитики
            ОстатокСумма = Ит.СКД("С") - Ит.СКК("С");
            ОстатокКол = Ит.СКД("К") - Ит.СКК("К");
            
            // Исключаем пустые остатки во избежание захламления файла
            Если (ОстатокСумма = 0) И (ОстатокКол = 0) Тогда
                Продолжить;
            КонецЕсли;
            
            // Добавляем запись в DBF-файл
            ДБФ.Добавить();
            
            ДБФ.Shcet = СтрокаУслСчета;
            ДБФ.StKod = Контрагент.Код;
            ДБФ.KONTR = Контрагент.Наименование;
            ДБФ.KontrIdent = ЗначениеВСтрокуВнутр(Контрагент);
            
            ДБФ.Summa = ОстатокСумма;
            ДБФ.Kol = ОстатокКол;
            
            ДБФ.MatKod = Номенклатура.Код;
            ДБФ.MatName = Номенклатура.Наименование;
            ДБФ.MatIdent = ЗначениеВСтрокуВнутр(Номенклатура);
            
            // Обработка базовой единицы измерения
            Если ПустоеЗначение(Номенклатура.БазоваяЕдиница) = 0 Тогда
                ДБФ.MatED = Номенклатура.БазоваяЕдиница.Наименование;
                ДБФ.MatEDKOD = Номенклатура.БазоваяЕдиница.Код;
            КонецЕсли;
            
            ДБФ.Sklad = Склад.Наименование;
            ДБФ.SkladKOD = Склад.Код;
            
            // Получаем периодическое значение МОЛ на дату выгрузки
            Если ПустоеЗначение(Склад.МОЛ) = 0 Тогда
                ДБФ.MOL = Склад.МОЛ.Получить(Дата1).Наименование;
            КонецЕсли;
            
            ДБФ.Записать();
            
        КонецЦикла; // Конец цикла по складам
    КонецЦикла; // Конец цикла по материалам
КонецЦикла; // Конец цикла по контрагентам

ДБФ.ЗакрытьФайл();
Сообщить("Выгрузка остатков успешно завершена!", "i");

Подведем итоги

Мы полностью переработали алгоритм выгрузки остатков по забалансовому счету 002.1. Исключение неактуальных для данного счета уровней субконто («Договоры» и «Объекты строительства») позволило восстановить корректную работу вложенных циклов. Включение метода Опции(1) обеспечило попадание данных по забалансовым счетам в выборку бухгалтерских итогов, а перенос фильтрации остатков на самый глубокий уровень аналитики гарантирует точность выгружаемых сумм и количеств.

← На главную