Как программно перенести остатки по счету в документ «Операция» в 1С:Бухгалтерия 3.0 и исправить сопутствующие ошибки?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

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

Анализ исходного кода и причин возникновения ошибок

Рассмотрим фрагмент кода, в котором выполняется попытка получить кредитовые остатки по счету 76.09 и перенести их в документ ОперацияБух:


&НаСервере
Процедура ПереносНаСервере()
    
    ДатаОпераций = ТекущаяДата();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ
    |    ХозрасчетныйОстатки.Субконто1,
    |    ХозрасчетныйОстатки.Субконто2,
    |    ХозрасчетныйОстатки.Субконто3 КАК ДокументРасчетов,
    |    ХозрасчетныйОстатки.СуммаОстатокКт КАК Сумма
    |ИЗ
    |    РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами), , ) КАК ХозрасчетныйОстатки
    |ГДЕ
    |    ХозрасчетныйОстатки.СуммаОстатокКт > 0";
    Запрос.УстановитьПараметр("Период", ДатаОпераций);
    
    Попытка
        НачатьТранзакцию();
        Операция = Документы.ОперацияБух.СоздатьДокумент();
        Операция.Дата = ДатаОпераций;
        Операция.Содержание = "ТЕСТ: перенос кредитового остатка со счета 76.09 " + ДатаОпераций;
        Операция.Организация = Справочники.Организации.НайтиПоКоду("000000001");
        Операция.Ответственный = ПараметрыСеанса.ТекущийПользователь;
        Операция.Записать(РежимЗаписиДокумента.Запись);
        
        НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.Регистратор.Установить(Операция.Ссылка);
        НаборЗаписей.Прочитать();
        
        Выборка = Запрос.Выполнить().Выбрать();
        Если Выборка.Следующий() Тогда
            
            НСтрока = НаборЗаписей.Добавить();
            НСтрока.Регистратор = Операция.Ссылка;
            НСтрока.Период = ДатаОпераций;
            НСтрока.Организация = Операция.Организация;
            
            НСтрока.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетДт, НСтрока.СубконтоДт, "Контрагенты", Выборка.Субконто1);
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетДт, НСтрока.СубконтоДт, "Договоры", Выборка.Субконто2);
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетДт, НСтрока.СубконтоДт, "ДокументыРасчетовСКонтрагентами", Выборка.ДокументРасчетов);
            
            НСтрока.СчетКт = ПланыСчетов.Хозрасчетный.ВзаиморасчетыССКТранзитный;
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетКт, НСтрока.СубконтоКт, "Контрагенты", Выборка.Субконто1);
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетКт, НСтрока.СубконтоКт, "Договоры", Выборка.Субконто2);
            БухгалтерскийУчет.УстановитьСубконто(НСтрока.СчетКт, НСтрока.СубконтоКт, "ДокументыРасчетовСКонтрагентами", Выборка.ДокументРасчетов);
            
            НСтрока.Сумма = Выборка.Сумма;
            НСтрока.СуммаНУДт = Выборка.Сумма;
            НСтрока.СуммаНУКт = Выборка.Сумма;
            
        КонецЕсли;  
        НаборЗаписей.Записать();
        ЗафиксироватьТранзакцию();
        ТекстВозврата = ТекстВозврата + ?(ТекстВозврата = "", "", Символы.пс) + ": Создана операция """ + Строка(Операция.Ссылка) + """";
    Исключение
        ОтменитьТранзакцию();
        ЗаписьЖурналаРегистрации("ТЕСТ: перенос кредитового остатка со счета 76.09", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        ТекстВозврата = ТекстВозврата + ?(ТекстВозврата = "", "", Символы.пс) + ": " + ОписаниеОшибки();
    КонецПопытки;
    
КонецПроцедуры

В приведенном коде допущены две ключевые синтаксические и логические ошибки:

  1. Ошибка типизации переменной: Выражение ТекстВозврата = ТекстВозврата + ... вызывает исключение «Преобразование значения к типу Число не может быть выполнено». Если переменная ТекстВозврата не была инициализирована строковым значением (имеет значение Неопределено или тип Число по умолчанию), платформа пытается применить оператор + как математическое сложение, что приводит к ошибке при попытке прибавить строку.
  2. Отсутствие цикла по выборке: Конструкция Если Выборка.Следующий() Тогда считывает ровно одну (первую) строку из результата запроса. Для обработки всех записей остатков необходим цикл Пока Выборка.Следующий() Цикл.

Исправление ошибок и инициализация переменных

Выясним причину первой ошибки: переменная ТекстВозврата должна быть явно объявлена как строка до начала вычислений и блоков обработки исключений:

ТекстВозврата = "";

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


Пока Выборка.Следующий() Цикл
    // Добавление и заполнение строки набора записей
КонецЦикла;

Оптимизация работы с движениями документа «ОперацияБух»

Проанализируем архитектурные особенности конфигурации «1С:Бухгалтерия предприятия 3.0»:

  1. Работа через коллекцию Операция.Движения: Создание отдельного объекта НаборЗаписей и предварительная запись документа через Операция.Записать() создают избыточные обращения к базе данных. Эффективнее использовать коллекцию Операция.Движения.Хозрасчетный, установив флаг Записывать = Истина. В этом случае документ и его проводки сохраняются за один вызов Операция.Записать().
  2. Заполнение реквизита СуммаОперации: Если реквизит СуммаОперации в документе ручной операции не заполнен, в журнале документов сумма операции будет равна нулю. Значение следует накапливать в цикле и передавать в шапку документа.
  3. Отбор по организации в запросе: В параметрах виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.Остатки необходимо явно указывать условие по организации, чтобы исключить выборку данных чужих организаций в многофирменной базе.
  4. Безопасное управление транзакцией: В блоке Исключение перед отменой транзакции следует проверять Если ТранзакцияАктивна() Тогда, чтобы избежать падения программы при повторной отмене.

Итоговый корректный код переноса остатков

Посмотрим на исправленный и оптимизированный вариант процедуры:


&НаСервере
Процедура ПереносОстатковНаСервере()
    
    ТекстВозврата = "";
    ДатаОпераций = ТекущаяДата();
    
    ОрганизацияСсылка = Справочники.Организации.НайтиПоКоду("000000001");
    Если ОрганизацияСсылка.Пустая() Тогда
        ВызватьИсключение "Организация с указанным кодом не найдена в базе данных.";
    КонецЕсли;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    ХозрасчетныйОстатки.Субконто1 КАК Контрагент,
    |    ХозрасчетныйОстатки.Субконто2 КАК Договор,
    |    ХозрасчетныйОстатки.Субконто3 КАК ДокументРасчетов,
    |    ХозрасчетныйОстатки.СуммаОстатокКт КАК Сумма
    |ИЗ
    |    РегистрБухгалтерии.Хозрасчетный.Остатки(
    |        &Период,
    |        Счет = ЗНАЧЕНИЕ(ПланСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами),
    |        ,
    |        Организация = &Организация) КАК ХозрасчетныйОстатки
    |ГДЕ
    |    ХозрасчетныйОстатки.СуммаОстатокКт > 0";
    
    Запрос.УстановитьПараметр("Период", ДатаОпераций);
    Запрос.УстановитьПараметр("Организация", ОрганизацияСсылка);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если РезультатЗапроса.Пустой() Тогда
        ТекстВозврата = "Остатки по счету для переноса не обнаружены.";
        Возврат;
    КонецЕсли;
    
    НачатьТранзакцию();
    Попытка
        Операция = Документы.ОперацияБух.СоздатьДокумент();
        Операция.Дата = ДатаОпераций;
        Операция.Организация = ОрганизацияСсылка;
        Операция.Ответственный = ПараметрыСеанса.ТекущийПользователь;
        Операция.Содержание = "Перенос кредитового остатка со счета 76.09 на счет ВзаиморасчетыССКТранзитный";
        
        ДвиженияХозрасчетный = Операция.Движения.Хозрасчетный;
        ДвиженияХозрасчетный.Записывать = Истина;
        
        ИтоговаяСумма = 0;
        Выборка = РезультатЗапроса.Выбрать();
        
        Пока Выборка.Следующий() Цикл
            
            Проводка = ДвиженияХозрасчетный.Добавить();
            Проводка.Период = ДатаОпераций;
            Проводка.Организация = ОрганизацияСсылка;
            
            // Заполнение Дебета
            Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ПрочиеРасчетыСРазнымиДебиторамиИКредиторами;
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетДт, Проводка.СубконтоДт, "Контрагенты", Выборка.Контрагент);
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетДт, Проводка.СубконтоДт, "Договоры", Выборка.Договор);
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетДт, Проводка.СубконтоДт, "ДокументыРасчетовСКонтрагентами", Выборка.ДокументРасчетов);
            
            // Заполнение Кредита
            Проводка.СчетКт = ПланыСчетов.Хозрасчетный.ВзаиморасчетыССКТранзитный;
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетКт, Проводка.СубконтоКт, "Контрагенты", Выборка.Контрагент);
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетКт, Проводка.СубконтоКт, "Договоры", Выборка.Договор);
            БухгалтерскийУчет.УстановитьСубконто(Проводка.СчетКт, Проводка.СубконтоКт, "ДокументыРасчетовСКонтрагентами", Выборка.ДокументРасчетов);
            
            // Суммовые показатели
            Проводка.Сумма = Выборка.Сумма;
            Проводка.СуммаНУДт = Выборка.Сумма;
            Проводка.СуммаНУКт = Выборка.Сумма;
            
            ИтоговаяСумма = ИтоговаяСумма + Выборка.Сумма;
            
        КонецЦикла;
        
        Операция.СуммаОперации = ИтоговаяСумма;
        Операция.Записать(РежимЗаписиДокумента.Запись);
        
        ЗафиксироватьТранзакцию();
        ТекстВозврата = "Успешно создан документ: " + Строка(Операция.Ссылка) + " на сумму " + Строка(ИтоговаяСумма);
        
    Исключение
        Если ТранзакцияАктивна() Тогда
            ОтменитьТранзакцию();
        КонецЕсли;
        
        ЗаписьЖурналаРегистрации("Перенос остатков", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        ТекстВозврата = "Ошибка при переносе остатков: " + ОписаниеОшибки();
    КонецПопытки;
    
КонецПроцедуры

Важное замечание: В типовой конфигурации «1С:Бухгалтерия предприятия» взаиморасчеты с контрагентами ведутся с использованием специализированных регистров подсистем (НДС, УСН). Если перенос остатков по взаиморасчетам выполняется ручной операцией без движений по этим регистрам, в дальнейшем могут возникнуть расхождения при автоматическом зачете авансов и формировании регламентированной отчетности. Для штатного переноса расчетов между договорами и контрагентами рекомендуется использовать документ «Корректировка долга».

← На главную