В процессе автоматической загрузки данных из внешних файлов DBF в информационные базы 1С:Предприятие 7.7 (особенно в файловом режиме) периодически возникает неприятная ситуация: в журнале появляется новый документ с номером, датой и общими реквизитами, однако данные шапки и строки табличной части оказываются абсолютно пустыми. При этом стандартный журнал регистрации не фиксирует никаких ошибок времени выполнения.
Разберем детально, почему возникает подобный сбой, как устроено хранение документов в файловой 1С 7.7 и как правильно доработать алгоритм загрузки, чтобы исключить появление «фантомных» документов.
Чтобы понять причину проблемы, проанализируем физическую структуру хранения документов в таблицах формата DBF платформы 1С 7.7:
1SJOURN.DBF): здесь хранятся дата, время, вид документа, номер, признак проведенности/пометки на удаление, автор и общие реквизиты.DH*.DBF): хранит уникальные реквизиты шапки конкретного вида документа.DT*.DBF): содержит строки, привязанные к документу по его внутреннему идентификатору IDDOC.Если в коде обработки отсутствует явное управление транзакциями, платформа выполняет физическую запись в эти таблицы последовательно. При возникновении скрытого исключения (например, при чтении данных из файла, ненайденном элементе справочника или сбое файловой блокировки) управление может перейти к вызову Записать() до того, как строки были фактически добавлены, либо произойдет частичная фиксация записи только в 1SJOURN.DBF.
Главная ошибка многих автоматических обработок — безусловный вызов метода Записать() даже в тех случаях, когда табличная часть осталась пустой из-за отсутствия соответствий в справочниках или ошибок структуры исходного DBF.
Введем строгую проверку: документ сохраняется только тогда, когда успешно заполнены ключевые реквизиты шапки и добавлена хотя бы одна строка. Разберем правильную структуру кода:
// Открываем файл обмена
ДБФ = СоздатьОбъект("XBase");
ДБФ.ОткрытьФайл(ИмяФайлаDBF,, 1); // Открытие только для чтения
Если ДБФ.Открыта() = 0 Тогда
ЗаписьЖурнала("ОШИБКА: Не удалось открыть файл " + ИмяФайлаDBF);
Возврат;
КонецЕсли;
Док = СоздатьОбъект("Документ.ЗаявкаПокупателя");
Док.Новый();
Док.ДатаДок = ТекущаяДата();
// Заполняем реквизиты шапки
СпрКонтр = СоздатьОбъект("Справочник.Контрагенты");
Если СпрКонтр.НайтиПоКоду(СокрЛП(ДБФ.KOD_KONTR)) = 1 Тогда
Док.Контрагент = СпрКонтр.ТекущийЭлемент();
Иначе
ЗаписьЖурнала("ВНИМАНИЕ: Контрагент не найден по коду " + ДБФ.KOD_KONTR);
КонецЕсли;
// Обходим строки файла
СпрНом = СоздатьОбъект("Справочник.Номенклатура");
ДБФ.Первая();
Пока ДБФ.ВКонце() = 0 Цикл
Если СпрНом.НайтиПоКоду(СокрЛП(ДБФ.ARTIKUL)) = 1 Тогда
Док.НоваяСтрока();
Док.Товар = СпрНом.ТекущийЭлемент();
Док.Количество = ДБФ.KOLVO;
Док.Цена = ДБФ.PRICE;
Док.Сумма = Док.Количество * Док.Цена;
Иначе
ЗаписьЖурнала("ВНИМАНИЕ: Товар с кодом " + ДБФ.ARTIKUL + " не найден в базе!");
КонецЕсли;
ДБФ.Следующая();
КонецЦикла;
ДБФ.ЗакрытьФайл();
// Валидация перед записью
Если ПустоеЗначение(Док.Контрагент) = 1 Тогда
ЗаписьЖурнала("ОТМЕНА: Документ не записан, так как не заполнен контрагент.");
ИначеЕсли Док.КоличествоСтрок() = 0 Тогда
ЗаписьЖурнала("ОТМЕНА: В документе нет строк! Запись отменена.");
Иначе
НачатьТранзакцию();
Попытка
Док.Записать();
ЗафиксироватьТранзакцию();
ЗаписьЖурнала("УСПЕХ: Документ " + Док.НомерДок + " успешно создан.");
Исключение
ОтменитьТранзакцию();
ЗаписьЖурнала("ОШИБКА ТРАНЗАКЦИИ: Не удалось записать документ: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
Стандартный журнал регистрации 1С 7.7 не сохраняет низкоуровневые события фоновых процедур и скрытые исключения. При автоматическом обмене критически важно вести собственный текстовый лог-файл, в который фиксируется каждый этап обработки данных.
Сформулируем основные правила построения информативного лога:
Попытка ... Исключение не должны оставаться пустыми; текст ошибки обязательно пишется в лог через ОписаниеОшибки().[ИНФО], [ВНИМАНИЕ], [ОШИБКА].Посмотрим на пример структуры вспомогательной функции для записи в лог:
Процедура ЗаписьВЛог(ТекстСообщения, ПутьКЛогу)
Текст = СоздатьОбъект("Текст");
Если ФС.СуществуетФайл(ПутьКЛогу) = 1 Тогда
Текст.Открыть(ПутьКЛогу);
КонецЕсли;
СтрокаЛога = "" + ТекущаяДата() + " " + ТекущееВремя() + ": " + ТекстСообщения;
Текст.ДобавитьСтроку(СтрокаЛога);
Текст.Записать(ПутьКЛогу);
КонецПроцедуры
Если код валидации корректен, но пропуски данных продолжают возникать спорадически, причину следует искать в файловой подсистеме операционной системы и целостности таблиц DBF/CDX:
.CDX из каталога ИБ и запустим 1С 7.7 в монопольном режиме для их автоматического пересоздания.DH*.DBF или DT*.DBF при попытке записи. Каталог базы и папки обмена необходимо обязательно добавить в исключения сканирования.DBF-таблиц.