Когда округление мешает пробитию чека

В современных фискальных регистраторах должно строго соблюдаться правило: Количество * Цена = Сумма.

Иногда, в процессе применения скидок, это правило нарушается.

Некоторые чеки не пробивались с ошибкой неправильной суммы:

При печати чека произошла ошибка.
Чек не напечатан на фискальном устройстве.
Дополнительное описание:
При выполнении операции произошла ошибка: Неверная цена (сумма)

Я начал разбираться и выявил среди отложенных чеков такие.

Использовал запрос по отложенным без резервирования чекам:

ВЫБРАТЬ
	Т.Ссылка КАК Ссылка,
	//Т.Номенклатура КАК Номенклатура,
	Т.Количество КАК Количество,
	Т.Цена КАК Цена,
	Т.Сумма КАК Сумма,
	Т.Количество * Т.Цена КАК СуммаПоПроизведению,
	Сумма /  Т.Количество КАК РасчетнаяЦена,
	Т.СуммаАвтоматическойСкидки КАК СуммаАвтоматическойСкидки,
	Т.СуммаРучнойСкидки КАК СуммаРучнойСкидки,
	Т.Ссылка.Статус КАК Статус
ИЗ
	Документ.ЧекККМ.Товары КАК Т
ГДЕ
	Т.Ссылка.Статус = &Статус
	И Т.Количество * Т.Цена <> Т.Сумма

Здесь в 1С устроено так, что Цена — это цена без скидки, Сумма — это сумма со скидкой.

Получил вот такой результат, где видно, что один из товаров в чеке дает неправильную цену, которая не может округлиться до двух знаков (339,983…):

Как видно из отладки, «глючит» именно типовой функционал, выдавая скидку 170.14:

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

В нашем примере: 170.14 : 17 = 10,00823… получаем цену 10,01 10,01 * 17 = 170,17

Причем поправлять надо в двух местах, общую функцию расчета ручной скидки разработчики УТ не написали. Расширяем модуль ОбработкаТабличнойЧастиКлиентСервер:

&ИзменениеИКонтроль("ПересчитатьСуммуСУчетомРучнойСкидкиВСтрокеТЧ")
Процедура дор_ПересчитатьСуммуСУчетомРучнойСкидкиВСтрокеТЧ(ТекущаяСтрока, СтруктураДействий, КэшированныеЗначения)
	СтруктураПараметровДействия = Неопределено;
	Если СтруктураДействий.Свойство("ПересчитатьСуммуСУчетомРучнойСкидки", СтруктураПараметровДействия) Тогда
		Очищать = Неопределено;
		ПересчитыватьСуммуРучнойСкидки = Неопределено;
		ИмяКоличества = Неопределено;
		Если СтруктураПараметровДействия <> Неопределено Тогда
			СтруктураПараметровДействия.Свойство("Очищать", Очищать);
			СтруктураПараметровДействия.Свойство("ПересчитыватьСуммуРучнойСкидки", ПересчитыватьСуммуРучнойСкидки);
			СтруктураПараметровДействия.Свойство("ИмяКоличества", ИмяКоличества);
			Если НЕ ЗначениеЗаполнено(ИмяКоличества) Тогда
				ИмяКоличества = "КоличествоУпаковок";
			КонецЕсли;
			Если Очищать = Истина Тогда
				ТекущаяСтрока.СуммаРучнойСкидки = 0;
				ТекущаяСтрока.ПроцентРучнойСкидки = 0;
			КонецЕсли;
		КонецЕсли;
		Если ПересчитыватьСуммуРучнойСкидки = Ложь Тогда
		Иначе
			ТекущаяСтрока.СуммаРучнойСкидки = Окр(ТекущаяСтрока[ИмяКоличества] *ТекущаяСтрока.Цена * ТекущаяСтрока.ПроцентРучнойСкидки / 100, 2);
		КонецЕсли;
#Вставка
			//Осипов 2022-10-01 важно крайне для того чтобы чек пробивался.
			Если ТекущаяСтрока.Количество <> 0 Тогда
				ТекущаяСтрока.СуммаРучнойСкидки = ОКР(ТекущаяСтрока.СуммаРучнойСкидки / ТекущаяСтрока.Количество, 2) * ТекущаяСтрока.Количество;
			КонецЕсли;
#КонецВставки
		
		ТекущаяСтрока.Сумма = ТекущаяСтрока.Сумма - ТекущаяСтрока.СуммаРучнойСкидки;
	КонецЕсли;
КонецПроцедуры
&ИзменениеИКонтроль("ПересчитатьСуммуРучнойСкидкиВСтрокеТЧ")
Процедура дор_ПересчитатьСуммуРучнойСкидкиВСтрокеТЧ(ТекущаяСтрока, СтруктураДействий, КэшированныеЗначения)
	ИмяКоличества = Неопределено;
	Если СтруктураДействий.Свойство("ПересчитатьСуммуРучнойСкидки", ИмяКоличества) Тогда
		Если НЕ ЗначениеЗаполнено(ИмяКоличества) Тогда
			ИмяКоличества = "КоличествоУпаковок"; 
		КонецЕсли;
		ТекущаяСтрока.СуммаРучнойСкидки = Окр(ТекущаяСтрока[ИмяКоличества] *ТекущаяСтрока.Цена * ТекущаяСтрока.ПроцентРучнойСкидки / 100, 2);
#Вставка
		//Осипов 2022-10-01 важно крайне для того чтобы чек пробивался.
		Если ТекущаяСтрока.Количество <> 0 Тогда
			ТекущаяСтрока.СуммаРучнойСкидки = ОКР(ТекущаяСтрока.СуммаРучнойСкидки / ТекущаяСтрока.Количество, 2) * ТекущаяСтрока.Количество;
		КонецЕсли;
#КонецВставки
		
	КонецЕсли;
КонецПроцедуры

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

Проверьте актуальные релизы, взяв количество 17, скидку 2.78% и цену 360.

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

Но и в таком случае, все же, вина на разработчиках УТ. Они должны были предусмотреть округление скидки под кратность количества.

Среда: 11.4.13.46. Объем: 1 час.

fixin

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

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

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

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