При переносе данных и разработке обработок загрузки из внешних источников (например, DBF-файлов учетных программ) часто возникает задача создания единого документа с несколькими строками вместо дробления данных на отдельные документы. В платформе 1С:Предприятие 7.7 начинающие разработчики нередко сталкиваются с ошибками при переходе от заполнения реквизитов шапки к наполнению табличной части. Разберем типичную проблему, проанализируем причины ее возникновения и рассмотрим корректный алгоритм формирования строк документа.
Проанализируем фрагмент кода, который вызвал затруднение при попытке сформировать акт с двумя строками (одна строка со ставкой НДС, вторая — льготируемая без НДС):
ДокАкт.ВыбратьСтроки;
Пока ДокАкт.ПолучитьСтроку = 1 Цикл
ДокАкт.НоваяСрока;
// Заполнение реквизитов первой строки...
ДокАкт.НоваяСтрока;
// Заполнение реквизитов второй строки...
ДокАкт.Записать;
ДокАкт.Провести;
Прервать;
КонецЦикла;
В приведенном коде допущены критические логические и синтаксические ошибки:
ВыбратьСтроки() и ПолучитьСтроку() предназначены исключительно для чтения уже записанных строк существующего документа. У только что созданного через Новый() документа табличная часть пуста. Метод ПолучитьСтроку() сразу возвращает 0, тело цикла Пока ... Цикл не выполняется ни разу, и строки вообще не создаются.ДокАкт.НоваяСрока; содержит опечатку в названии метода (пропущена буква «т»), что привело бы к ошибке времени выполнения.Записать() и Провести() были помещены внутрь цикла до завершения обработки структуры данных.Для добавления строк в табличную часть нового документа цикл перебора строк не требуется. Достаточно последовательно вызывать метод НоваяСтрока(), заполнять реквизиты текущей строки и только после добавления всех строк выполнять запись документа.
Рассмотрим пошагово правильную структуру кода:
Если (ПустоеЗначение(ДБФ.DATA_VYDAC) = 0) и ((ДБФ.LG_CH_TC <> 0) и (ДБФ.ST_OBL_NDS <> 0)) Тогда
// 1. Инициализация нового документа и заполнение шапки
ДокАкт.Новый();
ДокАкт.НомерДок = СокрЛП(Строка(ДБФ.REG_NOM));
ДокАкт.ДатаДок = ДБФ.DATA_VYDAC;
// Включение режима табличной части (если предусмотрено конфигурацией)
ДокАкт.ФлагТаблица = 1;
СпрВидДокЭСЧФ.НайтиПоКоду("606");
ДокАкт.ВидДокументаЭСЧФ = СпрВидДокЭСЧФ.ТекущийЭлемент();
ДокАкт.ВидОказанияУслуг = Перечисление.ВидОказанияУслуг.ОказаниеУслуг;
ДокАкт.СчетПокупателя = СчетПоКоду("62.1.1");
ДокАкт.СчетРеализации = СчетПоКоду("90.1.1");
// Поиск контрагента по УНН
Если СпрКонтр.НайтиПоРеквизиту("УНН", ДБФ.UNN_ZAKAZC, 1) = 1 Тогда
ДокАкт.Контрагент = СпрКонтр.ТекущийЭлемент();
Иначе
Предупреждение("У заказчика неверно указан УНН в акте №" + СокрЛП(Строка(ДБФ.REG_NOM)));
Возврат;
КонецЕсли;
// Поиск договора по номеру
СпрДог.ИспользоватьВладельца(СпрКонтр.ТекущийЭлемент());
Если СпрДог.НайтиПоРеквизиту("НомерДоговора", СокрЛП(ДБФ.REG_NOM), 1) = 1 Тогда
ДокАкт.Договор = СпрДог.ТекущийЭлемент();
КонецЕсли;
// Определение аналитики (субконто)
ДокАкт.НазначитьТип("шСубконто1", "Справочник.ВидыДеятельности");
ДокАкт.шСубконто1 = ВидДеят.ТекущийЭлемент();
ДокАкт.НазначитьТип("шСубконто2", "Справочник.ВидыВариантовРеализации");
Если (СтрЧислоВхождений(Строка(ДБФ.REG_NOM), "-42") = 1) или (СтрЧислоВхождений(Строка(ДБФ.REG_NOM), "-51") = 1) Тогда
ВидВарРеализ.НайтиПоКоду(2);
Иначе
ВидВарРеализ.НайтиПоКоду(1);
КонецЕсли;
ДокАкт.шСубконто2 = ВидВарРеализ.ТекущийЭлемент();
СпрУслуги.НайтиПоКоду(СокрЛП(Строка(ДБФ.REG_NOM)));
ДокАкт.шУслуга = СпрУслуги.ТекущийЭлемент();
// 2. Добавление первой строки (облагаемая НДС часть)
ДокАкт.НоваяСтрока();
ДокАкт.НаименованиеУслуги = ДокАкт.шУслуга;
ДокАкт.Субконто1 = ДокАкт.шСубконто1;
ДокАкт.Субконто2 = ДокАкт.шСубконто2;
ДокАкт.СуммаБезНДС = ДБФ.ST_OBL_NDS;
ДокАкт.СуммаНДС = ДБФ.SUMMA_NDS;
СтНДС.НайтиПоКоду("1"); // Ставка НДС 18% или 20%
ДокАкт.СтавкаНДС = СтНДС.ТекущийЭлемент();
ДокАкт.СуммаСНДС = ДБФ.ST_OBL_NDS + ДБФ.SUMMA_NDS;
ДокАкт.СуммаВсего = ДБФ.ST_OBL_NDS + ДБФ.SUMMA_NDS;
// 3. Добавление второй строки (льготируемая часть без НДС)
ДокАкт.НоваяСтрока();
ДокАкт.НаименованиеУслуги = ДокАкт.шУслуга;
ДокАкт.Субконто1 = ДокАкт.шСубконто1;
ДокАкт.Субконто2 = ДокАкт.шСубконто2;
ДокАкт.СуммаБезНДС = ДБФ.LG_CH_TC;
ДокАкт.СуммаНДС = 0;
СтНДС.НайтиПоКоду("5"); // Без НДС
ДокАкт.СтавкаНДС = СтНДС.ТекущийЭлемент();
ДокАкт.СуммаСНДС = ДБФ.LG_CH_TC;
ДокАкт.СуммаВсего = ДБФ.LG_CH_TC;
// 4. Запись и проведение готового документа со всеми строками
ДокАкт.Записать();
ДокАкт.Провести();
КонецЕсли;
Разберем ключевые технические нюансы, которые необходимо учитывать при работе с объектами метаданных и файлами DBF:
Новый(), а перезаписывается существующий объект, перед наполнением необходимо очистить его табличную часть. В платформе 7.7 нет метода Очистить(), поэтому используется цикл:
Пока ДокАкт.КоличествоСтрок() > 0 Цикл
ДокАкт.УдалитьСтроку(1);
КонецЦикла;
СтрДлина(число(ДБФ.DATA_VYDAC)) нестабильна, так как передача нечисловых символов или пустой строки приведет к ошибке приведения типов. Безопаснее проверять заполненность даты через функцию ПустоеЗначение(ДБФ.DATA_VYDAC) = 0.ФлагТаблица = 1 переключает видимость табличной части, типовые алгоритмы проведения или модули выгрузки ЭСЧФ могут по-прежнему считывать итоговые суммы из реквизитов шапки (шСуммаВсего, шСуммаНДС). При программном формировании документа рекомендуется явно заполнять реквизиты шапки суммой по всем добавленным строкам.СпрКонтр = СоздатьОбъект("Справочник.Контрагенты");) следует выполнять до начала цикла обхода DBF-файла. Это существенно ускорит выполнение загрузки больших объемов данных.