1С: работа с регистром «АдресныйОбъект»

Намедни прилетела интересная задача: создать визуальный построитель адреса доставки счёта клиента согласно данным ФИАС в древней не обновляемой конфигурации 1С. Первоначально подумал покопать в сторону сервиса https://fias-public-service.nalog.ru/api/spas/v2.0/swagger/index.html, написал заявку на генерацию ключа API для доступа, отправил её на указанную электронную почту…и тишина. Тащить самому адреса ФИАС и файлов и создавать для этого обвязку в конфигурараторе — трудоёмко. Но неожиданно возникла идея — а есть же обновляемая регулярно конфигурация 1С «Бухгалтерия», где этот справочник вполне используется и регулярно обновляется. Следовательно мы можем просто создать..ну например WEB сервис, при помощи которого будем тянуть данные для построения адреса из Бухгалтерии. Можно данные тянуть из регистров АдресныйОбъект, ДополнительныеАдресныеСведения, ИерархияАдресов и т.д, а можно покопать БСП, найти все нужные функции. За сим и оформил сервис:

&НаСервере
Функция ПолучитьПрокси()	
	Определение = Новый WSОпределения(
							Константы.СК_БУХURLВебСервиса.Получить(),
							Константы.СК_БУХИмяПользователя.Получить(),
							Константы.СК_БУХПароль.Получить()
							//,ИнтернетПрокси
						);
    
    Прокси = Новый WSПрокси(
						Определение,
						Константы.СК_БУХURIПространстваИмен.Получить(),
						"sk_SOAP_Services",
						"sk_SOAP_ServicesSoap"
						);
	Прокси.Пользователь = Константы.СК_БУХИмяПользователя.Получить();
	Прокси.Пароль = Константы.СК_БУХПароль.Получить();
	
	Возврат Прокси;
КонецФункции

Функция sk_gr_fias_exchange(request, params)  
	params=JSONВСтруктуру(params);
	МассивДляВозврата=Новый Массив();
	if (request="GetAdresses") тогда       
		//Parent,Level,TypeAddress,Counts,Poz,FindStr
		ДополнительныеПараметры=Новый Структура("КоличествоЗаписей,Позиция,СтрокаПоиска",params.Counts,params.Poz,params.FindStr);
		ТЗ=АдресныйКлассификаторСлужебный.АдресаДляИнтерактивногоВыбора(Новый УникальныйИдентификатор(params.Parent), params.Level, params.TypeAddress, ДополнительныеПараметры);		
		МассивДляВозврата=Новый Массив();
		для каждого стр из ТЗ.Данные цикл
			инф=Новый Структура("Идентификатор,Представление",Строка(стр.Идентификатор),Строка(стр.Представление));
			МассивДляВозврата.Добавить(инф);	
		конеццикла;					
	конецесли;	
	if (request="GetHomes") тогда       	
		ТЗ=АдресныйКлассификаторСлужебный.СписокДомов(Новый УникальныйИдентификатор(params.Parent),params.FindStr,params.Counts);		
		МассивДляВозврата=Новый Массив();
		для каждого стр из ТЗ цикл
			инф=Новый Структура("Идентификатор,Представление,Индекс",Строка(стр.Идентификатор),Строка(стр.Представление),Строка(стр.Значение.Индекс));
			МассивДляВозврата.Добавить(инф);	
		конеццикла;						
	конецесли;	
	
	Возврат СтруктураВСтрокуJSON(МассивДляВозврата);
КонецФункции

На целевой конфигурации, остаётся только дергать вызовы:

&НаСервере                                                  
Функция ПолучитьСписокАдресов(Родитель,Уровень)
// Уровень: 1- регион,2 - район, 3 - муниципальный район, 4-поселение, 5-город, 6 -нс, 7 - территория, 8 - улица
		Прокси=ПолучитьПрокси();		
			params=Новый Структура("Parent,Level,TypeAddress,Counts,Poz,FindStr");
			params.Parent=Строка(Родитель);
			params.Level=Уровень;
			params.TypeAddress="Административно-территориальный";
			params.Counts=500;
			params.FindStr="";
			Результат=Прокси.sk_gr_fias_exchange("GetAdresses",СтруктураВСтрокуJSON(params)); 
			//сообщить(Результат);
		возврат JSONВСтруктуру(Результат);

КонецФункции
&НаСервере                                                  
Функция ПолучитьСписокДомов(Родитель)
		Прокси=ПолучитьПрокси();		
			params=Новый Структура("Parent,Level,TypeAddress,Counts,Poz,FindStr");
			params.Parent=Строка(Родитель);
			params.Counts=500;
			params.FindStr="";
			Результат=Прокси.sk_gr_fias_exchange("GetHomes",СтруктураВСтрокуJSON(params)); 
			//сообщить(Результат);
		возврат JSONВСтруктуру(Результат);	
КонецФункции

И визуализировать всё подобным образом:

1С:Размещение индикатора прогресс бара на форме

Никогда не было и вот опять (с). Давненько не выводил на форму индикатор прогресс бара, и вот итог: забыл как это делается. И главное гугл/яндекс не особо помог. Во всех попадающихся ссылках расписывается как вывести данные в этот индикатор, а вот как вывести его на форму подразумевается что это настолько элементарно, что не требует пояснения 😉 Однакож вот, забыл. И так:

  1. В реквизиты формы добавляем реквизит с типом число
  2. Перетаскиваем его на форму и поле вид выбираем «Поле индикатора»
  3. Для обновления значения, используем «ЭтаФорма.Индикатор=12»
индикатор на форме 1с

P.S. А вот уж как в фоново обновлять индикатор, есть мои другие статьи

1С: Обновление формы после изменения данных на сервере

При обновлении данных на сервере, иногда бывает необходимость обновить содержимое клиентской формы. Сделать это можно вот так:

&НаКлиенте
Процедура СинхронизироватьСписок(Команда)
	СинхронизироватьСписокНаСервере();
	ОповеститьОбИзменении(Тип("СправочникСсылка.цукцукацук")); 
КонецПроцедуры

Чтение данных из файла docx средствами 1С

Задача: спарсить данные из таблицы, которая находится в файле формата docx средствами 1С

Решение: по сути своей файл формата docx является zip архивом, в котором находятся файлы формата xml и внешние ресурсы, типа картинок, стилей и т.п. Текстовое же содержимое находится непосредственно в файле document.xml. Его нужно лишь прочитать, найти в нём таблицу и распарсить данные.

Для начала загрузим файл на сервер, переименуем его в zip, и откроем его при помощи метода 1С «ЧтениеZipФайла», а найденный в архиве файл document.xml извлекем для дальнейшей обработки:

&НаКлиенте
Процедура ВыбратьФайлыИСделатьХорошо(Команда)
	Режим = РежимДиалогаВыбораФайла.Открытие;
    ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
    ДиалогОткрытияФайла.ПолноеИмяФайла = "";
    Фильтр = НСтр("ru = 'Текст'; en = 'Text'")+ "(*.docx)|*.docx";
    ДиалогОткрытияФайла.Фильтр = Фильтр;
    ДиалогОткрытияФайла.МножественныйВыбор = ложь;
    ДиалогОткрытияФайла.Заголовок = "Выберите файлы";
    Если ДиалогОткрытияФайла.Выбрать() Тогда
        МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы;
		ФайлСМС="";
		Для Каждого ИмяФайла Из МассивФайлов Цикл
			ФайлСМС=ИмяФайла;
		конеццикла;
		если ФайлСМС<>"" тогда 			
					АдресХранилищаФайла = "";			
					Состояние("Перемещаю файл на сервер");
		            ПоместитьФайл(АдресХранилищаФайла, ФайлСМС, , Ложь, ЭтаФорма.УникальныйИдентификатор);   					
					Состояние("Обрабатывается файл "+ФайлСМС);							
					таблицы=ПреобразоватьФайлDocXВМассивТаблиц(АдресХранилищаФайла);					
		иначе
			сообщить("Файл не выбран");
		конецесли;	
	конецесли;	        
КонецПроцедуры

&НаСервере
Функция ПреобразоватьФайлDocXВМассивТаблиц(АдресХранилищаФайла)	
	ТЗ=Новый ТаблицаЗначений();	
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилищаФайла);
	ИмяВременногоФайлаСпр = ПолучитьИмяВременногоФайла("zip");
	ДвоичныеДанные.Записать(ИмяВременногоФайлаСпр);     

	Архив = Новый ЧтениеZipФайла(ИмяВременногоФайлаСпр);
	ИмяВременногоФайлаXML = ПолучитьИмяВременногоФайла("xml");
	Для Каждого Элемент Из Архив.Элементы Цикл	
		если  Элемент.Имя="document.xml" тогда			
			Архив.Извлечь(Элемент, КаталогВременныхФайлов(), РежимВосстановленияПутейФайловZIP.НеВосстанавливать);			
		конецесли;
	Конеццикла;	
	Архив.Закрыть();
....

Далее файл documnet.xml необходимо загрузить как XML и распарсить в структуру при помощи построителя DOM. После чего останется только найти таблицу по имени узла w:tbl и поместить содержимое в таблицу значений:

ФайлXML = Новый ЧтениеXML;
    ФайлXML.ОткрытьФайл(КаталогВременныхФайлов()+"document.xml");
		ПостроительDOMXML=Новый ПостроительDOM;
		ДокументДом=ПостроительDOMXML.Прочитать(ФайлXML);
		ПрочитаноСтрок=0;		
		для каждого document из ДокументДом.ДочерниеУзлы цикл
			для каждого body из document.ДочерниеУзлы цикл
				для каждого el из body.ДочерниеУзлы цикл
					если el.ИмяУзла="w:tbl" тогда
							для каждого tab_el из el.ДочерниеУзлы цикл							
								если tab_el.ИмяУзла="w:tr" тогда
									если ПрочитаноСтрок=0 тогда
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[1].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[2].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[3].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[4].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[5].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[6].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[7].ТекстовоеСодержимое));
										ТЗ.Колонки.Добавить(УбратьНеОбрабатываемыеСимволы(tab_el.ДочерниеУзлы[8].ТекстовоеСодержимое));
									иначе	                 
										если tab_el.ДочерниеУзлы[1].ТекстовоеСодержимое="Всего:" тогда 
											прервать;
										КонецЕсли;           
										если tab_el.ДочерниеУзлы[1].ТекстовоеСодержимое<>"1" тогда
											если tab_el.ДочерниеУзлы[6].ТекстовоеСодержимое<>"" тогда
												нс=ТЗ.Добавить();
												нс[0]=tab_el.ДочерниеУзлы[1].ТекстовоеСодержимое;
												нс[1]=tab_el.ДочерниеУзлы[2].ТекстовоеСодержимое;
												нс[2]=tab_el.ДочерниеУзлы[3].ТекстовоеСодержимое;
												нс[3]=tab_el.ДочерниеУзлы[4].ТекстовоеСодержимое;
												нс[4]=tab_el.ДочерниеУзлы[5].ТекстовоеСодержимое;
													нс[4]=СтрЗаменить(нс[4],",",".");
													нс[4]=СтрЗаменить(нс[4]," ","");
													если нс[4]="" тогда нс[4]="0";конецесли;
													нс[4]=Число(Формат(нс[4],"ЧГ=0"));												
												нс[5]=tab_el.ДочерниеУзлы[6].ТекстовоеСодержимое;
												нс[6]=tab_el.ДочерниеУзлы[7].ТекстовоеСодержимое;
												нс[7]=tab_el.ДочерниеУзлы[8].ТекстовоеСодержимое;
													нс[7]=СтрЗаменить(нс[7],",",".");
													нс[7]=СтрЗаменить(нс[7]," ","");
													если нс[7]="" тогда нс[7]="0";конецесли;
													нс[7]=Число(Формат(нс[7],"ЧГ=0"));												
												
											конецесли;
										конецесли;
									конецесли;	
									ПрочитаноСтрок=ПрочитаноСтрок+1;
								конецесли;
							конеццикла;
							если ПрочитаноСтрок>0 тогда прервать;конецесли;
						конецесли;
						если ПрочитаноСтрок>0 тогда прервать;конецесли;
					конеццикла;
					если ПрочитаноСтрок>0 тогда прервать;конецесли;
				конеццикла;
				если ПрочитаноСтрок>0 тогда прервать;конецесли;
		конеццикла;	
	ФайлXML.Закрыть();
	Возврат ТЗ;	

1С: Хранение информации во внешних источниках данных

Как то упустил эту возможность платформы 1С и никогда ранее не использовал. А тут вдруг прилетела задача поработать файлами большого размера (xlsx, csv), на основании данных в которых нужно строить различного вида отчёты. Пришла мысль: а почему бы не загрузить данные этих файлов в БД, а затем уже спокойно стоить на основании этих данных отчёты. Какие-то регистры, справочники и т.п. создавать в конфигурации для этого посчитал излишним. Самое правильное, подумал я, хранить всё вообще в какой-то сторонней базе (в моём случае в PostgreSQL). А 1С использовать только для вывода и формирования отчётов. Вот тут то я и вспомнил, что когда то мельком читал про «внешние источники данных» в 1С. Значит пришло время попробовать хранение информации во внешних источниках данных.

Сначала создам БД, с таблицами ls и shemes со структурой вида::

хранение информации во внешних источниках данных.

, где id — автоинкримент типа integer. Забегая вперед, следует отметить, что 1С не умеет при добавлении данных во внешние источники данных, передавать инкрементальное значение, а потому создадим триггер, который будет выполнятся перед транзакцией запроса INSERT, и заменяет значение id, на следующее по порядку:

хранение информации во внешних источниках данных.

Подготовка закончена. Теперь подготовим платформу 1С. А именно необходимо установить драйвер ODBC. Под Linux ставим из репозитария, под Windows скачиваем и устанавливаем отсюда: https://www.postgresql.org/ftp/odbc/releases/REL-16_00_0005-mimalloc/

Далее необходимо зайти в конфигуратор 1С и добавить новый источник данных и таблицу в нём. При создании таблицы, необходимо выбрать «Выбрать из списка таблиц внешнего источника данных», и построить строку соединения с БД, вида:

хранение информации во внешних источниках данных.

После чего, будут доступны для добавления в конфигуратор таблицы БД:

хранение информации во внешних источниках данных.

После того как нажмем «Готово», в конфигураторе будет что-то вроде:

Далее остаётся научится читать,писать и удалять эти данные:

// добвление
	новыелс=внешниеисточникиданных.ОтчетыДля1С.Таблицы.reports_1c_public_ls.СоздатьОбъект();	
	новыелс.name="4232344";
	новыелс.Записать();
// изменение 
	мХарактеристика = внешниеисточникиданных.ОтчетыДля1С.Таблицы.reports_1c_public_ls.НайтиПоПолю("id",3);
	мОбъект = мХарактеристика.ПолучитьОбъект();
	мОбъект.name = "Уря! Чебуршка родил слона!";
	мОбъект.Записать();

//удаление 
	мХарактеристика = внешниеисточникиданных.ОтчетыДля1С.Таблицы.reports_1c_public_ls.НайтиПоПолю("id",3);
	мОбъект = мХарактеристика.ПолучитьОбъект();
	мОбъект.Удалить();
// чтение
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	reports_1c_public_ls.id КАК id,
		|	reports_1c_public_ls.name КАК name,
		|	reports_1c_public_shemes.name КАК name1
		|ИЗ
		|	ВнешнийИсточникДанных.ОтчетыДля1С.Таблица.reports_1c_public_ls КАК reports_1c_public_ls
		|		ЛЕВОЕ СОЕДИНЕНИЕ ВнешнийИсточникДанных.ОтчетыДля1С.Таблица.reports_1c_public_shemes КАК reports_1c_public_shemes
		|		ПО reports_1c_public_ls.sheme = reports_1c_public_shemes.id";
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		сообщить(ВыборкаДетальныеЗаписи.name);
		сообщить(ВыборкаДетальныеЗаписи.name1);
	КонецЦикла;

Update 16/09/2025: таки автоувеличение идентификатора умеет. Достаточно его указать как «только чтение» в 1С:

Но можно и с триггерами мудрить для желающих 😉

1 4 5 6 7 8 37