Ошибка расчета остатков в скд и ее программное исправление на примере универсального отчета. Ошибка расчета остатков в скд и ее программное исправление на примере универсального отчета Остатки и обороты в скд

Доброго времени суток, уважаемые читатели блога сайт! В прошлый раз мы уже затрагивали тему , которая рассказывала о применении функции . А сегодня в первой из этой серии статей, мы узнаем для чего нужны роли полей компоновки данных , а также рассмотрим примеры заполнения этих ролей.

Роль поля СКД указывает, что из себя представляет данное поле . Каждая роль поля может содержать свое свойство. Например, имеет числовое значение и содержит номер периода, если поле период. Если значение свойство «Период» равно 0 (ноль), то это означает, что данное поле периодом не является. Или свойство «Измерение» – содержит признак того, что поле является измерением. Если поле является измерением, то эта информация используется при расчете итогов по полям остатка.

Для каждого поля схемы компоновки данных можно указывать роль. Роли влияют на корректность расчета остатков . В частности, начального и конечного остатка по некоторой таблице. Если в запросе выбрана виртуальная таблица «ОстаткиИОбороты», то начальные и конечные остатки считаются по сложному алгоритму, особенно если у нас используются дополнительные развороты по периоду.

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

Добавим набор данных запрос. Для этого нам нужно сделать активным корневой элемент «Конструктор запроса». Давайте обратимся к виртуальной таблице «ОстаткиИОбороты» регистра накопления. Что мы видим?

Как можно заметить из иллюстрации выше, мы видим, что для некоторых полей роль заполнилась. Это произошло, потому что у нас установлен флаг «Автозаполнение». Но такое не всегда возможно, поэтому иногда приходится проставлять роль вручную. Посмотрим пару примеров.

Предположим, что в запросе мы используем , например, применяем оператор языка запросов «ВЫБОР». Опишем такое условие:

ВЫБОР КОГДА ОстаткиТоваровОстаткиИОбороты.Номенклатура = Значение(Справочник.Номенклатура.ПустаяСсылка) ТОГДА Значение(Справочник.Номенклатура.Шампунь) ИНАЧЕ ОстаткиТоваровОстаткиИОбороты.Номенклатура КОНЕЦ

Эта запись означает что, если номенклатура соответствует пустой ссылке (обращаемся к функции значение справочник «Номенклатура», пустая ссылка), то тогда буден возвращено значение предопределенного элемента. Предположим, что в нашей конфигурации есть такой предопределенный элемент и он называется «Шампунь». В противном случае, возвращаем значение самой номенклатуры. Получаем следующее:

Как видим для поля «Номенклатура» роль не заполнилась. Но как видно на изображении в действительности у нас не проставлена роль, для поля «Поле1», и в этом случае остаток не будет корректно рассчитан.

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

В конце статьи хочу посоветовать вам бесплатный от Сотникова Анатолия. Это курс от опытного программиста. Он на отдельной базе покажет вам, как строить отчеты в СКД. Вам только нужно внимательно слушать и запоминать! Вы получите ответы на такие вопросы:
  • Как создать простой отчет в виде списка?
  • Для чего нужны колонки Поле, Путь и Заголовок на закладке «Поля»?
  • Какие существуют ограничения для полей компоновки?
  • Как правильно настраивать роли?
  • Какие существуют роли для полей компоновки?
  • Где найти закладку компоновка данных в запросе?
  • Как настраивать параметры в СКД?
  • Дальше еще интереснее...
Наверное, не стоит самому стараться бороздить интернет в поисках нужной информации? Тем более все готово для применения. Только начните! Все подробности о том, что есть в бесплатных видеоуроках

41
Делал недавно отчет с неопределенным количеством колонок. Возиться с кодом было неохота, решил сделать на СКД. С этим проблема не возникла, необходимо было натянуть результат на произвольный макет (свой заголовок +... 27
Несмотря на то, изучающие СКД встречаются с этим на первый или второй день, это должно быть в разделе FAQ. Простой пример программного вывода отчета на компоновке, использующий настройки по умолчанию. //Получаем схему из... 18
При формировании отчетов на СКД по умолчанию все группировки развернуты, но бывает что необходимо сразу после формирования показать отчет со свернутыми группировками! Данный код в модуле отчета позволяет свернуть... 10
На этой закладке можно указать, какие осуществляются связи между двумя и более наборами дан-ных, по каким параметрам и условиям..png 1. «Источник связи» - указывается первый набор данных, от... 9
Что при разработке отчетов требуется чтобы у пользователя с ограниченными правами, отчет формировался полностью без проверки прав! Особенно если настроен RLS Есть несколько способов как это сделать: 1. Установить...

Не знаю, многим ли уже довелось столкнуться с ошибкой расчета начальных и конечных остатки по группировкам. Лично мне "посчастливилось", притом неоднократно. Причина, как мне удалось выяснить, кроется в неверных настройках полей данных СКД, важности которых многие начинающие (да и не очень) программисты пока до конца не осознают.

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

Если вы ранее не сталкивались с этой проблемой, то для лучшего понимания ее сути предлагаю воспроизвести ее самим с помощью универсального отчета (по метаданным). Запускаем отчет, выбираем любой непустой регистр накопления с остатками и оборотами, включаем в настройках отчета () флажок "Детальные записи", указываем какие-нибудь группировки и добавляем в состав выводимых полей Регистратор. Вуаля - начальные и конечные остатки суммируются по каждой группировке. Получается отчет с абсолютно некорректными цифрами, который показывать пользователям никак нельзя.

Для решения такой проблемы необходимо корректно заполнить настройки полей набора данных СКД - в частности, поле "Роль", которое имеет ключевое значение.

РЕШЕНИЕ интерактивное (не подходит для Универсального отчета ):

Открываем схему компоновки данных вашего отчета и смотрим в настройки полей набора данных.

Для полей начальных и конечных остатков по каждому из ресурсов необходимо заполнить роль: выбрать группу ролей "Остаток" и в ней указать значение "Нач. остаток" или "Кон. остаток" соответственно. Так ( ) это делается в конструкторе СКД.

Аналогичным образом необходимо проставить роль "Измерение" для всех измерений вашего набора данных.

Но этого недостаточно для корректной работы отчетов. Для правильного расчета полей остатков необходимо знать период каждого движения, чтобы расставить их в правильном хронологическом порядке. Если в вашем исходном источнике данных поля периода нет, необходимо его туда добавить. Если же поле периода в наборе данных уже есть, ему необходимо указать роль "Период" и соответствующий номер периода (подробнее о нумерации периодов можно прочесть в справке).

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

РЕШЕНИЕ программное (на примере Универсального отчета по метаданным):

Теперь рассмотрим, как исправить эту же ошибку в Универсальном отчете по метаданным. Универсальный отчет отличается от большинства прочих отчетов тем, что схема компоновки данных там генерируется полностью программно, поэтому настраивать роли для полей данных СКД тоже приходится программно.

Для ролей начальных и конечных остатков по каждому из ресурсов проще всего не изобретать велосипед (все уже написано до нас) и воспользоваться типовой процедурой ЗаполнитьПолеНабораДанныхОстаток() из общего модуля ТиповыеОтчеты. Туда передаете в качестве параметров поле набора данных и имя ресурса, и в результате в наборе данных создается поле остатка с корректно заполненной ролью.

Аналогичным образом при создании полей набора данных для измерений необходимо проставить им роль "Измерение". Код будет примерно следующим:

НовоеИзмерение = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, Измерение.Имя, Измерение.Синоним); НовоеИзмерение.Роль.Измерение = Истина;

Описанные выше манипуляции с полями ресурсов и измерений необходимы, но не достаточны для решения проблемы - основной бедой универсального отчета является отсутствие нумерации периодов. Поля периода присутствуют в наборе данных, но их роли не заполнены.

Поля периода в отчет добавляются процедурой общего модуля ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(), вызов которой происходит из процедуры модуля объекта ДобавитьПоляНабораДанных(). К сожалению, номера периодов эта процедура не проставляет.

Кроме того, в отчет нигде программно не добавляются поля "Номер строки" и "Регистратор". Мне показалось это странным, т.к. в итоговом наборе данных они присутствуют.

Как выяснилось, поля "Номер строки" и "Регистратор" (Recorder) добавляет сама платформа автоматически при инициализации компоновщика настроек. Причем платформа не заполняет роли для создаваемых ею полей, а программно их заполнить не получается, что создает проблемы при дальнейшей работе с ними. Но если эти поля создать "вручную" и программно прописать им правильные роли, то платформа уже не пытается создавать их заново.

Ниже я предлагаю рецепт, который помог мне почти полностью решить эту проблему платформы и Универсального отчета по метаданным:

Вот этот фрагмент кода модуля объекта:

// Добавляем поля периода Если ИмяТаблицы = "ОстаткиИОбороты" ИЛИ ИмяТаблицы = "Обороты" Тогда ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(СхемаКомпоновкиДанных.НаборыДанных); КонецЕсли; нужно заменить на следующий: // Добавляем поля периода Если ИмяТаблицы = "ОстаткиИОбороты" ИЛИ ИмяТаблицы = "Обороты" Тогда СписокПериодов = ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(СхемаКомпоновкиДанных.НаборыДанных); //Заполним служебные поля и проставим периоды вручную, т.к. платформа их не заполняет Поле = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, "НомерСтроки", "Номер строки"); Поле.Роль.НомерПериода = 1; Поле = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, "Регистратор", "Регистратор"); Поле.Роль.НомерПериода = 2; сч = 3; Для Каждого ПолеПериод Из СписокПериодов Цикл ПолеПериод.Значение.Роль.НомерПериода = сч; Если сч > 3 Тогда ПолеПериод.Значение.Роль.ТипПериода = ТипПериодаКомпоновкиДанных.Дополнительный; КонецЕсли; сч = сч+1; КонецЦикла; КонецЕсли;

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

UPDATE: мне подсказали в комментариях, что на диске ИТС в свое время вышла статья на эту тему. К сожалению, эта статья прошла мимо меня, но помочь мне в решении проблем с универсальным отчетом она бы смогла лишь отчасти. Увы, заморочки платформы со служебными полями СКД, такими как "Recorder", там также не описаны.

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

Не знаю, многим ли уже довелось столкнуться с ошибкой расчета начальных и конечных остатки по группировкам. Лично мне "посчастливилось", притом неоднократно. Причина, как мне удалось выяснить, кроется в неверных настройках полей данных СКД, важности которых многие начинающие (да и не очень) программисты пока до конца не осознают.

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

Если вы ранее не сталкивались с этой проблемой, то для лучшего понимания ее сути предлагаю воспроизвести ее самим с помощью универсального отчета (по метаданным). Запускаем отчет, выбираем любой непустой регистр накопления с остатками и оборотами, включаем в настройках отчета () флажок "Детальные записи", указываем какие-нибудь группировки и добавляем в состав выводимых полей Регистратор. Вуаля - начальные и конечные остатки суммируются по каждой группировке. Получается отчет с абсолютно некорректными цифрами, который показывать пользователям никак нельзя.

Для решения такой проблемы необходимо корректно заполнить настройки полей набора данных СКД - в частности, поле "Роль", которое имеет ключевое значение.

РЕШЕНИЕ интерактивное (не подходит для Универсального отчета ):

Открываем схему компоновки данных вашего отчета и смотрим в настройки полей набора данных.

Для полей начальных и конечных остатков по каждому из ресурсов необходимо заполнить роль: выбрать группу ролей "Остаток" и в ней указать значение "Нач. остаток" или "Кон. остаток" соответственно. Так ( ) это делается в конструкторе СКД.

Аналогичным образом необходимо проставить роль "Измерение" для всех измерений вашего набора данных.

Но этого недостаточно для корректной работы отчетов. Для правильного расчета полей остатков необходимо знать период каждого движения, чтобы расставить их в правильном хронологическом порядке. Если в вашем исходном источнике данных поля периода нет, необходимо его туда добавить. Если же поле периода в наборе данных уже есть, ему необходимо указать роль "Период" и соответствующий номер периода (подробнее о нумерации периодов можно прочесть в справке).

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

РЕШЕНИЕ программное (на примере Универсального отчета по метаданным):

Теперь рассмотрим, как исправить эту же ошибку в Универсальном отчете по метаданным. Универсальный отчет отличается от большинства прочих отчетов тем, что схема компоновки данных там генерируется полностью программно, поэтому настраивать роли для полей данных СКД тоже приходится программно.

Для ролей начальных и конечных остатков по каждому из ресурсов проще всего не изобретать велосипед (все уже написано до нас) и воспользоваться типовой процедурой ЗаполнитьПолеНабораДанныхОстаток() из общего модуля ТиповыеОтчеты. Туда передаете в качестве параметров поле набора данных и имя ресурса, и в результате в наборе данных создается поле остатка с корректно заполненной ролью.

Аналогичным образом при создании полей набора данных для измерений необходимо проставить им роль "Измерение". Код будет примерно следующим:

НовоеИзмерение = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, Измерение.Имя, Измерение.Синоним); НовоеИзмерение.Роль.Измерение = Истина;

Описанные выше манипуляции с полями ресурсов и измерений необходимы, но не достаточны для решения проблемы - основной бедой универсального отчета является отсутствие нумерации периодов. Поля периода присутствуют в наборе данных, но их роли не заполнены.

Поля периода в отчет добавляются процедурой общего модуля ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(), вызов которой происходит из процедуры модуля объекта ДобавитьПоляНабораДанных(). К сожалению, номера периодов эта процедура не проставляет.

Кроме того, в отчет нигде программно не добавляются поля "Номер строки" и "Регистратор". Мне показалось это странным, т.к. в итоговом наборе данных они присутствуют.

Как выяснилось, поля "Номер строки" и "Регистратор" (Recorder) добавляет сама платформа автоматически при инициализации компоновщика настроек. Причем платформа не заполняет роли для создаваемых ею полей, а программно их заполнить не получается, что создает проблемы при дальнейшей работе с ними. Но если эти поля создать "вручную" и программно прописать им правильные роли, то платформа уже не пытается создавать их заново.

Ниже я предлагаю рецепт, который помог мне почти полностью решить эту проблему платформы и Универсального отчета по метаданным:

Вот этот фрагмент кода модуля объекта:

// Добавляем поля периода Если ИмяТаблицы = "ОстаткиИОбороты" ИЛИ ИмяТаблицы = "Обороты" Тогда ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(СхемаКомпоновкиДанных.НаборыДанных); КонецЕсли; нужно заменить на следующий: // Добавляем поля периода Если ИмяТаблицы = "ОстаткиИОбороты" ИЛИ ИмяТаблицы = "Обороты" Тогда СписокПериодов = ТиповыеОтчеты.ДобавитьПоляПериодаВНаборДанных(СхемаКомпоновкиДанных.НаборыДанных); //Заполним служебные поля и проставим периоды вручную, т.к. платформа их не заполняет Поле = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, "НомерСтроки", "Номер строки"); Поле.Роль.НомерПериода = 1; Поле = ТиповыеОтчеты.ДобавитьПолеНабораДанных(СхемаКомпоновкиДанных.НаборыДанных, "Регистратор", "Регистратор"); Поле.Роль.НомерПериода = 2; сч = 3; Для Каждого ПолеПериод Из СписокПериодов Цикл ПолеПериод.Значение.Роль.НомерПериода = сч; Если сч > 3 Тогда ПолеПериод.Значение.Роль.ТипПериода = ТипПериодаКомпоновкиДанных.Дополнительный; КонецЕсли; сч = сч+1; КонецЦикла; КонецЕсли;

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

UPDATE: мне подсказали в комментариях, что на диске ИТС в свое время вышла статья на эту тему. К сожалению, эта статья прошла мимо меня, но помочь мне в решении проблем с универсальным отчетом она бы смогла лишь отчасти. Увы, заморочки платформы со служебными полями СКД, такими как "Recorder", там также не описаны.

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

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

Также создадим простые настройки варианта:

В результате получим следующий отчет:

У вас есть вопрос, нужна помощь консультанта?

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

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

Следует помнить, что у полей с ролью "Период" есть флажок "Дополнительный". И если по каким-то причинам у поля ПериодСекунда он будет снят, то отчет вернется к некорректному варианту. Для правильного расчета остатков необходимо либо наличие взведенного флажка "Дополнительный" в роли, либо присутствие поля в выбранных полях отчета на уровне варианта.