При разработке аналитических отчетов в Системе компоновки данных (СКД) регулярно возникает необходимость вычисления точного количества календарных или рабочих дней в периоде. Типичный пример — расчет показателя оборачиваемости товаров, средних дневных продаж или показателей выработки. Использование усредненных значений (например, жестко заданных 30 дней в месяце) приводит к погрешностям, поскольку длительность месяцев варьируется от 28 до 31 дня.
Рассмотрим подробнее, как корректно настроить расчет дней в СКД с помощью вычисляемых полей и ресурсов, а также разберем тонкости обработки неполных («рваных») периодов.
Разбирая работу с датами, первоочередно обратим внимание на важный синтаксический нюанс 1С. Функция РАЗНОСТЬДАТ используется как в языке запросов, так и в выражениях СКД, однако правила записи третьего параметра (типа разности) отличаются:
РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ)
РазностьДат(Дата1, Дата2, "ДЕНЬ")
Если в вычисляемом поле написать тип разности без кавычек, система выведет ошибку о том, что поле не найдено.
Проанализируем базовый сценарий: в отчете присутствует группировка по месяцам (поле ПериодМесяц или Период, приведенное к началу месяца). Нам требуется определить количество дней для каждого месяца.
Перейдем на вкладку «Вычисляемые поля» в схеме компоновки данных и добавим новое поле:
КоличествоДней
РазностьДат(ПериодМесяц, КонецПериода(ПериодМесяц, "МЕСЯЦ"), "ДЕНЬ") + 1
Почему требуется прибавлять +1? Функция РазностьДат рассчитывает интервал между датами. Например, разность между 01.01.2018 0:00:00 и 31.01.2018 23:59:59 при отсечении времени (или сравнении по дням) вернет 30. Чтобы получить фактическое количество дней в месяце (31 день для января), к результату добавляется единица.
Вышеописанная формула отлично работает, если отчет всегда формируется строго с 1-го по последнее число месяца. Однако если пользователь сформирует отчет, например, с 15 марта по 10 апреля, простой расчет дней месяца даст неверный результат за краевые месяцы.
Выясним, как учесть пересечение месяца с пользовательскими параметрами &НачалоПериода и &КонецПериода. Нам необходимо вычислить фактическую дату начала и конца отрезка в рамках рассматриваемого месяца.
В вычисляемом поле КоличествоДней пропишем следующее выражение:
РазностьДат(
ВЫБОР
КОГДА ПериодМесяц < &НачалоПериода ТОГДА &НачалоПериода
ИНАЧЕ ПериодМесяц
КОНЕЦ,
ВЫБОР
КОГДА КонецПериода(ПериодМесяц, "МЕСЯЦ") > &КонецПериода ТОГДА &КонецПериода
ИНАЧЕ КонецПериода(ПериодМесяц, "МЕСЯЦ")
КОНЕЦ,
"ДЕНЬ"
) + 1
Данная конструкция берет наибывшую дату начала (либо 1-е число месяца, либо параметр &НачалоПериода) и наименьшую дату окончания (либо конец месяца, либо параметр &КонецПериода), высчитывая точный период пребывания данных в отчете.
Распространенная ошибка разработчиков — указать для поля КоличествоДней стандартное выражение ресурса Сумма(КоличествоДней). Посмотрим, к чему это приводит:
Если в месяце продавалось 100 наименований номенклатуры, в группировке по месяцу система сложит 31 день 100 раз и выведет 3100 дней. Это полностью исказит расчеты.
Чтобы избежать дублирования суммы дней, настроим ресурс правильно:
КоличествоДней.
Максимум(КоличествоДней)
(также допускается использовать Среднее(КоличествоДней)).
РазностьДат(&НачалоПериода, &КонецПериода, "ДЕНЬ") + 1
Теперь, когда поле КоличествоДней рассчитывается корректно, перейдем к итоговой цели — вычислению показателя оборачиваемости (в днях). Формула оборачиваемости выглядит следующим образом:
Оборачиваемость (в днях) = (Средний остаток × Количество дней) / Продажи (в себестоимости или количествах)
На вкладке «Ресурсы» создаем вычисляемый показатель ОборачиваемостьДни и прописываем выражение с обязательной проверкой деления на ноль:
ВЫБОР
КОГДА Сумма(ПродажиОборот) = 0 ТОГДА 0
ИНАЧЕ (Сумма(СреднийОстаток) * Максимум(КоличествоДней)) / Сумма(ПродажиОборот)
КОНЕЦ
Если специфика бизнес-логики требует учета не календарных, а исключительно **рабочих дней** (без учета выходных и праздников), формулы СКД с функцией РазностьДат не подойдут.
В таком случае в запросе схемы компоновки данных выполняется соединение с регистром сведений РегламентированныйПроизводственныйКалендарь или ГрафикиРаботы по условию:
Календарь.Дата МЕЖДУ НачалоПериода И КонецПериода
И Календарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
Подсчет количества записей из производственного календаря даст точное число рабочих дней за выбранный интервал времени с учетом переносов праздничных дней.