Импорт справочников из Инфо-Предприятие 1.91 в БП2.0/ЗУП2.5 (из файлов *.db или *.xls/*.xlsx)

Опубликовал q_i в раздел Обработки - Обработка справочников

Обработка для импорта справочников Контрагенты, Номенклатура, ОсновныеСредства и ФизическиеЛица из DB-файлов Инфо-Предприятие 1.91 или из DB-файлов, сохранённых как файлы MS Excel (XLS/XLSX-файлы).

Проверялось на: Бухгалтерия Предприятия 2.0.65.3, Зарплата и Управление Персоналом 2.5.98.1.

В рамках проекта по переводу клиента с Инфо-Предприятие 1.91 на 1С:БП2.0+1С:ЗУП2.5 возникла задача по автоматическому переносу основных справочников. Готовое решение не нашёл, поэтому написал данную обработку.

Обработка умеет загружать справочники Контрагенты, Номенклатура, ОсновныеСредства и ФизическиеЛица как из DB-файлов Инфо-Предприятие (СУБД Paradox), так и из DB-файлов, сохранённых в формате MS Excel (XLS/XLSX-файлов).

Чтение DB-файлов работает на порядок быстрее, чем XLS/XLSX, но у меня оно отработало не на всех компьютерах, на которых пробовал запускать обработку. Не знаю точно, действительно ли это оказало влияние, но на тех компьютерах, на которых чтение DB-файлов отработало, был установлен BDE.

Теперь немного про код самой обработки.

Была написана пара универсальных функций для чтения данных: 1) из DB-файла (через ADO) и 2) из файла Excel. Обе функции в качестве параметра получают полное имя файла и возвращают таблицу значений, которая содержит все данные, прочитанные из этого DB-/XLS(X)-файла. Имена колонок возвращаемой таблицы значений совпадают с именами колонок DB-файла. В случае чтения из файла MS Excel, имена колонок берутся из первой строки таблицы.

Функция чтения из DB-файла в таблицу значений:

Функция ПолучитьТаблицуИзФайлаПарадокс(ИмяФайла)
	
	ТЗ = Новый ТаблицаЗначений;
	
	Файл = Новый Файл(ИмяФайла);
	
	СтрокаПодключения = "Driver={Microsoft Paradox Driver (*.db )};DefaultDir=" + Файл.Путь + ";CollatingSequence=ASCII";
	
	ПодключениеАДОДБ = Новый COMОбъект("ADODB.Connection");
	ПодключениеАДОДБ.Open(СтрокаПодключения);
	
	ТекстЗапроса = "SELECT * FROM " + Файл.ИмяБезРасширения;
	ВыборкаАДОДБ = ПодключениеАДОДБ.Execute(ТекстЗапроса);
	
	ВыборкаАДОДБ.MoveFirst();
	
	КолвоКолонок = ВыборкаАДОДБ.Fields.Count;
	
	Если КолвоКолонок = 0 Тогда
		ВызватьИсключение "Ошибка чтения файла " + ИмяФайла + ": таблица не содержит колонок!";
	КонецЕсли; 
	
	СоответствиеКолонок = Новый Соответствие; 
	Для НомКол = 0 По КолвоКолонок - 1 Цикл
		ИмяКолонки = ВыборкаАДОДБ.Fields(НомКол).Name;
		ТЗ.Колонки.Добавить(ИмяКолонки);
		СоответствиеКолонок.Вставить(НомКол, ИмяКолонки);
	КонецЦикла; 

	Пока НЕ ВыборкаАДОДБ.EOF Цикл
		НоваяСтрока = ТЗ.Добавить(); 
		Для НомКол = 0 По КолвоКолонок - 1 Цикл
			НоваяСтрока[СоответствиеКолонок.Получить(НомКол)] = ВыборкаАДОДБ.Fields(НомКол).Value;
		КонецЦикла;
		ВыборкаАДОДБ.MoveNext();
	КонецЦикла; 
	
	Возврат ТЗ; 
	
КонецФункции

Функция чтения из XLS/XLSX-файла в таблицу значений:

Функция ПолучитьТаблицуИзФайлаЕксель(ИмяФайла)
	
	ТЗ = Новый ТаблицаЗначений;
	
	Ексель = Новый COMОбъект("Excel.Application");
	КнигаЕксель = Ексель.Workbooks.Open(ИмяФайла, Ложь, Истина);
	ЛистЕксель = КнигаЕксель.Worksheets(1);
	
	// читаем первую строку с заголовками столбцов
	НомКол = 1;
	СоответствиеКолонок = Новый Соответствие; 
	Пока Истина Цикл
		ТекЗнач = СокрЛП(ЛистЕксель.Cells(1, НомКол).Value);
		Если ПустаяСтрока(ТекЗнач) Тогда
			Прервать;
		КонецЕсли;
		ТЗ.Колонки.Добавить(ТекЗнач);
		СоответствиеКолонок.Вставить(НомКол, ТекЗнач);
		НомКол = НомКол + 1; 
	КонецЦикла;
	
	КолвоКолонок = ТЗ.Колонки.Количество();
	
	Если КолвоКолонок = 0 Тогда
		ВызватьИсключение "Ошибка чтения таблицы Excel " + ИмяФайла + ": в первой строке не найдены заголовки столбцов!";
	КонецЕсли; 
	
	НомСтр = 2;
	Пока Истина Цикл
		ЕстьДанные = Ложь;
		СтруктураДанных = Новый Структура;
		Для НомКол = 1 По КолвоКолонок Цикл
			ИмяКолонки = СоответствиеКолонок.Получить(НомКол);
			ТекЗнач = ЛистЕксель.Cells(НомСтр, НомКол).Value;
			Если НЕ ПустаяСтрока(ТекЗнач) Тогда
				ЕстьДанные = Истина;
			КонецЕсли; 
			СтруктураДанных.Вставить(ИмяКолонки, ТекЗнач);
		КонецЦикла;
		Если НЕ ЕстьДанные Тогда
			Прервать;
		КонецЕсли; 
		НоваяСтрока = ТЗ.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СтруктураДанных);
		НомСтр = НомСтр + 1; 
	КонецЦикла; 
	
	Возврат ТЗ; 
	
КонецФункции

Для унификации вызвова функции чтения данных используется функция ПолучитьТаблицуИзФайла(), которая в зависимости от расширения файла вызывает одну из вышеприведённых функций:

Функция ПолучитьТаблицуИзФайла(ИмяФайла)
	
	Попытка
		Файл = Новый Файл(ИмяФайла);
		Если Лев(ВРег(Файл.Расширение), 4) = ".XLS" Тогда
			Возврат ПолучитьТаблицуИзФайлаЕксель(ИмяФайла);
		ИначеЕсли ВРег(Файл.Расширение) = ".DB" Тогда
			Возврат ПолучитьТаблицуИзФайлаПарадокс(ИмяФайла);
		Иначе 
			Сообщить("ПолучитьТаблицуИзФайла(): загрузка из файла " + ИмяФайла 
				+ " невозможна! Неизвестный тип файла: " + Файл.Расширение + "!", СтатусСообщения.Важное);
		КонецЕсли;
	Исключение
	    Сообщить("Ошибка загрузки данных из файла " + ИмяФайла + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
	КонецПопытки; 
	
	Возврат Неопределено;
	
КонецФункции

Далее на основе прочитанных данных создаются необходимые элементы справочников и заполняются данные в регистрах сведений.

Для примера рассмотрим загрузку справочника ФизическиеЛица. При нажатии соответствующей кнопки "Загрузить" (см.скриншот) вызывается процедура-обработчик КнопкаЗагрузитьСотрудникиНажатие():

Процедура КнопкаЗагрузитьСотрудникиНажатие(Элемент)

	ИмяФайла = ИмяФайлаСотрудники;
	НазваниеФайла = "Сотрудники";
	
	Если НЕ ПроверитьИмяФайла(ИмяФайла, НазваниеФайла) Тогда
		Возврат;
	КонецЕсли; 
	
	Сообщить("Начало загрузки: " + ТекущаяДата());
	
	Состояние("Чтение данных из файла...");
	ТаблицаДанных = ПолучитьТаблицуИзФайла(ИмяФайла);
	
	Колво = 0;
	КолвоВсего = ТаблицаДанных.Количество();
	
	Для Каждого СтрокаТаблицы Из ТаблицаДанных Цикл
		ОбработкаПрерыванияПользователя();
		Колво = Колво + 1; 
		ПроцентЗагружено = Цел(Колво / КолвоВсего * 100);
		Состояние("[" + Строка(ПроцентЗагружено) + "%] " + СтрокаТаблицы.famSotr);
		ЗагрузитьФизЛицо(СтрокаТаблицы, ФлагПерезаписыватьСуществующие);
	КонецЦикла; 
	
	Сообщить("Окончание загрузки: " + ТекущаяДата());
	
КонецПроцедуры

В этой процедуре вызывается ранее рассмотренная функция ПолучитьТаблицуИзФайла(ИмяФайла), которая возвращает таблицу значений с данными для загрузки, а затем в цикле по строкам полученной таблицы значений вызывается процедура ЗагрузитьФизЛицо(), которая непосредственно осуществляет создание элемента справочника ФизическиеЛица и сопутствующих ему записей в регистрах сведений (эта процедура работает как в БП2.0, так и в ЗУП2.5):

Процедура ЗагрузитьФизЛицо(Данные, Перезаписывать) Экспорт 
	
	Комментарий = СформироватьКомментарий(Данные, "ID");
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ФизическиеЛица.Ссылка
	|ИЗ
	|	Справочник.ФизическиеЛица КАК ФизическиеЛица
	|ГДЕ
	|	ФизическиеЛица.Комментарий ПОДОБНО &Комментарий";
	Запрос.УстановитьПараметр("Комментарий", Комментарий);
	РезультатЗапроса = Запрос.Выполнить();
	
	ТекОбъект = Неопределено;
	
	Если НЕ РезультатЗапроса.Пустой() Тогда
		Если НЕ Перезаписывать Тогда
			Возврат;
		КонецЕсли;
		Выборка = РезультатЗапроса.Выбрать();
		Выборка.Следующий();
		ТекОбъект = Выборка.Ссылка.ПолучитьОбъект();
	Иначе 
		ТекОбъект = Справочники.ФизическиеЛица.СоздатьЭлемент();
	КонецЕсли; 
	
	ТекОбъект.Комментарий = Комментарий;
	
	ФамилияФЛ = СПрописной(СокрЛП(Данные.famSotr));
	ИмяФЛ = СПрописной(СокрЛП(Данные.imyaSotr));
	ОтчествоФЛ = СПрописной(СокрЛП(Данные.otchSotr));
	
	ФИО = ФамилияФЛ
		+ ?(ПустаяСтрока(ИмяФЛ), "", " " + ИмяФЛ)
		+ ?(ПустаяСтрока(ОтчествоФЛ), "", " " + ОтчествоФЛ);
	
	ТекОбъект.Наименование = ФИО;
	ТекОбъект.ДатаРождения = ПолучитьДатуИзДанных(Данные.dataR22);
	
	// 1с: МестоРожденияСтрокойПослеРедактирования = ""+СокрЛП(Особое)+","+СокрЛП(Город)+","+СокрЛП(Район)+","+СокрЛП(Область)+","+СокрЛП(Страна);
	ТекОбъект.МестоРождения = "0," + СокрЛП(Данные.gorodJ2) + "," + СокрЛП(Данные.raiionJ2) + "," + СокрЛП(Данные.nazvRegJ2);
		
	ТекОбъект.ИНН = СокрЛП(Данные.innSotr2);
	ТекОбъект.КодИМНС = СокрЛП(Данные.kodGNISotr);
	ТекОбъект.СтраховойНомерПФР = СокрЛП(Данные.regNomerPF);
	КодПола = Лев(ВРег(СокрЛП(Данные.pol)), 1);
	Если КодПола = "Ж" Тогда
		ТекОбъект.Пол = Перечисления.ПолФизическихЛиц.Женский;
	ИначеЕсли КодПола = "М" Тогда
		ТекОбъект.Пол = Перечисления.ПолФизическихЛиц.Мужской;
	Иначе 
		// оно?
		ТекОбъект.Пол = Перечисления.ПолФизическихЛиц.ПустаяСсылка();
	КонецЕсли; 
	
	ТекОбъект.Записать();
	ФизЛицоСсылка = ТекОбъект.Ссылка;
	
	// ФИО физ.лиц
	ПериодЗаписи = ТекОбъект.ДатаРождения;
	НЗ = РегистрыСведений.ФИОФизЛиц.СоздатьНаборЗаписей();
	НЗ.Отбор.ФизЛицо.Установить(ФизЛицоСсылка);
	НЗ.Отбор.Период.Установить(ПериодЗаписи);
	Запись = НЗ.Добавить();
	Запись.ФизЛицо = ФизЛицоСсылка;
	Запись.Период = ПериодЗаписи;
	Запись.Фамилия = ФамилияФЛ;
	Запись.Имя = ИмяФЛ;
	Запись.Отчество = ОтчествоФЛ;
	НЗ.Записать();
	
	// паспортные данные
	ДатаВыдачи = ПолучитьДатуИзДанных(Данные.data_vyidachi);
	ПериодЗаписи = ?(ЗначениеЗаполнено(ДатаВыдачи), ДатаВыдачи, ТекОбъект.ДатаРождения);
	НЗ = РегистрыСведений.ПаспортныеДанныеФизЛиц.СоздатьНаборЗаписей();
	НЗ.Отбор.ФизЛицо.Установить(ФизЛицоСсылка);
	НЗ.Отбор.Период.Установить(ПериодЗаписи);
	Запись = НЗ.Добавить();
	Запись.ФизЛицо = ФизЛицоСсылка;
	Запись.Период = ПериодЗаписи;
	Если ЗначениеЗаполнено(Данные.kodDokumenta) Тогда
		Запись.ДокументВид = Справочники.ДокументыУдостоверяющиеЛичность.НайтиПоРеквизиту("КодИМНС", СокрЛП(Данные.kodDokumenta));
	КонецЕсли; 
	Запись.ДокументНомер = СокрЛП(Данные.seriya);
	Запись.ДокументДатаВыдачи = ДатаВыдачи;
	Запись.ДокументКемВыдан = СокрЛП(Данные.pasportnyie_dannyie);
	НЗ.Записать();
	
	// контактная информация
	СтруктураАдреса = Новый Структура; 
	СтруктураАдреса.Вставить("Индекс"			, СокрЛП(Данные.indeks));
	СтруктураАдреса.Вставить("Регион"			, СокрЛП(Данные.nazvReg));
	СтруктураАдреса.Вставить("Район"			, СокрЛП(Данные.raiion));	
	СтруктураАдреса.Вставить("Город"			, СокрЛП(Данные.gorod));
	СтруктураАдреса.Вставить("НаселенныйПункт"	, СокрЛП(Данные.nasPunkt));
	СтруктураАдреса.Вставить("Улица"			, СокрЛП(Данные.ulica));
	СтруктураАдреса.Вставить("Дом"				, СокрЛП(Данные.dom2));
	СтруктураАдреса.Вставить("Корпус"			, СокрЛП(Данные.korpus));
	СтруктураАдреса.Вставить("Квартира"			, СокрЛП(Данные.kvartira22));
	МЗ = РегистрыСведений.КонтактнаяИнформация.СоздатьМенеджерЗаписи();
	УправлениеКонтактнойИнформацией.ЗаполнитьОбъектРедактированияАдресаПоСтруктуре(МЗ, СтруктураАдреса);
	МЗ.Объект = ФизЛицоСсылка;
	МЗ.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес;
	МЗ.Вид = Справочники.ВидыКонтактнойИнформации.ЮрАдресФизЛица;
	МЗ.Записать();
	
КонецПроцедуры

Проверка существует ли уже такой элемент справочника осуществляется по реквизиту Комментарий. У загружаемых объектов в этом реквизите указывается уникальная строка, возвращаемая функцией СформироватьКомментарий(), которая помимо всего прочего содержит в себе значение ID объекта системы Инфо-предприятие.

Вот код функции СформироватьКомментарий():

Функция СформироватьКомментарий(Данные, ПереченьПолей)
	
	Стр = "#Загружено из Инфо-Предприятие {";
	
	ДанныеКомментария = Новый Структура(ПереченьПолей);
	СписокПолей = Новый СписокЗначений;
	Для Каждого КлючИЗначение Из ДанныеКомментария Цикл
		СписокПолей.Добавить(КлючИЗначение.Ключ);
	КонецЦикла; 
	
	СписокПолей.СортироватьПоЗначению();
	
	ЗаполнитьЗначенияСвойств(ДанныеКомментария, Данные);
	Для Каждого ЭлементСписка Из СписокПолей Цикл
		ИмяПоля = ЭлементСписка.Значение;
		Стр = Стр + ИмяПоля + "=" + ДанныеКомментария[ИмяПоля] + ";";
	КонецЦикла; 
	
	Стр = Стр + "}#";
	
	Возврат Стр;
	
КонецФункции

Вот, собственно, и всё. Процедуры загрузки остальных справочников (Контрагенты, Номенклатура, ОсновныеСредства) аналогичны приведённой здесь процедуре ЗагрузитьФизЛицо(). Если кому-то они будут нужны - пишите, вышлю код.

Весь код под GPLv3.

Скачать файлы

Наименование Файл Версия Размер
ZagruzkaIzInfoPredpriyatie.epf.7z
.7z 12,90Kb
05.12.16
1
.7z 0.1 12,90Kb 1 Скачать

См. также

Добавить вознаграждение
В этой теме еще нет сообщений.