При проектировании или доработке системы на платформе 1С:Предприятие часто возникает задача расширения аналитики существующего учета. Рассмотрим классическую проблему: у нас есть работающий регистр накопления (остатки), и бизнес требует добавить в отчеты разбивку по периодам (например, "Дата начала аренды" и "Дата окончания аренды").
Сложность заключается в том, что эти даты присутствуют только в части документов (например, в документе реализации или специальном документе начисления), но отсутствуют в стандартных документах прихода или списания. Проанализируем, как правильно реализовать такую задачу, чтобы не "сломать" учет и сохранить производительность системы.
Рассмотрим ситуацию, описанную автором. Появилась потребность проводить один документ на будущие периоды, создавая несколько записей в регистре с разными датами начала и конца. Если не добавить эти поля в структуру регистра, записи свернутся (схлопнутся), и мы потеряем детальную информацию для отчета.
Перед нами встает выбор из трех вариантов:
Давайте подробно разберем каждый вариант и выясним, почему прямая модификация измерений — это, как правило, плохое решение.
На первый взгляд, это кажется самым логичным решением: добавили измерение, записали данные, построили отчет. Однако, как верно подмечено в обсуждении, здесь кроется фундаментальная ошибка проектирования регистров остатков.
Принцип закрываемости регистра (Message 9)
Главный принцип регистра накопления вида "Остатки" — закрытие движений в ноль. Таблица остатков виртуальна, она рассчитывается как сумма приходов минус сумма расходов.
Если вы добавите измерение ДатаНачала, то система будет считать уникальным ключом записи набор всех измерений, включая эту дату.
Представим ситуацию:
Результат: Регистр не закроется. В отчете "Остатки и обороты" вы увидите две строки:
В сумме это дает ноль, но для пользователя отчет будет выглядеть как "разъехавшаяся" аналитика. Это недопустимо для складского или финансового учета. Чтобы этого избежать, вам пришлось бы при списании программно подбирать пустую дату (что теряет смысл добавления измерения) или при приходе провидчески знать будущую дату расхода (что невозможно).
Проблема производительности (Message 10)
Даты в измерениях — это потенциальная проблема "Cardinality" (селективности). Таблица итогов регистра накопления эффективна, когда количество комбинаций измерений ограничено. Если даты разнообразны (особенно если там есть время), таблица итогов раздувается до размеров таблицы движений, и смысл использования регистра накопления теряется.
Если мы запишем даты в Реквизиты регистра, мы избежим проблемы с незакрытыми остатками. Реквизиты не участвуют в формировании уникального ключа остатков. Приход и расход по товару "Стул" схлопнутся в ноль, даже если у них разные реквизиты.
Однако здесь возникает проблема получения данных:
Остатки, Обороты, ОстаткиИОбороты) не позволяют делать отбор или группировку по реквизитам напрямую в параметрах.Пример запроса, который придется писать (псевдокод):
ВЫБРАТЬ
ТоварыНаСкладахОстаткиИОбороты.Номенклатура,
ТоварыНаСкладахОстаткиИОбороты.КоличествоОборот,
ТоварыНаСкладах.ДатаНачалаАренды // Реквизит
ИЗ
РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты AS ТоварыНаСкладахОстаткиИОбороты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах AS ТоварыНаСкладах
ПО ТоварыНаСкладахОстаткиИОбороты.Регистратор = ТоварыНаСкладах.Регистратор
И ТоварыНаСкладахОстаткиИОбороты.НомерСтроки = ТоварыНаСкладах.НомерСтроки
Это рабочее решение, но оно значительно утяжеляет запросы в отчетах. Если таких отчетов много и база большая, производительность упадет.
Наиболее правильным подходом, который советуют опытные разработчики (Message 4, 10), является разделение потоков данных. Не стоит пытаться "впихнуть" аналитику одного конкретного документа в общий регистр, где она не нужна для 90% других операций.
Мы рекомендуем использовать один из двух подходов:
Создайте независимый (или подчиненный регистратору) регистр сведений, например, СрокиАрендыПоДокументам.
При проведении документа с датами вы пишите движения и в основной РН (только суммы/количества), и в этот РС (даты). В отчетах вы просто соединяете данные РН с этим РС.
Если ваша задача — анализировать именно обороты (сколько услуг оказано в разрезе периодов), создайте отдельный Регистр накопления (Обороты), например ПродажиПоПериодамАренды.
ДатаНачала и ДатаОкончания.Подводя итог обсуждения, сформулируем алгоритм действий:
Разделение ответственности между объектами метаданных — залог стабильной и масштабируемой системы. Лучше иметь два специализированных регистра, чем один "супер-регистр" с кучей пустых полей и медленной работой.