Драматическое округление до 10 копеек в продажах. УТ 11.5

Клиент захотел, чтобы цены и ручные скидки в заказах и реализациях округлялись до 10 копеек. Это способ решения проблемы с округлением НДС. Но только для рублевых документов.

Вот на этом моменте и возникла драма, которая усложнила решение задачи на добрый час.

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

Поэтому я решил вставлять валюту в кэшированные значения при открытии документа:

&НаКлиенте
Процедура дор_ПриОткрытииПосле(Отказ)
	//Обновляем кэшированные значения, добавляем туда свои параметры...
	дор_К.ДополнитьКэшированныеЗначения(КэшированныеЗначения, ЭтаФорма);
КонецПроцедуры

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

&НаКлиенте
Процедура дор_ДоговорПриИзмененииПеред(Элемент)
	дор_К.ДополнитьКэшированныеЗначения(КэшированныеЗначения, ЭтаФорма);
КонецПроцедуры

Вставка в кэшированные значения выглядит так:

Процедура ДополнитьКэшированныеЗначения(КэшированныеЗначения, Форма) Экспорт
	
	Если КэшированныеЗначения = Неопределено Тогда
		КэшированныеЗначения = ОбработкаТабличнойЧастиКлиентСервер.ПолучитьСтруктуруКэшируемыеЗначения();
	КонецЕсли;
	
	//Осипов - сохраняем валюту
	КэшированныеЗначения.Вставить("дор_Валюта", Форма.Объект.Валюта);
	КэшированныеЗначения.Вставить("дор_ТипОбъекта", ТипЗнч(Форма.Объект.Ссылка));

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

Я нашел метод ОбработкаТабличнойЧастиКлиентСервер.ПересчитатьСуммуВСтрокеТЧ, вмешательство в которое корректирует цену как при расчете по виду цены (при изменении номенклатуры, например), так и при ручной корректировке цены.

Скидку корректирую в методе после ОбработкаТабличнойЧастиКлиентСервер.ПересчитатьСуммуСУчетомРучнойСкидкиВСтрокеТЧ.


&После("ПересчитатьСуммуСУчетомРучнойСкидкиВСтрокеТЧ")
Процедура дор_ПересчитатьСуммуСУчетомРучнойСкидкиВСтрокеТЧ(ТекущаяСтрока, СтруктураДействий, КэшированныеЗначения)

	//Округляем цену и скидку до 10 копеек
	Если ТребуетсяОкруглениеДо10Копеек(КэшированныеЗначения) Тогда
		
		//Проверяем скидку и округляем ее до 10 копеек
		СтараяСуммаРучнойСкидки = ТекущаяСтрока.СуммаРучнойСкидки;
		Если НЕ ЦенаОкругленаДо10Копеек(СтараяСуммаРучнойСкидки) Тогда
			//Округляем сумму ручной скидки
			НоваяСуммаРучнойСкидки = ОкруглитьЦенуДо10Копеек(СтараяСуммаРучнойСкидки);
			ТекущаяСтрока.СуммаРучнойСкидки = НоваяСуммаРучнойСкидки;
			//Если сумма скидки больше, сумма меньше...
			ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма - (НоваяСуммаРучнойСкидки - СтараяСуммаРучнойСкидки);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры  

&Перед("ПересчитатьСуммуВСтрокеТЧ")
Процедура дор_ПересчитатьСуммуВСтрокеТЧ(ТекущаяСтрока, СтруктураДействий, КэшированныеЗначения)
	//Округляем цену и скидку до 10 копеек

	Если ТребуетсяОкруглениеДо10Копеек(КэшированныеЗначения) Тогда

		//Проверяем цену и округляем ее до 10 копеек
		СтараяЦена = ТекущаяСтрока.Цена;
		Если НЕ ЦенаОкругленаДо10Копеек(ТекущаяСтрока.Цена) Тогда
			НоваяЦена = ОкруглитьЦенуДо10Копеек(СтараяЦена);     
			ТекущаяСтрока.Цена = НоваяЦена;
		КонецЕсли;
		
	КонецЕсли;
КонецПроцедуры


Функция ТребуетсяОкруглениеДо10Копеек(КэшированныеЗначения) Экспорт                                        
	Возврат 	
	КэшированныеЗначения.Свойство("дор_Валюта") 
	И КэшированныеЗначения.дор_Валюта = дор_Кэш.ВалютаРегламентированногоУчета() 
	И КэшированныеЗначения.Свойство("дор_ТипОбъекта")  
	И ( 
		КэшированныеЗначения.дор_ТипОбъекта = Тип("ДокументСсылка.РеализацияТоваровУслуг")
		ИЛИ КэшированныеЗначения.дор_ТипОбъекта = Тип("ДокументСсылка.ЗаказКлиента")
	)
	;
КонецФункции


Функция ЦенаОкругленаДо10Копеек(Цена) Экспорт                                        
	Возврат Цена * 10 = Цел(Цена * 10);
КонецФункции

Функция ОкруглитьЦенуДо10Копеек(Цена) Экспорт                                        
	Возврат Цел(Цена * 10) / 10;
КонецФункции

Проверяем:

Теперь сделаем скидку 33%.

Типовой вариант делает скидку: 2 * 2 953.5 * 33% = 1 711,71 и сумму 3 475,29.

Откорректированная расширением новая сумма ручной скидки 1 711.70 и новая сумма 3 475,30:

При этом НДС считается верно 3 475,30 * 20% = 695,06

И сумма с НДС тоже корректна: 3 475,30 + 695,06 = 4170,36

UPD: пришлось переделать, т.к. функция пересчета вызывается и из сервера (например при заполнении по выбранному виду цен), и кэшированные значения передаются не с клиента, а создаются заново. Я долго ломал голову как быть, в итоге просто добавляю колонку дор_ОкруглятьЦеныВРублях в табличную часть товаров, если надо делать округление цен. Дешево и сердито, а что делать.

Вот серверная продедура, которая изменяет колонку дор_ОкруглятьЦеныВРублях в табличной части Товары.

Процедура ДополнитьТаблицуТоваровПризнаками(Форма) Экспорт

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

UPD 2023-09-20: важно что при удалении реквизита надо указывать путь к нему строкой, а не указывать объект реквизит. Поправил это в коде. Также добавил галочку в документы «Не округлять копейки» (дор_НеОкруглятьКопейки), чтобы старые счета могли отгрузить по согласованным ценам. Это важно!

Я вызываю ее из после процедуру ПриСозданииНаСервере. А также перед процедурами РассчитатьИтоговыеПоказатели и РассчитатьИтоговыеПоказателиЗаказа, где я раньше не мох вызывать обновление кэша, потому что процедуры были серверными.

Проверяю, требуется или нет пересчет тоже несложно:

Функция ТребуетсяОкруглениеДо10Копеек(ТекущаяСтрока) Экспорт                                        
	Попытка
		Зн = ТекущаяСтрока.дор_ОкруглятьЦеныВРублях;
		Возврат Истина;
	Исключение
		Возврат ложь;
	КонецПопытки;
КонецФункции

Костыли, а что делать…

UPD: обнаружил, что не работает в новых документах, там серверный вызов конвертирует текущую строку в структуру, а мое поле не добавляет! Расширение модуля ОбработкаТабличнойЧастиКлиент:


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

Также перенес событие из ПриСозданииНаСервере в ПриОткрытии (может валюта заполняется уже при открытии):

&НаКлиенте
Процедура дор_ПриОткрытииПосле(Отказ)
	//Обновляем кэшированные значения, добавляем туда свои параметры...
	//дор_К.ДополнитьКэшированныеЗначения(КэшированныеЗначения, ЭтаФорма);
	дор_ПриОткрытииПослеНаСервере(); //Когда валюта заполнена
	дор_УстановитьВидимость();
КонецПроцедуры  

&НаСервере
Процедура дор_ПриОткрытииПослеНаСервере()
	дор_С.ДополнитьТаблицуТоваровПризнаками(ЭтаФорма);
КонецПроцедуры 

UPD: Важно! Необходимо на всякий случай внедрить пересчет НДС перед записью реализации и заказа. Там же описаны и итоги внедрения.

Среда: 11.5.12.53

fixin

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

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

комментария 3

  1. rzd:

    дор_К дор_С это реально наименования модулей?

  1. 03.10.2023

    […] ввода округления до копеек клиент обратился с проблемой, что сумма НДС в […]

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *