Применение множественных условий по отсрочке платежа в запросе

03.09.18

Разработка - Запросы

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Управление дебиторкой
.cf 23,87Kb
1
1 Скачать (1 SM) Купить за 1 850 руб.

Постановка задачи.

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

Интерфейс настройки для вида отсрочки должен выглядеть приблизительно следующим образом:

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

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

В конечном итоге требуется разработать процедуру автоматического формирования документа "Начисление штрафа по просроченной дебиторской задолженности".

Оговорки ...

В целях наглядной демонстрации основных идей, изложенных в данной статье, я максимально возможно упростил всё, что было можно. Акцент сделан на методике расчёта нужных значений именно в запросе. Чтобы текст запроса был короче, я убрал из описания задачи такие требования, как, например, использование периодических регистров сведений для хранения значений настроек. Выбросил из постановки задачи сложные условия, оставив только самые простые, но не искажающие смысл происходящего. Значительно упростил модель данных, набросок которой может выглядеть приблизительно следующим образом:

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

Главная идея.

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

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

ВЫБРАТЬ
	Д.Сделка,
	КОЛИЧЕСТВО(К.Дата) - 1 КАК КалендарныеДни,
	СУММА(ВЫБОР
			КОГДА К.Выходной
			ТОГДА 0
			ИНАЧЕ 1 КОНЕЦ) - 1  КАК БанковскиеДни
ИЗ
	РегистрНакопления.Взаиморасчёты.Остатки(&НачалоПериода) КАК Д
	ВНУТРЕННЕЕ СОЕДИНЕНИЕ
		РегистрСведений.Календарь КАК К
	ПО К.Дата МЕЖДУ Д.Сделка.Дата И &НачалоПериода
ГДЕ
	Д.СуммаОстаток > 0
СГРУППИРОВАТЬ ПО
	Д.Сделка

День реализации не считается за просрочку поэтому в запросе используется -1 (минус один) день. Далее присоединяем настройки:

ВЫБРАТЬ
	*
ИЗ
	ОсновныеДанные КАК Д

	ВНУТРЕННЕЕ СОЕДИНЕНИЕ
		Справочник.ВидыОтсрочекПлатежа КАК Н
	ПО ИСТИНА

	ЛЕВОЕ СОЕДИНЕНИЕ
		Справочник.ВидыОтсрочекПлатежа.УсловияПрименения КАК У
	ПО Н.Ссылка = У.Ссылка

Результирующая таблица будет выглядеть приблизительно вот так:

Я выделил три группы данных (слева направо): основные данные, виды отсрочек, условия применения отсрочек. Как мы видим, отсрочка по группе "А" имеет два условия применения. Я выделил эти записи жёлтым фоном.

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

Реализация.

Нам потребуется дополнительное поле, которое будет показывать результат вычисления условия. Если условие выполняется, то это будет "1", а если - нет, то "0". Код запроса для этих целей может выглядеть следующим образом:

ВЫБОР
	КОГДА У.Значение ЕСТЬ NULL ТОГДА 1
	КОГДА У.Условие = &УсловиеГруппаНоменклатуры
		И Д.ГруппаНоменклатуры = У.Значение ТОГДА 1
	КОГДА У.Условие = &УсловиеСуммаРеализации
		И Д.СуммаПродажи > У.Значение ТОГДА 1
	ИНАЧЕ 0
КОНЕЦ

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

После вычисления всех условий применения отсрочек нужно вычислить для каких именно отсрочек выполняются ВСЕ условия. Для этого используем функцию агрегирования МИНИМУМ. Она нам покажет какие условия в разрезе отсрочек получили значения равные нулю, то есть не выполнились. Этот кусок кода будет выглядеть следующим образом:

ИМЕЮЩИЕ
	МИНИМУМ(
		ВЫБОР
			КОГДА У.Значение ЕСТЬ NULL ТОГДА 1
			КОГДА У.Условие = &УсловиеГруппаНоменклатуры
				И Д.ГруппаНоменклатуры = У.Значение ТОГДА 1
			КОГДА У.Условие = &УсловиеСуммаРеализации
				И Д.СуммаПродажи > У.Значение ТОГДА 1
			ИНАЧЕ 0
		КОНЕЦ) > 0

Предположим, что у нас применились две отсрочки из всех возможных, и мы получили какой-то вот такой результат:

Казалось бы, что ровно также, как и с условиями применения отсрочек, мы можем применить волшебную функцию агрегирования (на этот раз МАКСИМУМ) и вычислить какая же из отсрочек даёт наилучшие условия для покупателя согласно условию задачи, но ... Поле "Это КД", которое определяет вид дней отсрочки (календарные или банковские), одновременно мешает и необходимо нам для определения какое поле "КД" или "БД" использовать в дальнейших вычислениях. Если мы его выкинем из состава группируемых полей, то навсегда потеряем эту информацию ...

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

Применить функцию МАКСИМУМ к двум полям одновременно можно только если их объединить. Для этого я использовал следующий трюк:

Н.ДниОтсрочки * 10 + (ВЫБОР КОГДА Н.КалендарныеДни ТОГДА 0 ИНАЧЕ 1 КОНЕЦ)

Умножая число дней отсрочки на 10, мы сдвигаем разряды числа влево на один знак, а затем, в зависимости от приоритета кодируемого значения (вид дней), заполняем появившийся справа разряд нужным значением. Нетрудно догадаться, что в таком случае мы можем использовать значения приоритетов от 0 до 9. В результате имеем что-то такое:

Я зачеркнул те значения, которые уйдут в результате агрегирования и выделил значение 101 в закодированном поле "Дни отсрочки + БД/КД" жирным шрифтом как победителя в этой гонке. Раскодирование этого значения обратно выполняется следующим образом:

ВЫБРАТЬ
	Д.Сделка,
	Д.КалендарныеДни,
	Д.БанковскиеДни,
	ВЫРАЗИТЬ(МАКСИМУМ(Н.ДниОтсрочки) / 10 КАК ЧИСЛО(3,0)) КАК ДниОтсрочки,
	(ВЫБОР
		КОГДА (МАКСИМУМ(Н.ДниОтсрочки) / 10 - ВЫРАЗИТЬ(МАКСИМУМ(Н.ДниОтсрочки) / 10 КАК ЧИСЛО(3,0)) * 10) = 1
		ТОГДА ИСТИНА
		ИНАЧЕ ЛОЖЬ
	КОНЕЦ) КАК ЭтоКалендарныеДни

В данном случае мы получаем целую часть от деления вот этим кодом, преобразуя результат деления на 10 к целому числу без знака:

ВЫРАЗИТЬ(МАКСИМУМ(Н.ДниОтсрочки) / 10 КАК ЧИСЛО(3,0))

Получение остатка от деления после этого тривиально. В этом примере кода поле Н.ДниОтсрочки это уже закодированные число дней и их вид.

Результатом всей этой истории получается вот такая вот простая таблица (см. прилагаемую конфигурацию):

Заключение.

Таким образом можно выделить 4 этапа выполнения запроса:

1. Получение основных данных, к которым применяются настройки.

2. Получение настроек и вычисление условий их применения.

3. Вычисление настройки, которая имеет наивысший приоритет относительно других.

4. Применение победившей настройки к основным данным.

Привожу текст всего запроса из прилагаемой тестовой конфигурации здесь:

ВЫБРАТЬ
	Сделка                      КАК Реализация,
	Сделка.Номенклатура.Группа  КАК ГруппаНоменклатуры,
	Сделка.Дата                 КАК ДатаПродажи,
	Сделка.Сумма                КАК СуммаПродажи,
	Сделка.Сумма - СуммаОстаток КАК СуммаОплачено,
	СуммаОстаток                КАК СуммаОстаток,
	КОЛИЧЕСТВО(К.Дата) - 1      КАК КалендарныеДни,
	СУММА(ВЫБОР
			КОГДА К.Выходной
			ТОГДА 0
			ИНАЧЕ 1 КОНЕЦ) - 1  КАК БанковскиеДни
ПОМЕСТИТЬ
	ОсновныеДанные
ИЗ
	РегистрНакопления.Взаиморасчёты.Остатки(&НачалоПериода) КАК О
	ВНУТРЕННЕЕ СОЕДИНЕНИЕ
		РегистрСведений.Календарь КАК К
	ПО К.Дата МЕЖДУ О.Сделка.Дата И &НачалоПериода
ГДЕ
	СуммаОстаток > 0
СГРУППИРОВАТЬ ПО
	Сделка,
	СуммаОстаток
;



ВЫБРАТЬ
	Т.Реализация, Т.ДатаПродажи,
	Т.СуммаПродажи, Т.СуммаОплачено, Т.СуммаОстаток,
	Т.КалендарныеДни, Т.БанковскиеДни,
	ВЫРАЗИТЬ(МАКСИМУМ(Т.ДниОтсрочки) / 10 КАК ЧИСЛО(3,0)) КАК ДниОтсрочки,
	(ВЫБОР
		КОГДА (МАКСИМУМ(Т.ДниОтсрочки) / 10 - ВЫРАЗИТЬ(МАКСИМУМ(Т.ДниОтсрочки) / 10 КАК ЧИСЛО(3,0)) * 10) = 1
		ТОГДА ИСТИНА
		ИНАЧЕ ЛОЖЬ
	КОНЕЦ) КАК ЭтоКалендарныеДни
ПОМЕСТИТЬ
	ДанныеПлюсОтсрочка
ИЗ
	(ВЫБРАТЬ
		Д.Реализация, Д.ГруппаНоменклатуры, Д.ДатаПродажи,
		Д.СуммаПродажи, Д.СуммаОплачено, Д.СуммаОстаток,
		Д.КалендарныеДни, Д.БанковскиеДни,
		О.ДниОтсрочки * 10 + (ВЫБОР КОГДА О.КалендарныеДни ТОГДА 0 ИНАЧЕ 1 КОНЕЦ) КАК ДниОтсрочки
	ИЗ
		ОсновныеДанные КАК Д

		ВНУТРЕННЕЕ СОЕДИНЕНИЕ
			Справочник.ВидыОтсрочекПлатежа КАК О
		ПО ИСТИНА

		ЛЕВОЕ СОЕДИНЕНИЕ
			Справочник.ВидыОтсрочекПлатежа.УсловияПрименения КАК У
		ПО О.Ссылка = У.Ссылка

	СГРУППИРОВАТЬ ПО
		Д.Реализация, Д.ГруппаНоменклатуры, Д.ДатаПродажи,
		Д.СуммаПродажи, Д.СуммаОплачено, Д.СуммаОстаток,
		Д.КалендарныеДни, Д.БанковскиеДни, О.Ссылка,
		О.ДниОтсрочки * 10 + (ВЫБОР КОГДА О.КалендарныеДни ТОГДА 0 ИНАЧЕ 1 КОНЕЦ)

	ИМЕЮЩИЕ
		МИНИМУМ(
			ВЫБОР
				КОГДА У.Значение ЕСТЬ NULL ТОГДА 1
				КОГДА У.Условие = &УсловиеГруппаНоменклатуры
					И Д.ГруппаНоменклатуры = У.Значение ТОГДА 1
				КОГДА У.Условие = &УсловиеСуммаРеализации
					И Д.СуммаПродажи > У.Значение ТОГДА 1
				ИНАЧЕ 0
			КОНЕЦ) > 0
	) КАК Т

СГРУППИРОВАТЬ ПО
	Т.Реализация, Т.ДатаПродажи,
	Т.СуммаПродажи, Т.СуммаОплачено, Т.СуммаОстаток,
	Т.КалендарныеДни, Т.БанковскиеДни
;



ВЫБРАТЬ
	Т.Реализация, Т.ДатаПродажи,
	Т.СуммаПродажи, Т.СуммаОплачено, Т.СуммаОстаток,
	(ВЫБОР
		КОГДА Т.ЭтоКалендарныеДни
		ТОГДА Т.КалендарныеДни
		ИНАЧЕ Т.БанковскиеДни
	КОНЕЦ) КАК ПрошлоДней,
	Т.ДниОтсрочки - (ВЫБОР
						КОГДА Т.ЭтоКалендарныеДни
						ТОГДА Т.КалендарныеДни
						ИНАЧЕ Т.БанковскиеДни
					КОНЕЦ) КАК ДниПросрочки
ИЗ
	ДанныеПлюсОтсрочка КАК Т
ГДЕ
	Т.ДниОтсрочки - (ВЫБОР КОГДА Т.ЭтоКалендарныеДни ТОГДА Т.КалендарныеДни ИНАЧЕ Т.БанковскиеДни КОНЕЦ) < 0

 

См. также

Инструментарий разработчика Роли и права Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    152176    834    397    

843

Запросы Программист Запросы Бесплатно (free)

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

16.08.2024    6850    user1840182    5    

28

Математика и алгоритмы Запросы Программист Платформа 1С v8.3 Запросы Бесплатно (free)

Рассмотрим быстрый алгоритм поиска дублей с использованием hash функции по набору полей шапки и табличных частей.

08.07.2024    2103    ivanov660    9    

22

Запросы СКД Программист Стажер Система компоновки данных Россия Бесплатно (free)

Часто при разработке отчетов в СКД возникает ситуация, когда не совсем понятно, почему отчет выводит не те данные, которые нужны, либо не выводит вовсе. Возникает потребность увидеть конечный запрос, который формирует СКД. Как это сделать, рассмотрим в этой статье.

15.05.2024    7233    implecs_team    6    

46

Запросы Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Часто поступают задачи по произвольному распределению общих сумм. После распределения иногда пропадают копейки. Суть решения добавить АвтоНомерЗаписи() в ВТ распределения, и далее используя функции МАКСИМУМ или МИНИМУМ можем положить разницу копеек в первую или последнюю строку знаменателя распределения.

11.04.2024    3205    andrey_sag    10    

35

Запросы СКД Программист Стажер Платформа 1С v8.3 Запросы Система компоновки данных 1С:ERP Управление предприятием 2 Бесплатно (free)

В типовых конфигурациях разработчики компании 1С иногда используют в отчетах, построенных на СКД, такую конструкцию, как "ГДЕ ЛОЖЬ". Такая конструкция говорит о том, что данные в запросе не будут получены совсем. Для чего же нужен тогда запрос?

13.02.2024    7311    KawaNoNeko    23    

26

Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Абонемент ($m)

Есть список полей в виде текста, или запрос - закидываем в набор СКД.

1 стартмани

31.01.2024    2982    3    Yashazz    0    

34
Оставьте свое сообщение