Смена контрагента в реализации. УТ 11.4

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

Учитывая сложности с партнерами-контрагентами, проверил, какая процедура вызывается отладчиком:

Нашел место, где очищаются товары:

К сожалению, расширением сюда не подлезть.

Поэтому я решил сделать по другому — сохранять табличную часть товаров в начале процедуры, а при завершении восстанавливать:

&НаКлиенте
&Вместо("ПартнерПриИзменении")
Процедура дор_ПартнерПриИзменении(Элемент)
	//Сохраняем табличную часть 
	Адрес = СохранитьТЧТовары();	
	ПродолжитьВызов(Элемент);
	ВосстановитьТЧТовары(Адрес);	
КонецПроцедуры

&НаСервере
Функция СохранитьТЧТовары()
	ТЗ = Объект.Товары.Выгрузить();
	Возврат ПоместитьВоВременноеХранилище(ТЗ, ЭтаФорма.УникальныйИдентификатор)
КонецФункции

&НаСервере
Процедура ВосстановитьТЧТовары(Адрес)
	ТЗ = ПолучитьИзВременногоХранилища(Адрес);
	Объект.Товары.Загрузить(ТЗ);
	//Дальше вызовем два обработчика, чтобы корректно обновились итоги документа
	ОчищатьСтроки = Ложь;
	ОтвязатьВсеСтрокиОтЗаказа = Ложь;
	СкладПриИзмененииСервер(ОчищатьСтроки, ОтвязатьВсеСтрокиОтЗаказа);
	ЗаполнитьСлужебныеРеквизитыПоНоменклатуре();	
КонецПроцедуры

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

Поэтому отделаться «малой кровью не получится», придется писать полноценную отмену проведения цепочки и заново ее проводить. Текущая реализация обрабатывается особым образом, т.к. она в текущий момент проводится:

&НаСервере
Процедура ИзменитьКонтрагентаЗаказа(ТекущийОбъект) Экспорт
	
	ТекЗаказ = ТекущийОбъект.ЗаказКлиента;
	Если Не ЗначениеЗаполнено(ТекЗаказ) Тогда
		Возврат;
	КонецЕсли;
	
	Если ТекЗаказ.Контрагент = ТекущийОбъект.Контрагент Тогда
		//Сравниваем только контрагента, партнеры у контрагентов одинаковые
		//Партнер более широкая сущность, чем контрагенты
		Возврат;
	КонецЕсли;
	
	НачальноПроведен = ТекущийОбъект.Проведен;
	
	МассивКПроведению = Новый Массив();
	З = Новый Запрос(
	"ВЫБРАТЬ
	|	РеализацияТоваровУслуг.Ссылка КАК Ссылка
	|ИЗ
	|	Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
	|ГДЕ
	|	РеализацияТоваровУслуг.Проведен И РеализацияТоваровУслуг.ЗаказКлиента = &Заказ");
	З.УстановитьПараметр("Заказ", ТекЗаказ);
	Выборка = З.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Если Выборка.Ссылка = ТекущийОбъект.Ссылка Тогда
			РабочийОбъект = ТекущийОбъект;
		Иначе
			//У остальных реализаций тоже меняем контрагента
			РабочийОбъект = Выборка.Ссылка.ПолучитьОбъект();
			РабочийОбъект.Контрагент = ТекущийОбъект.Контрагент;
			РабочийОбъект.Партнер = ТекущийОбъект.Партнер;
			РабочийОбъект.Соглашение = ТекущийОбъект.Соглашение;
			РабочийОбъект.Договор = ТекущийОбъект.Договор;
			МассивКПроведению.Добавить(Выборка.Ссылка);
		КонецЕсли;
		Если НЕ ЗначениеЗаполнено(РабочийОбъект.Ссылка) Тогда
			Продолжить;	
		КонецЕсли;
		Если РабочийОбъект.Проведен Тогда
			РабочийОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
		КонецЕсли;
		Сообщить("Распроведена реализация: " + РабочийОбъект);
	КонецЦикла;
	
	О = ТекЗаказ.ПолучитьОбъект();
	О.Контрагент = ТекущийОбъект.Контрагент;
	О.Партнер = ТекущийОбъект.Партнер;
	О.Соглашение = ТекущийОбъект.Соглашение;
	О.Договор = ТекущийОбъект.Договор;
	О.Склад = ТекущийОбъект.Склад;
	Если О.Проведен Тогда
		О.Записать(РежимЗаписиДокумента.Проведение);
	Иначе
		О.Записать(РежимЗаписиДокумента.Запись);
	КонецЕсли;
	Сообщить("Изменен контрагент в заказе: " + О);
	
	Для Каждого СсылкаНаРеализацию ИЗ МассивКПроведению Цикл
		РабочийОбъект = СсылкаНаРеализацию.ПолучитьОбъект();
		Попытка
			РабочийОбъект.Записать(РежимЗаписиДокумента.Проведение);
			Сообщить("Проведена реализация: " + РабочийОбъект);
		Исключение
			Сообщить("Не удалось провести реализацию: " + РабочийОбъект + ", проведите ее вручную!", СтатусСообщения.Важное);
		КонецПопытки;
	КонецЦикла;

	//Восстанавлием проведение текущего объекта
	ТекущийОбъект.Проведен = НачальноПроведен;
	
КонецПроцедуры

&НаСервере
Процедура дор_ПередЗаписьюНаСервереПеред(Отказ, ТекущийОбъект, ПараметрыЗаписи)
	
	Если Отказ Тогда
		Возврат;
	КонецЕсли;
	
	ИзменитьКонтрагентаЗаказа(ТекущийОбъект);
	
КонецПроцедуры

Попробуем распровести реализацию 149 в этой цепочке:

При этом будут выданы сообщения о распроведении и проведении других документов:

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

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

Потом я забыл, что в других реализациях нужно менять контрагента и обработка на них спотыкалась, т.к. контрагент в заказах был уже поправлен, а в реализациях еще нет.

И наконец, для меня стало приятным сюрпризом, что при вызове из формы событие «Перед записью на сервере» не вызывается в транзакции, т.е. в случае ошибки проведения/распроведения ситуация так и фиксируется, что в принципе, удобнее пользователю.

Среда: УТ 11.4.13.46 Объем: 1.5 час.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

Добавить комментарий

Ваш адрес email не будет опубликован.