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