Сказ о том, как в одной крупной компании документооборот внедряли, или проблемы типовых обменов между КА и ДО

10.11.20

Бизнес-анализ

Приветствую всех. Сегодня пойдет речь о том, как на одной крупной компании внедряли 1С:Документооборот 2.1 в связке с КА 2.4. Вроде бы системы типовые, мы практически не добавляли ничего в них, но проблем было столько, что я решил изложить их в статье. Может, кому-то пригодится это в дальнейшем, и не придется тратить кучу времени на поиск решений.

КА -комплексная автоматизация, ДО - документооборот.

Итак, базы развернуты, опубликованы, можем начинать. А начнем с синхронизации...

Этап 1: Синхронизация

Настраиваем типовую синхронизацию, далее первый запуск и...ничего не работает.  Идем в журнал регистрации и видим странную ошибку.

Неверное имя колонки
{Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(8431)}:        Коллекция.Колонки.Добавить(ИмяПоля);
{Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(8310)}:    КоллекцияГруппировки = ИнициализацияТаблицыПоКлючевымПолям(МассивКлючевыхПолейПоиска);
{Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(9955)}:                ЗагрузитьТабличнуюЧасть(Объект, Имя, ИнформацияОТипах, ПараметрыОбъекта, Правило);
{Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(16050)}:            ПоследнийОбъектЗагрузки = ПрочитатьОбъект();
{Обработка.КонвертацияОбъектовИнформационныхБаз.МодульОбъекта(2663)}:        ПроизвестиЧтениеДанныхВРежимеВнешнегоСоединения(ЧтениеСообщения);
{ОбщийМодуль.ОбменДаннымиСервер.Модуль(5794)}:        ОбработкаОбменаДаннымиВнешнееСоединение.ВыполнитьВыгрузкуДанных(ОбработкаДляЗагрузкиДанных);
{ОбщийМодуль.ОбменДаннымиСервер.Модуль(2936)}:            ВыполнитьДействиеОбменаДляУзлаИнформационнойБазыПоВнешнемуСоединению(Отказ,
{Обработка.ВыполнениеОбменаДанными.МодульМенеджера(34)}:    ОбменДаннымиСервер.ВыполнитьОбменДаннымиДляУзлаИнформационнойБазы(
{(1)}:Обработки.ВыполнениеОбменаДанными.ВыполнитьЗапускОбменаДанными(Параметры[0],Параметры[1])
{ОбщийМодуль.ОбщегоНазначения.Модуль(4884)}:    Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
{ОбщийМодуль.ДлительныеОперации.Модуль(724)}:        ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыПроцедуры);
{ОбщийМодуль.ДлительныеОперации.Модуль(715)}:    ВыполнитьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);

 

Что ж, делать нечего...Идем в отладку. И что мы там наблюдаем? Довольно интересную картину.

По какой-то причине у нас две колонки с одним наименованием.

Идем в правила конвертации и видим, что в тч контактной информации две строки с конвертацией реквизита ДействуетС, удаляем лишнюю строку, заменяем правила - и о чудо, все работает.

Больше с синхронизацией проблем не было (только доработки, связанные со спецификой внедрения). Переходим к  бесшовной интеграции.

з.ы. ошибка эта была в нескольких релизах подряд, на последнем релизе не проверял, но при необходимости могу посмотреть.

Этап 2.Интеграция (бесшовка).

Историю о настройке бесшовной интеграции начну с небольшого описания работы самого механизма.

На стороне КА имеются следующие объекты:

ПланОбмена : ИнтеграцияС1СДокументооборотомПереопределяемый

РегистрСведений: ОчередьСообщенийВ1СДокументооборот

При изменении объекта, участвующего в интеграции, этот объект регистрируется на узле плана обмена. Далее фоновое задание вызывает процедуру модуля, в котором соответственно выполняются последовательно три процедуры:

ИнтеграцияС1СДокументооборотОбмен.ПодготовитьДанныеДляОтправки();

ИнтеграцияС1СДокументооборотОбмен.ОтправитьДанные();

ИнтеграцияС1СДокументооборотОбмен.ПолучитьДанные();

ПодготовитьДанныеДляОтправки();  - формирует пакеты в формате xml и помещает их в регистр сведений ОчередьСообщенийВ1СДокументооборот в виде двоичных данных. При этом пакеты формируются с контролем длины пакета, при превышении длины пакет разбивается на части. В одном пакете может содержаться несколько объектов, а значит если возникнет проблема загрузки хотя бы одного объекта из пакета - пакет не прогрузится. По факту это сделано в угоду производительности, но при этом сказалось на устойчивости системы. (В итоге после согласования с заказчиком была механизм был изменен под логику ОдинОбъект-ОдинПакет см. далее)

ОтправитьДанные() - получает записи регистра, получает из двоичных данных пакет, формирует на основе пакетов запрос, выполняет этот запрос на стороне ДО. В случае успешного выполнения запись в регистре удаляется.

Минус этого метода - все пакеты обрабатываются в одной конструкции Попытка-Исключение. Если хотя бы один пакет  с ошибкой, все остальные пакеты уже не обрабатываются.

Также была переделана - каждый пакет обрабатывается в отдельной попытке.

ПолучитьДанные() - в цикле с уловием, пока есть необработанные пакеты на стороне ДО формируется запрос, который передает на сторону ДО номер последнего успешно обработанного пакета и возвращает в КА новый пакет, после чего данный пакет обрабатывается на стороне ДО. В типовом варианте также при возникновении ошибки загрузка останавливается. (Также была доработана).

На стороне ДО:

План обмена ИнтегрированныеСистемы

регистр сведений ОчередиСообщенийОбменаСИнтегрированнымиСистемами

справочник: СообщенияИнтегрированныхСистем

Фоновое задание формирует пакет xml и в виде двоичных данных записывает его в справочник.

Далее на стороне КА вызывается процедура ПолучитьДанные()

при успешном получении элемент справочника помечается на удаление.

2.1 Выгрузка из ДО в КА (не те правила подставляются)

ИнтеграцияС1СДокументооборотОбмен  ПолучитьДанные();

В этой процедуре для объекта производится поиск подходящего правила. Ниже представлен скриншот функции, получающей правило интеграции для объекта.

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

Заменяем на функцию, указанную в рекомендациях (заодно делаем для себя дополнительную запись в Журнал регистрации.

Теперь правило определяются корректно и большая часть ошибок уже решена. Едем дальше...

2.2 Обмен заявками на расходование ДС по физ лицам

После создания правила для Заявки на расходование ДС - Внутренний документ (Заявка на расходование ДС) с частью заявок появились проблемы. А именно, у заявки вид хоз. операции "Выдача подотчетнику" банковский счет с владельцем физ. лицо. В правиле для банковского счета стоит флаг Обновлять. В ДО у банковского счета во владельцах справочника Физ. лица нет в принципе. При обмене из-за этого возникает ошибка "ОбщийМодуль.ИнтеграцияС1СДокументооборот.Модуль(467) Значение не является значением объектного типа (name)". - по отладке это как раз момент заполнения владельца у банковского счета. Сейчас пока выключили обновление у банковского счета, но это решение временное. параллельно написали в ТП 1с. 

Таких заявок оказалось крайне мало, но по мне, это недоработка документооборота.

 

2.3 Обмен статусами документов

В КА помимо статуса в объекте есть регистр сведений СостоянияСогласованияВДокументообороте. В процедуре получения данных из ДО в этот регистр записываются данные по статусу, если они есть в пакете. После записи в регистр вызывается процедура ИнтеграцияС1СДокументооборотПереопределяемый.ПриИзмененииСостоянияСогласования в которой на текущий момент ничего нет (процедура пустая). Я предполагаю, что данный регистр в дальнейшем нужно обрабатывать, получая статус и объект по идентификатору и далее изменять статус в самом объекте. Но мы идем немного другим путем и прописываем соответствия статусов непосредственно в правилах интеграции.

Перечь статусов в КА и ДО не соответствует, поэтому их нужно синхронизировать с помощью выражений.

Из КА в ДО:

Если Параметры.Источник.Статус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.НеСогласована Тогда
	Параметры.Результат = "НеСогласован";
ИначеЕсли Параметры.Источник.Статус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.Согласована Тогда
	Параметры.Результат = "Согласован";
ИначеЕсли Параметры.Источник.Статус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате Тогда
	Параметры.Результат = "Согласован";
ИначеЕсли Параметры.Источник.Статус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.Отклонена Тогда
	Параметры.Результат = "НеСогласован";
КонецЕсли;
ЗаписьЖурналаРегистрации("интеграция Отправка",УровеньЖурналаРегистрации.Информация,,Параметры.Результат,,);

Из ДО в КА:

пСтатус = Неопределено;
Если Параметры.Источник.statusApproval.name = "Согласован" Тогда
    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.Согласована;
ИначеЕсли Параметры.Источник.statusApproval.name = "Не согласован" Тогда
    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.НеСогласована;
ИначеЕсли Параметры.Источник.statusApproval.name = "На согласовании" Тогда
    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.НеСогласована;
КонецЕсли;
пСтатусДляЖР = "статус " + Параметры.Источник.status.name+"; объект "+Параметры.Источник.title+"; ст согл "+Параметры.Источник.statusApproval.name;
ЗаписьЖурналаРегистрации("интеграция Получение",УровеньЖурналаРегистрации.Информация,,пСтатусДляЖР,,);
Параметры.Результат = пСтатус;

 

Также столкнулись с такой проблемой: в КА заявку перевели в статус "К оплате", через некоторое время из ДО прилетает статус "Согласовано". Пришлось на стороне КА делать проверку, если статус "К оплате", то обмен его уже изменить не может. Такие заявки контролируются ответственным пользователем.

3. Меняем логику работы обмена.

После обсуждений с заказчиком было принято решение о том, что текущую логику работы обмена нужно поменять. А именно:

-сделать проверку на количество итераций по ошибочным пакетам при загрузке из ДО в КА;

-если ошибочный пакет грузится повторно, присваиваем ему статус обработанного с занесением ошибки в ЖР (в дальнейшем планируется отдельный регистр + рассылка ошибок по ответственным);

-под каждый объект делаем свой пакет, т.е если в очереди будет ошибочный объект, то он не повлияет на остальные пакеты в очереди;

В итоге доработки выглядят так:

 
 на стороне КА ИнтеграцияС1СДокументооборотОбмен

 

&Вместо("ПолучитьДанные")
Процедура is4b_ПолучитьДанные()
	Попытка
		
		Прокси = ИнтеграцияС1СДокументооборотПовтИсп.ПолучитьПрокси();
		
		ПоддерживаетсяОбновлениеФайлов = 
			ИнтеграцияС1СДокументооборотПовтИсп.ДоступенФункционалВерсииСервиса("2.1.9.1.CORP");
		ОбъектыКОбновлениюПечатныхФорм = Новый ТаблицаЗначений;
		ОбъектыКОбновлениюПечатныхФорм.Колонки.Добавить("Объект");
		ОбъектыКОбновлениюПечатныхФорм.Колонки.Добавить("ОбъектXDTO");
		ОбъектыКОбновлениюПечатныхФорм.Колонки.Добавить("Правило");
		
		УзелДокументооборота = ИнтеграцияС1СДокументооборотПовтИсп.УзелДокументооборота();
		СоставПланаОбмена = Метаданные.ПланыОбмена.ИнтеграцияС1СДокументооборотомПереопределяемый.Состав;
		
		ПрочитаныВсеСообщения = Ложь;
		
		МассивОшибочныхПакетов = Новый Массив;
		СчетчикИтераций = 0;
		Пока Не ПрочитаныВсеСообщения 
			И МассивОшибочныхПакетов.Количество()<10 
			И СчетчикИтераций<50 Цикл
			СчетчикИтераций = СчетчикИтераций+1;
			//Каждое сообщение обрабатываем в отдельной попытке
			Попытка
			
			Запрос = ИнтеграцияС1СДокументооборот.СоздатьОбъект(Прокси, "DMGetChangesRequest");
			Запрос.lastMessageId = Константы.НомерПоследнегоПринятогоСообщенияДокументооборота.Получить();
			
			Ответ = Прокси.execute(Запрос);
			ИнтеграцияС1СДокументооборот.ПроверитьВозвратВебСервиса(Прокси, Ответ);
			
			//bmv
			//проверяем, если уже была попытка записи и завершилась с ошибокой
			//то помечаем этот пакет, как обработанный в ДО
			ИндексПакетаВМассиве =МассивОшибочныхПакетов.Найти(Ответ.messageId);
			Если ИндексПакетаВМассиве<>Неопределено Тогда
				МассивОшибочныхПакетов.Удалить(ИндексПакетаВМассиве);
				НомерИсходный = Константы.НомерПоследнегоПринятогоСообщенияДокументооборота.Получить();
				НомерПринятый = Строка(Ответ.messageId);
				Если НомерИсходный <> НомерПринятый Тогда
					Константы.НомерПоследнегоПринятогоСообщенияДокументооборота.Установить(НомерПринятый);
				КонецЕсли;
				Продолжить;
			КонецЕсли;

			//bmv

			Для каждого ОбъектXDTO Из Ответ.objects Цикл
				
								
				
				Если ОбъектXDTO.objectId.type = "DMInternalDocumentTemplate"
					Или ОбъектXDTO.objectId.type = "DMIncomingDocumentTemplate"
					Или ОбъектXDTO.objectId.type = "DMOutgoingDocumentTemplate" Тогда
					
					Справочники.ПравилаИнтеграцииС1СДокументооборотом.ОбновитьПравилаПоШаблону(ОбъектXDTO);
					
					Продолжить;
					
				КонецЕсли;
				
				Ссылки = ИнтеграцияС1СДокументооборот.СсылкиПоВнешнимОбъектам(ОбъектXDTO);
				
				Для Каждого ОбъектСсылка Из Ссылки Цикл
					
					//Правило = Справочники.ПравилаИнтеграцииС1СДокументооборотом.ПравилоИнтеграцииОбъекта(
					//	ОбъектСсылка, ОбъектXDTO.objectId.type);
					
					//bmv 26_10_20
					Правило = Неопределено;
					Правила = ИнтеграцияС1СДокументооборотВызовСервера.ПодходящиеПравила(ОбъектСсылка,ОбъектXDTO);
					Если Правила.Количество()=1 Тогда
						Правило = Правила[0].Ссылка;
					КонецЕсли;
					ЗаписьЖурналаРегистрации("ПолучениеИзДО.ПодборПравилИнтеграции", УровеньЖурналаРегистрации.Информация,,ОбъектСсылка,"Выбрано правило "+ Правило);
					//bmv 26_10_20
					Если Правило = Неопределено Тогда
						Продолжить;
					КонецЕсли;
					
					Если ОбъектXDTO.Свойства().Получить("files") <> Неопределено
						И ОбъектXDTO.Установлено("files") Тогда
						
						Если ОбъектXDTO.files.Количество() <> 0 Тогда
							ИнтеграцияС1СДокументооборотПереопределяемый.ПриПоявленииПрисоединенныхФайловДокументооборота(
								ОбъектXDTO.objectId.id,
								ОбъектXDTO.objectId.type,
								ОбъектСсылка);
						Иначе
							ИнтеграцияС1СДокументооборотПереопределяемый.ПриУдаленииПрисоединенныхФайловДокументооборота(
								ОбъектXDTO.objectId.id,
								ОбъектXDTO.objectId.type,
								ОбъектСсылка);
						КонецЕсли;
						
					КонецЕсли;
					
					Объект = ОбъектСсылка.ПолучитьОбъект();
					
					ИсходнаяПометкаУдаления = Объект.ПометкаУдаления;
					
					Обновление = Истина;
					ТребуетсяПерепроведение = Ложь;
					ЕстьИзменения = Справочники.ПравилаИнтеграцииС1СДокументооборотом.ЗаполнитьОбъектПоОбъектуXDTO(
						Прокси,
						Объект,
						ОбъектXDTO,
						Правило,
						Обновление,
						ТребуетсяПерепроведение);
						
					Если ЕстьИзменения Тогда
							
						Если Объект.ПометкаУдаления
							И Не ИсходнаяПометкаУдаления Тогда
							
							МетаданныеОбъекта = Объект.Метаданные();
							Если Метаданные.Документы.Содержит(МетаданныеОбъекта)
								И МетаданныеОбъекта.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить
								И Объект.Проведен Тогда
								Объект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
							Иначе
								Объект.ОбменДанными.Загрузка = Истина;
								Объект.Записать();
							КонецЕсли;
							
						Иначе
							
											
							ЗаполненКорректно = Объект.ПроверитьЗаполнение();
							
							Если ЗаполненКорректно Тогда
								Если ТребуетсяПерепроведение Тогда
									Объект.Записать(РежимЗаписиДокумента.Проведение,
										РежимПроведенияДокумента.Неоперативный);
								Иначе
									Объект.ОбменДанными.Загрузка = Истина;
									Объект.Записать();
								КонецЕсли;
							Иначе
								СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
								ТекстСообщения = "";
								Для Каждого СообщениеПользователю Из СообщенияПользователю Цикл 
									ТекстСообщения = ТекстСообщения + СообщениеПользователю.Текст + Символы.ПС;
								КонецЦикла;
								ВызватьИсключение ТекстСообщения;
							КонецЕсли;
							
						КонецЕсли;
						
						Если ПоддерживаетсяОбновлениеФайлов
							И ИнтеграцияС1СДокументооборотКлиентСервер.ЭтоДокумент(ОбъектXDTO.objectId.type) Тогда
							КОбновлению = ОбъектыКОбновлениюПечатныхФорм.Добавить();
							КОбновлению.Объект = Объект;
							КОбновлению.ОбъектXDTO = ОбъектXDTO;
							КОбновлению.Правило = Правило;
						КонецЕсли;
					
						Если СоставПланаОбмена.Содержит(Объект.Метаданные()) Тогда
							ПланыОбмена.УдалитьРегистрациюИзменений(УзелДокументооборота, Объект.Ссылка);
						КонецЕсли;
						
					КонецЕсли;
					
				КонецЦикла;
				
			КонецЦикла;
			
			// С версии 1.4.8 выполняется обновление состояний согласования на стороне ИС.
			Если Ответ.Свойства().Получить("records") <> Неопределено Тогда
				
				Для каждого ОбъектXDTO Из Ответ.records Цикл
					
					ЗапросСвязанныйОбъект = Новый Запрос(
						"ВЫБРАТЬ ПЕРВЫЕ 1
						|	Объект
						|ИЗ
						|	РегистрСведений.ОбъектыИнтегрированныеС1СДокументооборотом
						|ГДЕ
						|	ТипОбъектаДО = &ТипОбъектаДО
						|	И ИдентификаторОбъектаДО = &ИдентификаторОбъектаДО
						|");
					Если ИнтеграцияС1СДокументооборот.ПроверитьТип(Прокси, ОбъектXDTO, 
						"DMApprovalStateRecord") Тогда
						ЗапросСвязанныйОбъект.УстановитьПараметр("ТипОбъектаДО",
							ОбъектXDTO.type);
						ЗапросСвязанныйОбъект.УстановитьПараметр("ИдентификаторОбъектаДО",
							ОбъектXDTO.id);
						Выборка = ЗапросСвязанныйОбъект.Выполнить().Выбрать();
						Если Выборка.Следующий() Тогда
							Если ОбъектXDTO.status = Неопределено Тогда // запись удалена (например, прерывание)
								ИнтеграцияС1СДокументооборотВызовСервера.ПриИзмененииСостоянияСогласования(
									ОбъектXDTO.id,
									ОбъектXDTO.type,
									Неопределено,
									Ложь,
									Выборка.Объект);
							Иначе
								ИдентификаторСостояния = ОбъектXDTO.status.objectId.id;
								Состояние = Перечисления.СостоянияСогласованияВДокументообороте[ИдентификаторСостояния];
								ИнтеграцияС1СДокументооборотВызовСервера.ПриИзмененииСостоянияСогласования(
									ОбъектXDTO.id,
									ОбъектXDTO.type,
									Состояние,
									Ложь,
									Выборка.Объект,
									ОбъектXDTO.name,
									ОбъектXDTO.date);
							КонецЕсли;
						КонецЕсли;
					КонецЕсли;					
									
				КонецЦикла;
				
			КонецЕсли;
			
			НомерИсходный = Константы.НомерПоследнегоПринятогоСообщенияДокументооборота.Получить();
			НомерПринятый = Строка(Ответ.messageId);
			Если НомерИсходный <> НомерПринятый Тогда
				Константы.НомерПоследнегоПринятогоСообщенияДокументооборота.Установить(НомерПринятый);
			КонецЕсли;
			
			ПрочитаныВсеСообщения = (Ответ.messageId = Неопределено);
			
			ОбновитьПечатныеФормы(ОбъектыКОбновлениюПечатныхФорм);
			
		Исключение
			МассивОшибочныхПакетов.Добавить(Ответ.messageId);
			Инфо = ОписаниеОшибки();
			ЗаписьЖурналаРегистрации(
			ИнтеграцияС1СДокументооборот.ИмяСобытияЖурналаРегистрации(
				НСтр("ru = 'Получение данных'",
					ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка())),
			УровеньЖурналаРегистрации.Ошибка,
			,
			Запрос.Тип().Имя,
			Запрос.Тип().Имя + Символы.ПС + Инфо+"; ИД пакета: "+Ответ.messageId);
		КонецПопытки;
	
		КонецЦикла; 
		
	Исключение
		Инфо = ОписаниеОшибки();
		ЗаписьЖурналаРегистрации(
			ИнтеграцияС1СДокументооборот.ИмяСобытияЖурналаРегистрации(
				НСтр("ru = 'Получение данных'",
					ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка())),
			УровеньЖурналаРегистрации.Ошибка,
			,
			Запрос.Тип().Имя,
			Запрос.Тип().Имя + Символы.ПС + Инфо);
		
	КонецПопытки; 

КонецПроцедуры

&Вместо("ПодготовитьДанныеДляОтправки")
Процедура is4b_ПодготовитьДанныеДляОтправки()
	УзелДокументооборота = ИнтеграцияС1СДокументооборотПовтИсп.УзелДокументооборота();
	
	Прокси = ИнтеграцияС1СДокументооборотПовтИсп.ПолучитьПрокси();
	
	// Выборка всех изменений для данной интегрированной системы
	ИнтегрированныеОбъекты = ПолучитьМассивЗарегистрированныхДанных(УзелДокументооборота);
	
	Если ИнтегрированныеОбъекты.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	//bmv 30_10_20
	МассивУспешноОбработаны = Новый Массив;
	//bmv 30_10_20
	Для Каждого ИнтегрированныйОбъект Из ИнтегрированныеОбъекты Цикл
		//bmv 30_10_20
		//под каждый объект свой пакет
		ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
		ЗаписьXML = Новый ЗаписьXML;
		ЗаписьXML.ОткрытьФайл(ИмяВременногоФайла, "UTF-8");
		ЗаписьXML.ЗаписатьОбъявлениеXML();
		ЗаписьXML.ЗаписатьНачалоЭлемента("Message");
		//bmv 30_10_20
		
		ОбъектXDTO = ИнтеграцияС1СДокументооборот.ПолучитьXDTOИзмененийИзОбъекта(Прокси, ИнтегрированныйОбъект);
		
		Если ОбъектXDTO = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Попытка
			Прокси.ФабрикаXDTO.ЗаписатьXML(ЗаписьXML, ОбъектXDTO);
			//bmv 30_10_20
			МассивУспешноОбработаны.Добавить(ИнтегрированныйОбъект);
			//bmv 30_10_20
		Исключение
			Инфо = ОписаниеОшибки();
			ЗаписьЖурналаРегистрации(
				ИнтеграцияС1СДокументооборот.ИмяСобытияЖурналаРегистрации(НСтр("ru = 'Выгрузка XDTO в XML'",
					ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка())),
				УровеньЖурналаРегистрации.Ошибка,
				,
				ОбъектXDTO.Тип().Имя,
				ОбъектXDTO.Тип().Имя + Символы.ПС + Инфо);
		КонецПопытки;
		//bmv 30_10_20
		ЗаписьXML.ЗаписатьКонецЭлемента();
		ЗаписьXML.Закрыть();
		ДвоичныеДанныеСообщения = Новый ДвоичныеДанные(ИмяВременногоФайла);
		ДанныеСообщения = Новый ХранилищеЗначения(ДвоичныеДанныеСообщения, Новый СжатиеДанных(9));
	
		РегистрыСведений.ОчередьСообщенийВ1СДокументооборот.ДобавитьСообщение(ДанныеСообщения);
		#Если Сервер Тогда
		УдалитьФайлы(ИмяВременногоФайла);
		#КонецЕсли
		//bmv 30_10_20
	КонецЦикла;
	
	
	//bmv 30_10_20
	//Для Каждого ИнтегрированныйОбъект Из ИнтегрированныеОбъекты Цикл
	Если МассивУспешноОбработаны.Количество()>0 Тогда
		Для Каждого ИнтегрированныйОбъект Из МассивУспешноОбработаны Цикл
			ПланыОбмена.УдалитьРегистрациюИзменений(УзелДокументооборота, ИнтегрированныйОбъект.Объект);
		КонецЦикла;
	КонецЕсли;
	//bmv 30_10_20
КонецПроцедуры

&Вместо("ОтправитьДанные")
Процедура is4b_ОтправитьДанные()
	Попытка
		
		ИдентификаторСообщения = Неопределено;
		МоментВремени = Неопределено;
		
		Запрос = Новый Запрос(
			"ВЫБРАТЬ
			|	ОчередьСообщенийВ1СДокументооборот.МоментВремени КАК МоментВремени,
			|	ОчередьСообщенийВ1СДокументооборот.Данные КАК Данные,
			|	ОчередьСообщенийВ1СДокументооборот.Идентификатор КАК Идентификатор
			|ИЗ
			|	РегистрСведений.ОчередьСообщенийВ1СДокументооборот КАК ОчередьСообщенийВ1СДокументооборот
			|
			|УПОРЯДОЧИТЬ ПО
			|	МоментВремени");
		
		Результат = Запрос.Выполнить();
		
		Если Результат.Пустой() Тогда
			Возврат;
		КонецЕсли; 
		
		Прокси = ИнтеграцияС1СДокументооборотПовтИсп.ПолучитьПрокси();
		
		//Запрос = ИнтеграцияС1СДокументооборот.СоздатьОбъект(Прокси, "DMPutChangesRequest");
		//ОбщийРазмерСообщений = 0;
		ПредельныйРазмерСообщений = 
			ИнтеграцияС1СДокументооборотВызовСервера.МаксимальныйРазмерПередаваемогоФайла();
		
		Выборка = Результат.Выбрать();
		
		Пока Выборка.Следующий() Цикл
			//bmv 30_10_20
			Попытка
			Запрос = ИнтеграцияС1СДокументооборот.СоздатьОбъект(Прокси, "DMPutChangesRequest");
			ИдентификаторСообщения = Выборка.Идентификатор;
			МоментВремени = Выборка.МоментВремени;
			
			ДвоичныеДанные = Выборка.Данные.Получить();
			РазмерДвоичныеДанные = ДвоичныеДанные.Размер();
			//ОбщийРазмерСообщений = ОбщийРазмерСообщений + ДвоичныеДанные.Размер();
			
			//Если ОбщийРазмерСообщений > ПредельныйРазмерСообщений
			//	И Запрос.objects.Количество() > 0 Тогда
			
			Если РазмерДвоичныеДанные>ПредельныйРазмерСообщений Тогда
				ЗаписьЖурналаРегистрации(
				НСтр("ru = 'Интеграция с 1С:Документооборотом.Отправка данных'",
				ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,
				Метаданные.РегистрыСведений.ОчередьСообщенийВ1СДокументооборот,
				Строка(ИдентификаторСообщения),
				" превышен максимальный размер пакета");
				Продолжить;
			КонецЕсли;
				//Результат = Прокси.execute(Запрос);
				//ИнтеграцияС1СДокументооборот.ПроверитьВозвратВебСервиса(Прокси, Результат);
				
				//Запрос = ИнтеграцияС1СДокументооборот.СоздатьОбъект(Прокси, "DMPutChangesRequest");
				//ОбщийРазмерСообщений = 0;
				
			
			ИмяФайлаСообщенияОбмена = ПолучитьИмяВременногоФайла("xml");
			ДвоичныеДанные.Записать(ИмяФайлаСообщенияОбмена);
			
			ЧтениеXML = Новый ЧтениеXML;
			ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщенияОбмена);
			ЧтениеXML.Прочитать();
			ЧтениеXML.Прочитать();
			
			Пока ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Цикл
				// Выполняется последовательное чтение одного объекта за другим
				ТипXDTO = Прокси.ФабрикаXDTO.Тип("http://www.1c.ru/dm", ЧтениеXML.Имя);
				ОбъектXDTO = Прокси.ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипXDTO);
				Запрос.objects.Добавить(ОбъектXDTO);
			КонецЦикла;
			
			ЧтениеXML = Неопределено;
			#Если Сервер Тогда
			УдалитьФайлы(ИмяФайлаСообщенияОбмена);
			#КонецЕсли
			Результат = Прокси.execute(Запрос);
			ИнтеграцияС1СДокументооборот.ПроверитьВозвратВебСервиса(Прокси, Результат);
			//если ошибок нет, сразу удаляем запись в регистре
			МенеджерЗаписи = РегистрыСведений.ОчередьСообщенийВ1СДокументооборот.СоздатьМенеджерЗаписи();
			ЗаполнитьЗначенияСвойств(МенеджерЗаписи, Выборка);
			МенеджерЗаписи.Удалить();

		Исключение
				Инфо = ОписаниеОшибки();
				ЗаписьЖурналаРегистрации(
				НСтр("ru = 'Интеграция с 1С:Документооборотом.Отправка данных'",
				ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,
				Метаданные.РегистрыСведений.ОчередьСообщенийВ1СДокументооборот,
				Строка(ИдентификаторСообщения),
				Запрос.Тип().Имя + Символы.ПС + Инфо);
			    ОбновитьДанныеПоОшибке(ИдентификаторСообщения, МоментВремени, Инфо);
			КонецПопытки;
		КонецЦикла; 
		
		//Если Запрос.objects.Количество() > 0 Тогда
		//	Результат = Прокси.execute(Запрос);
		//	ИнтеграцияС1СДокументооборот.ПроверитьВозвратВебСервиса(Прокси, Результат);
		//КонецЕсли;
		
		//Выборка.Сбросить();
		
		//Пока Выборка.Следующий() Цикл
			
						
		//КонецЦикла;
		
	Исключение
		
		Инфо = ОписаниеОшибки();
		
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Интеграция с 1С:Документооборотом.Отправка данных'",
				ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка,
			Метаданные.РегистрыСведений.ОчередьСообщенийВ1СДокументооборот,
			Строка(ИдентификаторСообщения),
			Запрос.Тип().Имя + Символы.ПС + Инфо);
		ОбновитьДанныеПоОшибке(ИдентификаторСообщения, МоментВремени, Инфо);	
		
		
	КонецПопытки; 

КонецПроцедуры

Процедура ОбновитьДанныеПоОшибке(ИдентификаторСообщения, МоментВремени, Инфо)
	    Если ИдентификаторСообщения <> Неопределено Тогда
			МенеджерЗаписи = РегистрыСведений.ОчередьСообщенийВ1СДокументооборот.СоздатьМенеджерЗаписи();
			МенеджерЗаписи.МоментВремени = МоментВремени;
			МенеджерЗаписи.Идентификатор = ИдентификаторСообщения;
			МенеджерЗаписи.Прочитать();
			МенеджерЗаписи.КоличествоПопытокОтправки = МенеджерЗаписи.КоличествоПопытокОтправки + 1;
			МенеджерЗаписи.ТекстСообщенияОбОшибке = Инфо;
			МенеджерЗаписи.Записать();
		КонецЕсли;
КонецПроцедуры

 

 
На стороне ДО модуль ОбработкаЗапросовXDTOОбмен

 


&Вместо("ФормированиеСообщений")
Процедура is4b_ФормированиеСообщений()
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания();
	
	УзлыОбмена = ОбработкаЗапросовXDTOПовтИсп.ПолучитьУзлыОбменаИнтегрированныхСистем();
	
	Если Не ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюСИнтегрированнымиСистемами") Тогда
		Для каждого ИнтегрированнаяСистема Из УзлыОбмена Цикл
			ПланыОбмена.УдалитьРегистрациюИзменений(ИнтегрированнаяСистема);
		КонецЦикла; 
		Возврат;
	КонецЕсли; 
	
	Для каждого ИнтегрированнаяСистема Из УзлыОбмена Цикл
		СформироватьПакетыОбмена(ИнтегрированнаяСистема);
		//Сообщение = СоздатьНовоеСообщение(ИнтегрированнаяСистема);
		//СформироватьПакетОбмена(Сообщение, ИнтегрированнаяСистема);
	КонецЦикла;
КонецПроцедуры

Процедура СформироватьПакетыОбмена(Узел)
	УстановитьПривилегированныйРежим(Истина);
	
	ПараметрыСеанса.УзелИнтегрированнойСистемы = Узел; // для кода, формирующего XDTO-объекты
	
	МассивНеобработанныхОбъектов = Новый Массив;	
	//Сначала получаем все данные с момента последнего обмена
	НомерСообщения = 1;
	ПланыОбмена.ВыбратьИзменения(Узел, НомерСообщения);
		
	// Выборка всех изменений
	ДанныеДляПередачи = ПолучитьДанныеДляПередачи(Узел, НомерСообщения);
		
	//КоличествоОбъектовВсего = ДанныеДляПередачи.Количество();
	//ВВыборкеЕстьДанные = КоличествоОбъектовВсего > 0;
		НачатьТранзакцию();
	//В цикле по выбранным объектам формируем сообщения и заполняем данными
	Для Каждого ЭлементДанных Из ДанныеДляПередачи Цикл
			ОбъектыXDTO = Новый Массив;
			ЗаписиXDTO = Новый Массив;

			Сообщение = СоздатьНовоеСообщение(Узел);
			НачалоПодготовки = ТекущаяУниверсальнаяДатаВМиллисекундах();
			ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
			ЗаписьXML = Новый ЗаписьXML;
			ЗаписьXML.ОткрытьФайл(ИмяВременногоФайла, "UTF-8");
			ЗаписьXML.ЗаписатьОбъявлениеXML();
			Попытка
				ПолучитьXDTOИзОбъекта(ЭлементДанных, ОбъектыXDTO, ЗаписиXDTO);
				//ВызватьИсключение("тест"); //тестируем ошибочную ситуацию
			Исключение
				Инфо = ИнформацияОбОшибке();
				ЗаписьЖурналаРегистрации(
					НСтр("ru = 'Обмен с интегрированными системами.Формирование сообщения'", Метаданные.ОсновнойЯзык.КодЯзыка),
					УровеньЖурналаРегистрации.Ошибка,,
					ЭлементДанных,
					ПодробноеПредставлениеОшибки(Инфо));
				//ВызватьИсключение;
				
				//Если формирование объекта прошло с ошибкой, тогда удаляем сообщение для этого пакета, очищаем записьХМЛ
				СообщениеОбъект = Сообщение.ПолучитьОбъект();
				СообщениеОбъект.Удалить();
				ЗаписьXML.Закрыть();
				УдалитьФайлы(ИмяВременногоФайла);
				МассивНеобработанныхОбъектов.Добавить(ЭлементДанных);
			    Продолжить;				
			КонецПопытки;
			// Расчет процента готовности сообщения.
			// Максимальное значение 99, т.к. необходимо гарантировать, 
			//	что не будет выполняться попытка передать сообщение клиенту до того,
			//	как данные сообщения будут записаны.
			СчетчикОбъектов = 1;
			ПроцентГотовности = Окр(99 * СчетчикОбъектов);
			РегистрыСведений.СтепеньГотовностиСообщенийИнтегрированныхСистем.УстановитьПроцентГотовности(
				Сообщение, ПроцентГотовности);
				
				КонецПодготовки = ТекущаяУниверсальнаяДатаВМиллисекундах();
		
			РегистрыСведений.СведенияОСообщенияхОбменаСИнтегрированнымиСистемами.ЗаписатьВремяПодготовки(
			Сообщение,
			(КонецПодготовки - НачалоПодготовки)/1000);

			
			ВыгрузитьМассивXDTOВСообщение(ИмяВременногоФайла, ЗаписьXML, ОбъектыXDTO, ЗаписиXDTO, Сообщение);
			УдалитьФайлы(ИмяВременногоФайла);

		КонецЦикла;
		ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерСообщения);
		//Если были ошибочные данные, перерегистрируем их на узле
		Если МассивНеобработанныхОбъектов.Количество()>0 Тогда
			Для Каждого ОшибочныйОбъект Из МассивНеобработанныхОбъектов Цикл
				ПланыОбмена.ЗарегистрироватьИзменения(Узел,ОшибочныйОбъект);
			КонецЦикла;
		КонецЕслИ;
		ЗафиксироватьТранзакцию();
КонецПроцедуры


&Вместо("ПолучитьИзменения")
Функция is4b_ПолучитьИзменения(Сообщение)
	Если ПолучитьФункциональнуюОпцию("ИспользоватьСинхронизациюСИнтегрированнымиСистемами") = Ложь Тогда 
		Константы.ИспользоватьСинхронизациюСИнтегрированнымиСистемами.Установить(Истина);
	КонецЕсли; 
	
	Ответ = ОбработкаЗапросовXDTO.СоздатьОбъект("DMGetChangesResponse");
	Узел = ОбработкаЗапросовXDTOКОРП.УзелИнтегрированнойСистемыПоСообщению(Сообщение);
	
	ИдентификаторПринятогоСообщения = Сообщение.lastMessageId;
	
	Если ИдентификаторПринятогоСообщения <> Неопределено Тогда
		Запрос = Новый Запрос;
		Запрос.Текст = 
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	СообщенияИнтегрированныхСистем.Ссылка
			|ИЗ
			|	Справочник.СообщенияИнтегрированныхСистем КАК СообщенияИнтегрированныхСистем
			|ГДЕ
			|	СообщенияИнтегрированныхСистем.ПометкаУдаления = ЛОЖЬ
			|	И СообщенияИнтегрированныхСистем.ИдентификаторСообщения = &ИдентификаторСообщения
			|	И СообщенияИнтегрированныхСистем.Входящее = ЛОЖЬ";
		Запрос.УстановитьПараметр("ИдентификаторСообщения", Строка(ИдентификаторПринятогоСообщения));
		ВыборкаПринятыеСообщения = Запрос.Выполнить().Выбрать();
		Если ВыборкаПринятыеСообщения.Следующий() Тогда
			ПринятоеСообщение = ВыборкаПринятыеСообщения.Ссылка;
			ПринятоеСообщениеОбъект = ПринятоеСообщение.ПолучитьОбъект();
			ПринятоеСообщениеОбъект.УстановитьПометкуУдаления(Истина);
			РегистрыСведений.СведенияОСообщенияхОбменаСИнтегрированнымиСистемами.ЗаписатьДатуПередачиКлиенту(
				ПринятоеСообщение,
				ТекущаяДатаСеанса());
			ИдентификаторПринятогоСообщения = Неопределено;
		Иначе
			ИдентификаторПринятогоСообщения = Неопределено;
		КонецЕсли;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	СообщенияИнтегрированныхСистем.Ссылка,
		|	СообщенияИнтегрированныхСистем.ДанныеСообщения КАК Данные,
		|	СообщенияИнтегрированныхСистем.ДатаСоздания КАК ДатаСоздания,
		|	СообщенияИнтегрированныхСистем.ИдентификаторСообщения
		|ИЗ
		|	Справочник.СообщенияИнтегрированныхСистем КАК СообщенияИнтегрированныхСистем
		|ВНУТРЕННЕЕ СОЕДИНЕНИЕ
		|	РегистрСведений.ОчередиСообщенийОбменаСИнтегрированнымиСистемами КАК ОчередиСообщенийОбменаСИнтегрированнымиСистемами
		|ПО
		|	СообщенияИнтегрированныхСистем.Очередь = ОчередиСообщенийОбменаСИнтегрированнымиСистемами.Очередь
		|ВНУТРЕННЕЕ СОЕДИНЕНИЕ
		|	РегистрСведений.СтепеньГотовностиСообщенийИнтегрированныхСистем КАК СтепеньГотовностиСообщенийИнтегрированныхСистем
		|ПО
		|	СообщенияИнтегрированныхСистем.Ссылка = СтепеньГотовностиСообщенийИнтегрированныхСистем.Сообщение
		|ГДЕ
		|	ОчередиСообщенийОбменаСИнтегрированнымиСистемами.ИнтегрированнаяСистема = &ИнтегрированнаяСистема
		|	И НЕ СообщенияИнтегрированныхСистем.ПометкаУдаления
		|	И СтепеньГотовностиСообщенийИнтегрированныхСистем.ПроцентГотовности = 100
		|
		|УПОРЯДОЧИТЬ ПО
		|	ДатаСоздания УБЫВ";
	Запрос.УстановитьПараметр("ИнтегрированнаяСистема", Узел);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Если Выборка.Следующий() Тогда
		
		ИмяФайлаСообщенияОбмена = ПолучитьИмяВременногоФайла("xml");
		ДвоичныеДанные = Выборка.Данные.Получить();
		ДвоичныеДанные.Записать(ИмяФайлаСообщенияОбмена);
		СсылочныйТип = ФабрикаXDTO.Тип("http://www.1c.ru/dm", "DMObject");
			
		ЧтениеXML = Новый ЧтениеXML;
		ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщенияОбмена);
		
		ЧтениеXML.Прочитать(); // корневой элемент "Message"
		
		ЧтениеXML.Прочитать();
		Пока ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Цикл
			ТипXDTO = ФабрикаXDTO.Тип("http://www.1c.ru/dm", ЧтениеXML.Имя);
			ОбъектXDTO = ФабрикаXDTO.ПрочитатьXML(ЧтениеXML, ТипXDTO);
			Если СсылочныйТип.ЭтоПотомок(ТипXDTO) Тогда
				Ответ.objects.Добавить(ОбъектXDTO);
			Иначе // записи РС и тому подобные объекты не ссылочных типов
				Ответ.records.Добавить(ОбъектXDTO);
			КонецЕсли;
		КонецЦикла;
			
		Ответ.messageId = Строка(Выборка.ИдентификаторСообщения);
		
	КонецЕсли; 
	
	Возврат Ответ;
КонецФункции


 

Итог: синхронизация и бесшовная интеграция по правилам была настроена и запущена. При возникновении ошибок обмен не останавливается, ошибки фиксируются. Да, не совсем правильно помечать ошибочные пакеты из очереди как обработанные, но в нашем случае по ошибкам будет настроено оповещение ответственных лиц и каждый случай будет проверяться в дальнейшем. Как показывает практика, даже если разворачивать "из коробки" типовые решения, то корректно они работают далеко не всегда. 

Комплексная автоматизация документооборот внедрение интеграция обмен синхронизация

См. также

Как реорганизовать работу проектного департамента, чтобы быть №1

Внедрение изменений Бесплатно (free)

Методики быстрореагирующего производства и QRM-ячейки применимы не только к станкам, но и к проектным командам. О том, как за счет разделения проектного офиса на многофункциональные QRM-ячейки обеспечить равномерную загрузку работу сотрудников, вырасти в два раза и существенно повысить лояльность заказчиков и коллектива, пойдет речь в статье.

14.02.2024    556    0    user1270271    2    

7

Управление ожиданиями на проекте

Работа с заинтересованными сторонами Бесплатно (free)

Каждый человек, который включается в проект после согласования контура автоматизации, имеет свое внутреннее понимание того, как должна работать система. О том, как определить в проекте ключевых функциональных специалистов и конкретные цели, поддерживать открытость при взаимодействии с заказчиком и передать проект на сервисное сопровождение, расскажем в статье.

08.02.2024    452    0    izybaevda    0    

5

Как внедрить 1С:ERP за 2 года и не сойти с ума

Анализ предметной области Анализ потребностей и поиск решений Внедрение изменений Бесплатно (free)

Для руководителей подразделений новые проекты вызывают желание получить максимальный эффект от реализации идей, а также опасения, верно ли выбран ориентир нововведений. О том, как справиться с трудностями, дойти до цели и внедрить 1С:ERP на производственном предприятии, ежедневно выпускающем десятки тысяч единиц готовой продукции, расскажем в статье.

30.01.2024    6701    0    user1578851    16    

16

Свободное программное обеспечение в крупной компании – миф или реальность? Как мы переводили 2500 пользователей на Linux

Внедрение изменений Бесплатно (free)

Переход на свободное программное обеспечение – серьезное испытание и для бизнес-пользователей, и для ИТ-подразделения. Нужно учесть много факторов, найти компромиссы и поменять привычки. О «пяти стадиях принятия неизбежного» и успешном преодолении трудностей при переводе ИТ-инфраструктуры автодилерских центров на Linux расскажем в статье.

29.01.2024    2418    0    user1063453    2    

5

Зачем нужны аналитики на проектах автоматизации

Анализ потребностей и поиск решений Бесплатно (free)

Исторически сложилось так, что аналитик 1С многими воспринимается как вечный падаван, который обеспечивает разработчиков информацией, а пользователей – инструкциями. Не согласимся с таким подходом и на примере реального кейса покажем, почему именно аналитик должен стать лидером проекта автоматизации.

18.01.2024    1590    0    user1754524    19    

12

Радио "Аналитик", 7 выпуск 2 сезона. Про работу аналитика с бизнесом и повышение бизнес-компетенций с Константином Семёновым

Анализ предметной области Работа с заинтересованными сторонами Анализ потребностей и поиск решений

В седьмом выпуске второго сезона подкаста Радио “Аналитик“ поговорили о том, что такое бизнес-компетенции, для чего они нужны аналитику, к чему может привести их отсутствие и как их развивать.

28.11.2023    414    0    Radio_Analyst    0    

2

Радио "Аналитик", 4 выпуск 2 сезона. Про решение проблем с Анастасией Московкиной

Анализ потребностей и поиск решений

В четвертом выпуске второго сезона подкаста Радио “Аналитик“ поговорили, как анализировать и приоритизировать проблемы, как работать с неопределенностью и решениями, которые приняли без нас.

17.10.2023    357    0    Radio_Analyst    0    

2
Комментарии
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
1. Torin 741 10.11.20 14:58 Сейчас в теме
(0) Отличная статья.+
user1174740; +1 Ответить
3. maks_20 164 10.11.20 16:06 Сейчас в теме
28. hdv 15.11.21 23:02 Сейчас в теме
Спасибо за статью, многое прояснило.

(3) maks_20 вы пишите
"Также столкнулись с такой проблемой: в КА заявку перевели в статус "К оплате", через некоторое время из ДО прилетает статус "Согласовано". Пришлось на стороне КА делать проверку, если статус "К оплате", то обмен его уже изменить не может. Такие заявки контролируются ответственным пользователем."
но не указали как это решили. у нас ровно такая же проблема. Казначеи не дожидаясь согласования в ДО переводят в ERP заявку в статус "К оплате", т.к. знают что платеж точно согласуют, а платить надо оперативно (например зарплата, налоги). И при изменении статуса останавливается обмен, т.к. типовая проверка не дает менять статус "К оплате".
Прошу вас поделиться кодом на произвольном языке в правилах для Статуса как вы проверяете уже присвоенный статус в объекте КА.
Буду очень благодарен
29. maks_20 164 16.11.21 11:17 Сейчас в теме
(28) Добрый день. Данную проблему решали не в правилах интеграции. В расширении для процедуры модуля объекта ЗаявкаНаРасходованиеДенежныхСредств заменил процедуру ПроверитьНаличиеОплатыЗаявки на свою:

&Вместо("ПроверитьНаличиеОплатыЗаявки")
Процедура is4b_ПроверитьНаличиеОплатыЗаявки(Отказ)
	Если Не ЭтоНовый() Тогда 
		//bmv 22_10_20
		Попытка
		СтарыйСтатус = Ссылка.Статус;
		Если СтарыйСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате
			И Статус <> Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате
			И ПараметрыСеанса.ТекущийПользователь.Наименование="<Не указан>" Тогда     //Фоновое задание, если пользователь не указан для него в настройках
			Статус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате;
			ЗаписьЖурналаРегистрации("Попытка смена статуса с Оплачено",УровеньЖурналаРегистрации.Информация,,Ссылка);
			Возврат;
		КонецЕсли;	
		Исключение
		//только для сохранения работоспособности раб базы
		КонецПопытки;
		//bmv 22_10_20	
		Если Статус <> Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате Тогда
		
		УстановитьПривилегированныйРежим(Истина);
		
		Запрос = Новый Запрос("
		|ВЫБРАТЬ
		|	ДенежныеСредства.СуммаРасход КАК Оплачено
		|ИЗ
		|	РегистрНакопления.ДенежныеСредстваКВыплате.Обороты(,,Период,
		|		ЗаявкаНаРасходованиеДенежныхСредств = &Заявка
		|	) КАК ДенежныеСредства
		|ГДЕ
		|	ДенежныеСредства.СуммаРасход > 0
		|");
		Запрос.УстановитьПараметр("Заявка", Ссылка);
		
		Выборка = Запрос.Выполнить().Выбрать();
		Если Выборка.Следующий() Тогда
			Текст = НСтр("ru = 'Заявка оплачена. Нельзя изменять статус заявки ""К оплате""'");
			ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
				Текст,
				ЭтотОбъект,
				"Статус",
				,
				Отказ);
		КонецЕсли;
		
	КонецЕсли;
	КонецЕсли;
КонецПроцедуры
Показать
30. hdv 22.11.21 10:59 Сейчас в теме
(29)
Добрый день. Мне все же удалось решить проблему через шаблон правил бесшовной интеграции. Если кому-то будет интересным, решение:
СтатусЗаявкиERP = Неопределено;
Параметры.Результат = Неопределено;

Если Параметры.Приемник <> Неопределено Тогда
	СтатусЗаявкиERP = Параметры.Приемник.Статус;
КонецЕсли;

Если СтатусЗаявкиERP <> Неопределено Тогда // удалось получить ссылку на объект и его статус, проверяем дальше
	Если СтатусЗаявкиERP <> Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.КОплате Тогда
		пСтатус = Неопределено;
		Попытка
			Если Параметры.Источник.statusApproval.name = "Согласован" Тогда
			    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.Согласована;
			ИначеЕсли Параметры.Источник.statusApproval.name = "Не согласован" Тогда
			    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.НеСогласована;
			ИначеЕсли Параметры.Источник.statusApproval.name = "На согласовании" Тогда
			    пСтатус = Перечисления.СтатусыЗаявокНаРасходованиеДенежныхСредств.НеСогласована;
			КонецЕсли;
		Исключение
		КонецПопытки;
	Иначе
		пСтатус = СтатусЗаявкиERP;
	КонецЕсли;
	Параметры.Результат = пСтатус;
КонецЕсли;
Показать
2. Vasvas05 22 10.11.20 15:14 Сейчас в теме
4. RustIG 1351 10.11.20 17:22 Сейчас в теме
(0) спасибо за опыт!
как полит.корректно вы написали в конце
Как показывает практика, даже если разворачивать "из коробки" типовые решения, то корректно они работают далеко не всегда.


вопросы из зала:
1) что за префикс "is4b_" ?
2) сколько человек с вашей стороны участвовало при решении проблем интеграции, тестировании, переговоров с заказчиком?
3) сколько времени потрачено на решение проблем?
TerveRus; +1 Ответить
5. maks_20 164 10.11.20 19:54 Сейчас в теме
(4) Префикс нашей команды, отмечаем им свои доработки, чтобы не путать с чужими. На внедрении ДО участвовало 3 человека: руководитель проекта, он же общался с заказчиком, специалист-консультант (занимался настройкой бизнес-процессов и тестированием) и программист. На настройку синхронизации и интеграции (с периодическим обсуждениями с заказчиком) ушло почти 2 недели.
6. 5277209 11.11.20 11:40 Сейчас в теме
Отличная статья! Спасибо! Уточните плиз, ДО проф или корп?
7. maks_20 164 11.11.20 11:55 Сейчас в теме
(6) Спасибо за отзыв. ДО версии КОРП.
8. baykovsky 11.11.20 12:02 Сейчас в теме
Спасибо за статью.
Типовые правила обмена между ДО и КА не предусматривают возможности отбора объектов. Т.е. грузится абсолютно все. Нет возможности установить отбор по одной организации или например указать, что синхронизировать надо только номенклатуру и контрагентов. Как вы решали эту проблему?
11. maks_20 164 11.11.20 12:42 Сейчас в теме
(8) дорабатывали правила регистрации.
TerveRus; +1 Ответить
9. kolya_tlt 86 11.11.20 12:15 Сейчас в теме
информация о стабильных релизах БИД не разглашается по понятным причинам. обратившись к сообществу на фб или вк вы бы получили стабильную сборку от команды разработки ДО или релиз на который нужно обновиться.
10. maks_20 164 11.11.20 12:37 Сейчас в теме
(9) Большая часть проблем именно в модулях на стороне КА, мы ставили самые последние релизы и там те же проблемы, по крайней мере касательно интеграции.
12. Kovekh 11.11.20 14:02 Сейчас в теме
Добрый человек, спасибо вам большое за первый пункт!
Вы бы знали, как долго я пытался найти эту ошибку. Такая вываливалась при обмене ERP-ДО в части контрагентов и организаций. Причём ДО уже у нас поднялся с 12 до 21, а в синхронизации всё та же дичь)
13. user1080690 11.11.20 16:29 Сейчас в теме
При всем уважении, статья вызывает улыбку.
Крупная компания и проект на 3 человека с акцентом на копание в коде выглядит забавно.
14. maks_20 164 11.11.20 16:39 Сейчас в теме
(13) На всем проекте работает 11 человек. Конкретно документооборотом занимается 3 человека. Если для Вас статья получилась забавной, что ж, это Ваше мнение, спорить с ним смысла не вижу.
user591389_aska_rabota; papche; RSConsulting; +3 Ответить
16. papche 602 12.11.20 10:08 Сейчас в теме
(13) Я думаю, на описанные задачи можно было бы посадить команду в 10 чел. И написать свою подсистему с обменом, повсюду вплетая типовой функционал. Ну и тогда было бы солиднее?
17. maks_20 164 12.11.20 10:47 Сейчас в теме
(16) Все возможно. вопрос в том, за чей счет будет вестись разработка. Ведь наладить типовой обмен в любом случае будет быстрее, чем разработать свою систему. Не каждый заказчик согласится оплачивать лишние часы. Разрабатывать аналог обмена за счет компании имеет смысл, если в дальнейшем планируется массовая продажа этих разработок другим клиентам.
18. papche 602 12.11.20 10:57 Сейчас в теме
(17) Ваш подход мне кажется рациональным. А размер команды должен быть адекватным в первую очередь выполняемым работам, а не размерам компании заказчика.
15. Константин С. 665 12.11.20 08:24 Сейчас в теме
Не реклама.
Берите Бит-финанс, там утверждение заявок можно в одной системе сделать.
19. SergeyTY 13.11.20 08:49 Сейчас в теме
спасибо что выводите в свет проблемы 1С и делитесь с решениями. КА я бы сравнил с кактусом: колется, но приходится... пока донесешь проблему до техподдержки, приходишь к мысли что лучше самому все сделать вручную.
20. sulig 65 23.11.20 15:47 Сейчас в теме
Отличная статья. Прошел почти все этапы. "не те правила подставляются" - нет базы под рукой, но насколько я помню это решается условиями применимости. С итерациями - спорное решение, я разбирал каждое событие и фиксил чтобы подобный инцидент не приводил к остановке обмена, сейчас обмен встает не чаще 1 раза за 3 месяца. Как решили проблему с авторизацией или для вас это не являлось проблемой?
21. maks_20 164 24.11.20 09:34 Сейчас в теме
(20) Спасибо. Условиями применимости к сожалению не решалась проблема. Изначально хотели ими обойтись. По поводу итераций - тут было согласовано с заказчиком. Сейчас у нас сделан отчет, который три раза в день рассылает ошибки обмена. Ответственный за обмены человек анализирует ошибки и далее оперативно их исправляет. Массив ошибок с момента внедрения уменьшился в десятки раз. А с авторизацией проблем не было кстати.
22. vihrov_av 22.12.20 09:43 Сейчас в теме
Всё четко и по делу. Прошел каждый из этих шагов при внедрении ERP + ДО.
К пункту 2.3 Обмен статусами документов добавлю:
Периодически сталкивался с такой проблемой когда согласование в ДО прошло и статус в ДО поменялся, а в ERP нет. Спустя какое то время удалось выяснить что некоторые процессы пользователи считают супер срочными и создавай документы в ERP и запускай процесс согласования не закрывают сам документ, а сразу же обзванивают участников процесса для оперативности согласования. И так как объект заблокирован, регламентное задание не может его изменить.
23. LomayaZakat 11.05.21 13:34 Сейчас в теме
Спасибо. Всё тоже самое.
24. xKEEPERx 3 24.08.21 00:30 Сейчас в теме
Подскажите, а откуда берётся вот это?
// Выборка всех изменений для данной интегрированной системы
ИнтегрированныеОбъекты = ПолучитьМассивЗарегистрированныхДанных(УзелДокументооборота);
25. maks_20 164 06.09.21 08:24 Сейчас в теме
(24) Это типовая функция в модуле ИнтеграцияС1СДокументооборотОбмен
26. xKEEPERx 3 06.09.21 08:42 Сейчас в теме
(25)спасибо, уже разобрался. У меня она по другому называется.
27. Skripagan 29.09.21 12:10 Сейчас в теме
Отличная статья. Спасибо !
Один вопрос, может не по теме, но может сможете подсказать.

Как я понимаю, обмена по правилам между ЗУП - ДО нет . Т.е. начальная синхронизация в таком составе баз невозможна ? Спасибо.
Оставьте свое сообщение