gifts2017

Изменение сумм в Заказе покупателя в УНФ (обработка заполнения табличной части Запасы)

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

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

Появилась необходимость в УНФ в заказах покупателей предоставлять ручные скидки. Например, уменьшить все суммы на 5%, или уменьшить все суммы так, чтобы итоговая сумма документа уменьшилась на 1000р., или сказать, что всё вместе продаётся за 10000р., и чтобы при этом все суммы пропорционально уменьшились/увеличились.

Во "взрослых" конфигурациях (УПП, УТ), насколько помню, есть спец.обработка таб.частей, которая позволяет решить эту задачу (а кроме неё ещё и много других) за пару кликов мыши. В УНФ такого не нашёл. Поэтому взялся за написание своего велосипеда. Большого опыта разработки для упр.приложения пока нет, поэтому буду благодарен за дельные замечания и предложения в комментариях.

Обработка добавляется в "Дополнительные отчеты и обработки" (Вид обработки = "Заполнение объекта"). После этого в документе Заказ покупателя появляется кнопка "Заполнить" с тремя командами:

  • "Скидка, %" - уменьшает все суммы в таб.части Запасы на указанный процент (если ввести отрицательное число, то наоборот увеличит на указанный процент).
  • "Скидка, сумма" - уменьшает все суммы в таб.части Запасы так, чтобы итоговая сумма документа уменьшилась на указанную сумму (если ввести отрицательное число, то наоборот итоговая сумма документа будет увеличена на эту сумму).
  • "Скидка, установить Итого" - уменьшает/увеличивает все суммы в таб.части Запасы так, чтобы итого по таб.части Запасы стало равно введённой сумме.

Код модуля обработки:

////////////////////////////////////////////////////////////////////////////////
// ПРОГРАММНЫЙ ИНТЕРФЕЙС

// Возвращает сведения о внешней обработке.
Функция СведенияОВнешнейОбработке() Экспорт
	
	ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
	
	ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
	ПараметрыРегистрации.Версия = "0.99";
	ПараметрыРегистрации.Назначение.Добавить("Документ.ЗаказПокупателя");
	
	НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
	НоваяКоманда.Представление = НСтр("ru = 'Скидка, %'");
	НоваяКоманда.Идентификатор = "УстановитьСкидкуПроцент";
	НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
	НоваяКоманда.ПоказыватьОповещение = Истина;
	
	НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
	НоваяКоманда.Представление = НСтр("ru = 'Скидка, сумма'");
	НоваяКоманда.Идентификатор = "УстановитьСкидкуСумма";
	НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
	НоваяКоманда.ПоказыватьОповещение = Истина;
	
	НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
	НоваяКоманда.Представление = НСтр("ru = 'Скидка, установить Итого'");
	НоваяКоманда.Идентификатор = "УстановитьСуммуИтого";
	НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
	НоваяКоманда.ПоказыватьОповещение = Истина;
	
	Возврат ПараметрыРегистрации;
	
КонецФункции

Код модуля формы (сама форма не содержит никаких реквизитов и элементов):

// {{{ Код взят из модуля формы документа ЗаказПокупателя (обработка события "изменение поля Сумма таб.части Запасы").
// Изменение кода свелось по большому счету к передаче ДокОбъект во все процедуры и обращение к "ДокОбъект" (вместо "Объект") внутри процедур.
// < Начало кода, права на который принадлежат фирме 1С

// Рассчитывается сумма НДС в строке табличной части.
//
&НаСервере
Процедура РассчитатьСуммуНДС(ДокОбъект, СтрокаТабличнойЧасти)
	
	СтавкаНДС = УправлениеНебольшойФирмойПовтИсп.ПолучитьЗначениеСтавкиНДС(СтрокаТабличнойЧасти.СтавкаНДС);
	
	СтрокаТабличнойЧасти.СуммаНДС = ?(ДокОбъект.СуммаВключаетНДС, 
									  СтрокаТабличнойЧасти.Сумма - (СтрокаТабличнойЧасти.Сумма) / ((СтавкаНДС + 100) / 100),
									  СтрокаТабличнойЧасти.Сумма * СтавкаНДС / 100);
											
КонецПроцедуры // ПересчитатьСуммыДокумента() 

// Процедура пересчитывает суммы в платежном календаре.
//
&НаСервере
Процедура ПересчитатьПлатежныйКалендарь(ДокОбъект, ПересчитыватьПроцент = Ложь)
	
	// +++ пересчет процента, а не суммы оплаты
	// для решения моей частной задачи нужно чтобы указанная в документе сумма оплаты не менялась, а менялся процент оплаты
	Если ПересчитыватьПроцент Тогда
		Для каждого ТекСтрока Из ДокОбъект.ПлатежныйКалендарь Цикл
			Всего = ДокОбъект.Запасы.Итог("Всего") + ДокОбъект.Работы.Итог("Всего");
			ТекСтрока.ПроцентОплаты = ?(Всего = 0, 0, ТекСтрока.СуммаОплаты / Всего * 100);
			ТекСтрока.СуммаНДСОплаты = Окр((ДокОбъект.Запасы.Итог("СуммаНДС") + ДокОбъект.Работы.Итог("СуммаНДС")) * ТекСтрока.ПроцентОплаты / 100, 2, 1);
		КонецЦикла;
		Возврат;
	КонецЕсли;
	// пересчет процента, а не суммы оплаты +++
	
	Для каждого ТекСтрока Из ДокОбъект.ПлатежныйКалендарь Цикл
		ТекСтрока.СуммаОплаты = Окр((ДокОбъект.Запасы.Итог("Всего") + ДокОбъект.Работы.Итог("Всего")) * ТекСтрока.ПроцентОплаты / 100, 2, 1);
		ТекСтрока.СуммаНДСОплаты = Окр((ДокОбъект.Запасы.Итог("СуммаНДС") + ДокОбъект.Работы.Итог("СуммаНДС")) * ТекСтрока.ПроцентОплаты / 100, 2, 1);
	КонецЦикла;
	
КонецПроцедуры // ПересчитатьПлатежныйКалендарь()

// Процедура - обработчик события ПриИзменении поля ввода Сумма.
//
&НаСервере
Процедура ЗапасыСуммаПриИзменении(ДокОбъект)
	
	Для Каждого СтрокаТабличнойЧасти Из ДокОбъект.Запасы Цикл
	
		// Цена.
		Если СтрокаТабличнойЧасти.Количество <> 0 Тогда
			СтрокаТабличнойЧасти.Цена = СтрокаТабличнойЧасти.Сумма / СтрокаТабличнойЧасти.Количество;
		КонецЕсли;
		
		// Скидка.
		Если СтрокаТабличнойЧасти.ПроцентСкидкиНаценки = 100 Тогда
			СтрокаТабличнойЧасти.Цена = 0;
		ИначеЕсли СтрокаТабличнойЧасти.ПроцентСкидкиНаценки <> 0 И СтрокаТабличнойЧасти.Количество <> 0 Тогда
			СтрокаТабличнойЧасти.Цена = СтрокаТабличнойЧасти.Сумма / ((1 - СтрокаТабличнойЧасти.ПроцентСкидкиНаценки / 100) * СтрокаТабличнойЧасти.Количество);
		КонецЕсли;
			
		// Сумма НДС.
		РассчитатьСуммуНДС(ДокОбъект, СтрокаТабличнойЧасти);
		
		// Всего.
		СтрокаТабличнойЧасти.Всего = СтрокаТабличнойЧасти.Сумма + ?(ДокОбъект.СуммаВключаетНДС, 0, СтрокаТабличнойЧасти.СуммаНДС);
		
	КонецЦикла;
		
	// Платежный календарь.
	ПересчитатьПлатежныйКалендарь(ДокОбъект, Истина); // для штатного пересчета платежного календаря нужно во втором параметре передать Ложь или не указывать его вообще
	
КонецПроцедуры // ЗапасыСуммаПриИзменении()
// Конец кода, права на который принадлежат фирме 1С / >
// Код взят из модуля формы документа ЗаказПокупателя (обработка события "изменение поля Сумма таб.части Запасы"). }}}

// отсюда и до конца файла GPLv3

&НаСервере
Процедура УстановитьСкидкуПроцент(ДокОбъект, ЗначСкидки)
	
	Для Каждого СтрокаТЧ Из ДокОбъект.Запасы Цикл
		СтрокаТЧ.Сумма = Окр(СтрокаТЧ.Сумма * (100 - ЗначСкидки) / 100, 2);
	КонецЦикла;
	
КонецПроцедуры

&НаСервере
Процедура УстановитьСкидкуСумма(ДокОбъект, ЗначСкидки)
	
	МассивСумм = ДокОбъект.Запасы.ВыгрузитьКолонку("Сумма");
	МассивСкидок = ОбщегоНазначения.РаспределитьСуммуПропорциональноКоэффициентам(ЗначСкидки, МассивСумм);
	
	Для Сч = 0 По МассивСумм.Количество() - 1 Цикл
		МассивСумм[Сч] = МассивСумм[Сч] - МассивСкидок[Сч];
	КонецЦикла;
	
	ДокОбъект.Запасы.ЗагрузитьКолонку(МассивСумм, "Сумма");
	
КонецПроцедуры

&НаСервере
Процедура УстановитьСуммуИтого(ДокОбъект, ЗначСкидки)
	
	МассивСумм = ДокОбъект.Запасы.ВыгрузитьКолонку("Сумма");
	МассивРез = ОбщегоНазначения.РаспределитьСуммуПропорциональноКоэффициентам(ЗначСкидки, МассивСумм);
	
	ДокОбъект.Запасы.ЗагрузитьКолонку(МассивРез, "Сумма");
	
КонецПроцедуры

&НаСервере
Процедура УстановитьСкидкуНаСервере(ИмяКоманды, ОбъектыНазначения, ЗначСкидки)
	
	Для Каждого ДокСсылка Из ОбъектыНазначения Цикл
		
		Если ТипЗнч(ДокСсылка) <> Тип("ДокументСсылка.ЗаказПокупателя") Тогда
			Продолжить;
		КонецЕсли;
		
		ДокОбъект = ДокСсылка.ПолучитьОбъект();
		
		Если ДокОбъект.Запасы.Количество() = 0 Тогда
			Продолжить;
		КонецЕсли;
		
		Если ИмяКоманды = "УстановитьСкидкуПроцент" Тогда
			УстановитьСкидкуПроцент(ДокОбъект, ЗначСкидки);
		ИначеЕсли ИмяКоманды = "УстановитьСкидкуСумма" Тогда
			УстановитьСкидкуСумма(ДокОбъект, ЗначСкидки);
		ИначеЕсли ИмяКоманды = "УстановитьСуммуИтого" Тогда
			УстановитьСуммуИтого(ДокОбъект, ЗначСкидки);
		КонецЕсли;
		
		ЗапасыСуммаПриИзменении(ДокОбъект);
		
		ДокОбъект.Записать();
		
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьКоманду(ИмяКоманды, ОбъектыНазначения) Экспорт
	
	Если ОбъектыНазначения.Количество() > 1 Тогда
		// не будем давать пользователю возможность массово устанавливать скидки
		ВызватьИсключение НСтр("ru = 'Установка скидок для нескольких документов не поддерживается!'");
		Возврат;
	КонецЕсли;
	
	ЗначСкидки = 0;
	ЧислоВведено = Ложь;
	Если ИмяКоманды = "УстановитьСкидкуПроцент" Тогда
		ЧислоВведено = ВвестиЧисло(ЗначСкидки, НСтр("ru = 'Уменьшить на %'"), 4, 1);
	ИначеЕсли ИмяКоманды = "УстановитьСкидкуСумма" Тогда
		ЧислоВведено = ВвестиЧисло(ЗначСкидки, НСтр("ru = 'Уменьшить на сумму'"), 15, 2);
	ИначеЕсли ИмяКоманды = "УстановитьСуммуИтого" Тогда
		ЧислоВведено = ВвестиЧисло(ЗначСкидки, НСтр("ru = 'Установить сумму Итого = '"), 15, 2);
	Иначе
		ВызватьИсключение "Неизвестная команда """ + ИмяКоманды + """!";
		Возврат;
	КонецЕсли;
	
	Если НЕ ЧислоВведено Тогда
		Возврат;
	КонецЕсли;
	
	Если НЕ ЗначениеЗаполнено(ЗначСкидки) Тогда
		Возврат;
	КонецЕсли;

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

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

Наименование Файл Версия Размер Кол. Скачив.
UstanovkaSkidokNaZapasyZakaza.epf.7z
.7z 5,48Kb
04.11.14
31
.7z 5,48Kb 31 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Владимир Астапов (vlastapov) 27.12.14 12:26
В УНФ, редакция 1.5 (1.5.2.25) выдает ошибку "Использование модальных окон в данном режиме запрещено!". Можно исправить?
2. q_i 30.12.14 12:53
(1) vlastapov, вместо процедуры "Процедура ВыполнитьКоманду(ИмяКоманды, ОбъектыНазначения) Экспорт" вставьте (см. прилагаемый файл):
&НаКлиенте
Процедура ВыполнитьКоманду(ИмяКоманды, ОбъектыНазначения) Экспорт
	
	Если ОбъектыНазначения.Количество() > 1 Тогда
		// не будем давать пользователю возможность массово устанавливать скидки
		ВызватьИсключение НСтр("ru = 'Установка скидок для нескольких документов не поддерживается!'");
		Возврат;
	КонецЕсли;
	
	ЗначСкидки = 0;
	Если ИмяКоманды = "УстановитьСкидкуПроцент" Тогда
		ПоказатьВводЧисла(Новый ОписаниеОповещения("ПродолжитьВыполнениеПослеВводаЧисла", ЭтаФорма, Новый Структура("ИмяКоманды, ОбъектыНазначения", ИмяКоманды, ОбъектыНазначения)), ЗначСкидки, НСтр("ru = 'Уменьшить на %'"), 4, 1);
	ИначеЕсли ИмяКоманды = "УстановитьСкидкуСумма" Тогда
		ПоказатьВводЧисла(Новый ОписаниеОповещения("ПродолжитьВыполнениеПослеВводаЧисла", ЭтаФорма, Новый Структура("ИмяКоманды, ОбъектыНазначения", ИмяКоманды, ОбъектыНазначения)), ЗначСкидки, НСтр("ru = 'Уменьшить на сумму'"), 15, 2);
	ИначеЕсли ИмяКоманды = "УстановитьСуммуИтого" Тогда
		ПоказатьВводЧисла(Новый ОписаниеОповещения("ПродолжитьВыполнениеПослеВводаЧисла", ЭтаФорма, Новый Структура("ИмяКоманды, ОбъектыНазначения", ИмяКоманды, ОбъектыНазначения)), ЗначСкидки, НСтр("ru = 'Установить сумму Итого = '"), 15, 2);
	Иначе
		ВызватьИсключение "Неизвестная команда """ + ИмяКоманды + """!";
		Возврат;
	КонецЕсли;
	
КонецПроцедуры	

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

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

Ещё отвалилось обновление открытой формы документа. При поиске формы с помощью кода
ПараметрыФормы = Новый Структура("Ключ", ДокСсылка);
ТекФорма = ПолучитьФорму("Документ.ЗаказПокупателя.Форма.ФормаДокумента", ПараметрыФормы);
ТекФорма.Открыта() возвращает Ложь. Пока некогда разбираться с этим. Буду благодарен коллегам если подскажут как найти и обновить форму открытого документа, из которого была вызвана процедура заполнения.
Прикрепленные файлы:
UstanovkaSkidokNaZapasyZakaza_dlya_unf1.5.2.epf.7z
3. Владислав Норченко (nvk1234) 29.11.15 19:26
Хорошо ли при вводе процента скидки писать непосредственно в объект документа? Ведь пользователю может не понравиться результат...
4. q_i 30.11.15 11:25
(3) nvk1234, когда писалась эта обработка (а это было год назад), количество костылей, которыми нужно было обложить БСП, чтобы что-то хоть как-то работало стремилось к бесконечности.
На данный момент обработка устарела, и я не удаляю эту публикацию только из-за наличия хоть и мизерной, но всё-таки вероятности, что кому-то могут пригодиться какие-нибудь куски кода из неё.
Дорабатывать в ближайшее время не планирую ввиду отсутствия коммерческого заказа.
5. Игорь (akaky_2001) 29.01.16 20:49
Мне пригодилась, так что автору респект
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа