Как это работает
В справочнике подсистемы настраиваются правила контроля (подробности ниже) для необходимых регистров, их измерений и ресурсов.
При записи документа (проведение оперативное или неоперативное, отмена проведения) его «новые» движения сравниваются со «старыми» в рамках настроенных правил. Результат сравнения - набор таблиц значений, содержащих информацию об изменениях.
Если изменения в движениях выявлены, то выполняется контролирующий запрос (или схема СКД), описанный (в большинстве случаев полученный автоматически) в правиле контроля. Запрос использует таблицы изменений и не обрабатывает данные по тем наборам измерений, которые не были изменены. Таким образом, минимизируется время выполнения запроса.
Результатом выполнения запроса является таблица значений, так называемая «таблица результата контроля». Если она пустая, то контроль пройден.
Если же в ней есть одна или более записей, то возможны следующие варианты развития событий: пользователь получит отказ в совершении своего действия (записи документа), будет сгенерирована ошибка или же пользователю будет разрешено выполняемое им действие.
В любом варианте пользователь сможет получить настроенное разработчиком правил контроля сообщение о возникших проблемах. Сообщение может быть достаточно подробным, поскольку при его настройке используются данные таблицы результата контроля и самого документа.
В завершение вся ситуация может быть запротоколирована в специальном регистре сведений подсистемы с сохранением всей доступной информации, включая данные всех исходных, рассчитанных и результирующих таблиц и даже данные всех внутренних таблиц контролирующего запроса.
Кроме этого, протоколируется длительность всех этапов контроля и записи всего документа.
Для чего это нужно?
Это, конечно, риторический вопрос. Особенно, если в конфигурации вообще нет никаких механизмов контроля товарных остатков или взаиморасчетов с клиентами. Или еще чего-то, что всегда очень хочется проконтролировать.
Желание заказчика «а можно сделать так, чтобы им (пользователям) нельзя было …?» - уже притча во языцех.
Типовые конфигурации, во всем их разнообразии, в плане контроля и его вариантов до сих пор остаются не очень гибкими.
Многообразие вариантов ведения бизнеса на постсоветском пространстве и внедренческих подходов делают иногда неработоспособными типовые решения по контролю тех или иных ресурсов в конфигурациях.
Достаточно вспомнить контроль только при оперативном проведении в УТ 10.3. Любовь организаций к ведению учета «задним числом» - тема отдельного разговора, не буду активно развивать ее здесь. Однако вкупе с таким контролем остатков это ядерная смесь.
Или возьмем более «свежие» проблемы: отсутствие контроля при отмене проведения Приходного ордера в ERP 2.4, позволяющее без проблем загнать остатки в минус.
Еще здесь же (ERP 2.4) в наличии «кривизна контроля» товарных остатков на конец дня, позволяющая делать приход позже расхода. При выбытии запрещено оперативное проведение. В последствии это может вызвать проблемы в БП 3, например, из-за нарушения строгой последовательности операций.
Можно много и долго говорить о «неправильной постановке учета», «непонимании работы типовых механизмов учета и/или контроля», «криво настроенных правах пользователей» и т.п. И даже в большинстве своем все это может быть правдиво…
Но боль чаще всего нужно лечить оперативно, здесь и сейчас, и с минимальными затратами.
Займемся же этим!
Я взял для примера демо-базу ERP версии 2.4.12.64, платформа 1С:Предприятие 8.3.17.1386 . Применил расширение ККО, в конфигураторе настроив режимы совместимости и соответствия ссылок в расширении, а также отключив Безопасный режим применения расширения (из-за использования привилегированного режима в модулях расширения).
Зашел под пользователем «Администратор (СоколовМИ)». Ну да, это же пример. И кто сказал, что мало пользователей с административными правами? Особенно на этапе внедрения или даже какое-то время после него?
Нашел Приходный ордер 00-00000005 от 10.04.2017 и отменил его проведение. Все контроли остатков включены, заметьте, и для моего сеанса ничего не выключалось. В итоге в ведомости по товарам на складах по «Складу бытовой техники» получаю вот такую «красоту-красноту»:
Опять провожу документ, дабы вернуть все в исходное состояние и иду настраивать правило ККО в справочник расширения «Правила комплексного контроля (комплексный контроль остатков)».
Создаю новый элемент, устанавливаю в шапке формы наименование «Товары на складе в наличии» и реквизит «Вариант регистрации событий контроля» в значение «Регистрировать все события (с данными результата контроля)».
На вкладке «Основные настройки» -> «Регистры и измерения» добавляю новую строку и выбираю регистр «Товары на складах»:
Автоматически в строке заполняются измерения регистра.
Переходим на вкладку «Формулы ресурсов». В левую табличку «Формулы» добавляем новую строку, в колонке «Псевдоним» пишем «ОтрицательноеКоличествоНаСкладе» (здесь должно указываться значение, подчиняющееся правилам именования переменных во встроенном языке 1С). Жмем на кнопку в колонке «Формула», в открывшемся окне дважды кликаем на ресурс «ВНаличии» и жмем ОК:
Появивишееся значение «< 0» в колонке «Условие» оставляем без изменений. Правую таблицу с появившимся в ней ресурсом не трогаем:
Переходим на вкладку «Получение результата контроля», пробегаем глазами сгенерированный текст контрольного запроса. Если он красиво отформатирован, значит системе удалось сгенерировать его правильно:
ВЫБРАТЬ
ОбщаяТаблицаИзменений.Номенклатура КАК Номенклатура,
ОбщаяТаблицаИзменений.Характеристика КАК Характеристика,
ОбщаяТаблицаИзменений.Назначение КАК Назначение,
ОбщаяТаблицаИзменений.Склад КАК Склад,
ОбщаяТаблицаИзменений.Помещение КАК Помещение,
ОбщаяТаблицаИзменений.Серия КАК Серия
ПОМЕСТИТЬ ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений
ИЗ
&кко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
ТоварыНаСкладах.ВидДвижения КАК ВидДвижения,
ТоварыНаСкладах.ВНаличии КАК ВНаличии
ПОМЕСТИТЬ ВТТоварыНаСкладах_ТаблицаНовыхДвижений
ИЗ
&ТоварыНаСкладах_ТаблицаНовыхДвижений КАК ТоварыНаСкладах
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
СУММА(ТоварыНаСкладах.ВНаличии) КАК ВНаличии
ПОМЕСТИТЬ ВТТоварыНаСкладах_Остатки
ИЗ
(ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.ВНаличии
ИНАЧЕ -ТоварыНаСкладах.ВНаличии
КОНЕЦ КАК ВНаличии
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура
И ОбщаяТаблицаИзменений.Характеристика = ТоварыНаСкладах.Характеристика
И ОбщаяТаблицаИзменений.Назначение = ТоварыНаСкладах.Назначение
И ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Помещение = ТоварыНаСкладах.Помещение
И ОбщаяТаблицаИзменений.Серия = ТоварыНаСкладах.Серия
ГДЕ
ТоварыНаСкладах.Период <= &кко_ДатаАнализа
И ТоварыНаСкладах.Активность
И ТоварыНаСкладах.Регистратор <> &Ссылка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Характеристика,
ТоварыНаСкладах.Назначение,
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Помещение,
ТоварыНаСкладах.Серия,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.ВНаличии
ИНАЧЕ -ТоварыНаСкладах.ВНаличии
КОНЕЦ
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТТоварыНаСкладах_ТаблицаНовыхДвижений КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура
И ОбщаяТаблицаИзменений.Характеристика = ТоварыНаСкладах.Характеристика
И ОбщаяТаблицаИзменений.Назначение = ТоварыНаСкладах.Назначение
И ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Помещение = ТоварыНаСкладах.Помещение
И ОбщаяТаблицаИзменений.Серия = ТоварыНаСкладах.Серия) КАК ТоварыНаСкладах
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Характеристика,
ТоварыНаСкладах.Назначение,
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Помещение,
ТоварыНаСкладах.Серия
ИМЕЮЩИЕ
СУММА(ТоварыНаСкладах.ВНаличии) <> 0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
ТоварыНаСкладах.ВНаличии КАК ТоварыНаСкладах_ВНаличии,
ТоварыНаСкладах.ВНаличии КАК ОтрицательноеКоличествоВНаличии
ИЗ
ВТТоварыНаСкладах_Остатки КАК ТоварыНаСкладах
ГДЕ
(ЛОЖЬ
ИЛИ ТоварыНаСкладах.ВНаличии < 0)
Переходим на вкладку «Настройка сообщений», устанавливаем флаг «Выводить сообщение» и в поле «Текст сообщения» помещаем следующий текст:
Комплексный контроль остатков (Товары на складе в наличии).
При записи документа сформируется недопустимое состояние остатков
по номенклатуре: [СтрокаТаблицыСообщений.Номенклатура.Наименование] ([СтрокаТаблицыСообщений.Номенклатура.Код])
на складе: [СтрокаТаблицыСообщений.Склад.Наименование]
[?(СтрокаТаблицыСообщений.ОтрицательноеКоличествоВНаличии < 0, Символы.Таб + "Остаток на складе в наличии = " + СтрокаТаблицыСообщений.ОтрицательноеКоличествоВНаличии + " " + СтрокаТаблицыСообщений.Номенклатура.ЕдиницаИзмерения + Символы.ПС, "")]
Устанавливаем в шапке флаг «Активная»
Сохраняем правило. Настройка завершена. Согласитесь, это совсем недолго в нашем простейшем случае.
Так как мы уже записывали документ, то для применения свежего правила контроля нужно заново зайти в базу. Дело в том, что в целях повышения производительности работы ККО для получения правил контроля используется общий модуль с повторным использованием.
Зашли, нашли наш приходный ордер, пробуем отменить его проведение.
Система заблокировала наше действие и сообщила о причинах:
Можно зайти в регистр сведений «Регистрация событий (комплексный контроль остатков)» и изучить появившуюся в нем запись:
Итак, мы с вами рассмотрели работу ККО на простом примере. Давайте теперь несколько усложним задачу.
Для этого уйдем в другую конфигурацию и настроим правило сразу для двух логически связанных регистров.
В этом примере я буду использовать уже достаточно старую и серьезно потрепанную различными доработками УТ 10.3 своего клиента.
Тут расширение уже не применить (обычное приложение). Поэтому через сравнение/объединение просто дополняю конфигурацию подсистемой ККО (нужно установить флажки объединения по единственной подсистеме файла Комплексный контроль остатков.cf).
Заходим в справочник правил контроля, создаем новый элемент, назовем его «Свободные остатки» (будем считать свободным остатком разницу между остатком на складе и резервом). На вкладке «Регистры и измерения» основных настроек добавляем последовательно регистры «ТоварыНаСкладах» и «ТоварыВРезервеНаСкладах».
При добавлении второго и последующих регистров одноименные измерения будут пытаться автоматически расположиться в одной колонке. Заголовки колонок, у которых заполнены измерения по всем регистрам подсвечены зеленым цветом. Такие измерения называются «общими» в рамках текущего правила контроля.
Я знаю, что характеристики номенклатуры в этой базе не используются. Также не используется резервирование по сериям номенклатуры. Кроме того, серии в документы перемещения и расхода подбираются в большинстве случаев автоматически (собственные доработки клиента) и конечного пользователя мало интересуют.
Посему я очищаю в настройке регистров все измерения, кроме «Склад» и «Номенклатура».
Но я хочу добавить в контроль информацию о документе резерва, который потенциально может загонять в минус свободные остатки при, например, отмене проведения какой-нибудь накладной на внутреннее перемещение или поступления товаров.
Для этого я добавляю третьим измерением к настройке регистра «ТоварыВРезервеНаСкладах» еще и «ДокументРезерва».
Теперь все это должно выглядеть примерно вот так:
Переходим на вкладку формул ресурсов и настраиваем сразу две формулы следующим образом:
Теперь стоит обратить внимание на сформировавшийся текст запроса на вкладке «Получение результата контроля», особенно на последний запрос в пакете:
ВЫБРАТЬ
ОбщаяТаблицаИзменений.Склад КАК Склад,
ОбщаяТаблицаИзменений.Номенклатура КАК Номенклатура
ПОМЕСТИТЬ ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений
ИЗ
&кко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.ВидДвижения КАК ВидДвижения,
ТоварыНаСкладах.Количество КАК Количество
ПОМЕСТИТЬ ВТТоварыНаСкладах_ТаблицаНовыхДвижений
ИЗ
&ТоварыНаСкладах_ТаблицаНовыхДвижений КАК ТоварыНаСкладах
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад КАК Склад,
ТоварыВРезервеНаСкладах.Номенклатура КАК Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва КАК ДокументРезерва,
ТоварыВРезервеНаСкладах.ВидДвижения КАК ВидДвижения,
ТоварыВРезервеНаСкладах.Количество КАК Количество
ПОМЕСТИТЬ ВТТоварыВРезервеНаСкладах_ТаблицаНовыхДвижений
ИЗ
&ТоварыВРезервеНаСкладах_ТаблицаНовыхДвижений КАК ТоварыВРезервеНаСкладах
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
СУММА(ТоварыНаСкладах.Количество) КАК Количество
ПОМЕСТИТЬ ВТТоварыНаСкладах_Остатки
ИЗ
(ВЫБРАТЬ
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.Количество
ИНАЧЕ -ТоварыНаСкладах.Количество
КОНЕЦ КАК Количество
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура
ГДЕ
ТоварыНаСкладах.Период <= &кко_ДатаАнализа
И ТоварыНаСкладах.Активность
И ТоварыНаСкладах.Регистратор <> &Ссылка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Номенклатура,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.Количество
ИНАЧЕ -ТоварыНаСкладах.Количество
КОНЕЦ
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТТоварыНаСкладах_ТаблицаНовыхДвижений КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура) КАК ТоварыНаСкладах
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Номенклатура
ИМЕЮЩИЕ
СУММА(ТоварыНаСкладах.Количество) <> 0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад КАК Склад,
ТоварыВРезервеНаСкладах.Номенклатура КАК Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва КАК ДокументРезерва,
СУММА(ТоварыВРезервеНаСкладах.Количество) КАК Количество
ПОМЕСТИТЬ ВТТоварыВРезервеНаСкладах_Остатки
ИЗ
(ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад КАК Склад,
ТоварыВРезервеНаСкладах.Номенклатура КАК Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва КАК ДокументРезерва,
ВЫБОР
КОГДА ТоварыВРезервеНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыВРезервеНаСкладах.Количество
ИНАЧЕ -ТоварыВРезервеНаСкладах.Количество
КОНЕЦ КАК Количество
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезервеНаСкладах КАК ТоварыВРезервеНаСкладах
ПО ОбщаяТаблицаИзменений.Склад = ТоварыВРезервеНаСкладах.Склад
И ОбщаяТаблицаИзменений.Номенклатура = ТоварыВРезервеНаСкладах.Номенклатура
ГДЕ
ТоварыВРезервеНаСкладах.Период <= &кко_ДатаАнализа
И ТоварыВРезервеНаСкладах.Активность
И ТоварыВРезервеНаСкладах.Регистратор <> &Ссылка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад,
ТоварыВРезервеНаСкладах.Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва,
ВЫБОР
КОГДА ТоварыВРезервеНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыВРезервеНаСкладах.Количество
ИНАЧЕ -ТоварыВРезервеНаСкладах.Количество
КОНЕЦ
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТТоварыВРезервеНаСкладах_ТаблицаНовыхДвижений КАК ТоварыВРезервеНаСкладах
ПО ОбщаяТаблицаИзменений.Склад = ТоварыВРезервеНаСкладах.Склад
И ОбщаяТаблицаИзменений.Номенклатура = ТоварыВРезервеНаСкладах.Номенклатура) КАК ТоварыВРезервеНаСкладах
СГРУППИРОВАТЬ ПО
ТоварыВРезервеНаСкладах.Склад,
ТоварыВРезервеНаСкладах.Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва
ИМЕЮЩИЕ
СУММА(ТоварыВРезервеНаСкладах.Количество) <> 0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад КАК Склад,
ТоварыВРезервеНаСкладах.Номенклатура КАК Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва КАК ДокументРезерва,
0 КАК ТоварыНаСкладах_Количество,
ТоварыВРезервеНаСкладах.Количество КАК ТоварыВРезервеНаСкладах_Количество,
0 КАК СвободныйОстаток,
ТоварыВРезервеНаСкладах.Количество КАК РезервНаСкладе
ИЗ
ВТТоварыВРезервеНаСкладах_Остатки КАК ТоварыВРезервеНаСкладах
ГДЕ
(ЛОЖЬ
ИЛИ ТоварыВРезервеНаСкладах.Количество < 0)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ВложенныйЗапрос.Склад,
ВложенныйЗапрос.Номенклатура,
НЕОПРЕДЕЛЕНО,
СУММА(ВложенныйЗапрос.ТоварыНаСкладах_Количество),
СУММА(ВложенныйЗапрос.ТоварыВРезервеНаСкладах_Количество),
СУММА(ВложенныйЗапрос.ТоварыНаСкладах_Количество - ВложенныйЗапрос.ТоварыВРезервеНаСкладах_Количество),
0
ИЗ
(ВЫБРАТЬ
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
НЕОПРЕДЕЛЕНО КАК ДокументРезерва,
ТоварыНаСкладах.Количество КАК ТоварыНаСкладах_Количество,
0 КАК ТоварыВРезервеНаСкладах_Количество
ИЗ
ВТТоварыНаСкладах_Остатки КАК ТоварыНаСкладах
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТоварыВРезервеНаСкладах.Склад,
ТоварыВРезервеНаСкладах.Номенклатура,
ТоварыВРезервеНаСкладах.ДокументРезерва,
0,
ТоварыВРезервеНаСкладах.Количество
ИЗ
ВТТоварыВРезервеНаСкладах_Остатки КАК ТоварыВРезервеНаСкладах) КАК ВложенныйЗапрос
СГРУППИРОВАТЬ ПО
ВложенныйЗапрос.Склад,
ВложенныйЗапрос.Номенклатура
ИМЕЮЩИЕ
(ЛОЖЬ
ИЛИ СУММА(ВложенныйЗапрос.ТоварыНаСкладах_Количество - ВложенныйЗапрос.ТоварыВРезервеНаСкладах_Количество) < 0)
Для тех формул, которые используют ресурсы только одного регистра будет создан отдельный запрос в объединении, включающий в себя все его измерения, в том числе и не «общие». Для всех остальных формул будет использован объединяющий запрос используемых в формуле регистров с расчетом значения формул только по «общим» измерениям.
Сообщения настраиваю следующим образом:
Комплексный контроль остатков (Свободные остатки).
При записи документа будет сформировано недопустимое состояние остатков
по номенклатуре: [СтрокаТаблицыСообщений.Номенклатура.Наименование] ([СтрокаТаблицыСообщений.Номенклатура.Код])
на складе: [СтрокаТаблицыСообщений.Склад.Наименование]: [?(ЗначениеЗаполнено(СтрокаТаблицыСообщений.ДокументРезерва), Символы.ПС + "по документу резерва: ", "")][?(ЗначениеЗаполнено(СтрокаТаблицыСообщений.ДокументРезерва), СокрЛП(СтрокаТаблицыСообщений.ДокументРезерва), "")]
[?(СтрокаТаблицыСообщений.СвободныйОстаток < 0, Символы.Таб + "Свободный остаток на складе = " + СтрокаТаблицыСообщений.СвободныйОстаток + " " + СтрокаТаблицыСообщений.Номенклатура.ЕдиницаХраненияОстатков + Символы.ПС, "")][?(СтрокаТаблицыСообщений.РезервНаСкладе < 0, Символы.Таб + "Количество в резерве на складе = " + СтрокаТаблицыСообщений.РезервНаСкладе + " " + СтрокаТаблицыСообщений.Номенклатура.ЕдиницаХраненияОстатков + Символы.ПС, "")]
Устанавливаю настройку регистрации событий ККО в значение «Регистрировать все события (с данными результата контроля)», отмечаю флаг «Активная». Сохраняю настройку и пробую отменить проведение у одного из «позавчерашних» перемещений, в котором указаны документы резерва. То есть, товар был зарезервирован под клиента и перемещался на склад реализации, где, скорее всего, к настоящему моменту был благополучно продан. Получаю результат:
Изучим зарегистрированную информацию о событии:
Мы познакомились с основной функциональностью и принципами работы ККО (комплексного контроля остатков).
Теперь перейдем к подробностям работы ККО.
Если вы успели заметить, запрос ККО, тот самый, который формируется автоматически, строится по основным таблицам регистра накопления, а отнюдь не по виртуальным.
Это сделано для возможности выделения из движений, формирующих остатки по измерениям, движений текущего документа.
Возможно, это влияет на скорость выполнения запроса, но по проводимым экспериментам в доступных мне условиях я этого не заметил.
В любом случае, на скорость выполнения запросов и по виртуальным таблицам, и по реальным, главным образом, влияет количество проверяемых позиций (наборов различных измерений). Но основное влияние на этот показатель оказывает количество движений в базе по каждому отдельно взятому набору измерений!
Сама система выстроена таким образом, что неизменившиеся наборы измерений проверяться не будут. То есть, если вы зашли в уже проведенный, например складской, документ с 200-ми строк в ТЧ Товары, и изменили только одну из них таким образом, что это повлияло на движения документа, то проверять ККО будет только одну изменившуюся позицию.
С другой стороны, если вы проводите новый документ или отменяете проведение существующего, то проверяться будут все движения по настроенным в ККО регистрам. Это может занимать определенное время. Но тут самое время вспомнить о наличии типовых механизмов в вашей конфигурации, которые, возможно, стоит отключить или модифицировать при использовании ККО в случае дублирования функций.
Это позволит вам высвободить необходимые ресурсы системы в случае их нехватки.
Основную часть времени при использовании ККО занимает именно выполнение контролирующего запроса. Остальные механизмы работают очень быстро.
В базе клиента (из рассмотренного примера в УТ 10.3) в боевом режиме работают сразу три правила по товарно-складским регистрам. Одно контролирует «свободные остатки» - разницу между остатком на складе и резервом. Второе – разницу между остатком на складе и суммой остатков организаций.
Третье анализирует «правильность» списания партий при работе «задним числом». Но при этом не блокирует действия пользователя и не выводит ему никаких сообщений. Это правило, вернее данные, получаемые в ходе его обработки, используется в работе одной регламентной операции. ККО сохраняет все свои данные (исходные, рассчитанные и результирующие) в структуре ДополнительныеСвойства объекта документа по ключу «кко_ДанныеКонтроля». Эти данные могут быть использованы различными программными обработками.
И «типовые» механизмы не отключены. ККО не будет выполняться, если в транзакции записи документа уже произошла критическая ошибка (Отказ=Истина), полученная в других механизмах проверки раньше. То есть, ККО в данном случае используется в «дополнение» к существующим «типовым» механизмам.
Это все к тому, что я, как разработчик правил ККО, посчитал такой подход приемлемым, имея в виду общую нагруженность системы и долю времени, требуемую ККО для обработки иногда сразу трех правил по одному документу.
Другой вопрос, что, проанализировав общее время, затрачиваемое на проведение некоторых видов документов, я поставил в ближайшие планы оптимизацию процедур записи и проведения этих документов :-)
От базы к базе значения производительности всегда будут разными. Но всегда можно проанализировать производительность правил ККО с помощью собираемой в регистре-логе статистики:
Сам лог, кстати, записывается в фоновом задании, не забирая время у транзакции записи документа.
Какие колонки содержит таблица результата контроля? Что может быть параметром запроса? Для чего и как можно использовать схему СКД вместо контролирующего запроса?
В том запросе, что ККО формирует автоматически, пока вы настраиваете в правиле регистры, измерения и формулы (ресурсы), можно выделить три основных блока:
- Трансляция во внутренние таблицы запроса необходимых таблиц значений, рассчитанных при сравнении «старых» и «новых» движений документа.
- Расчет «прогнозируемых» остатков по каждому регистру отдельно с учетом движений текущего документа.
- Выполнение финального запроса, формирующего таблицу результата контроля. В этом запросе рассчитываются все формулы правила ККО.
В колонках результата финального запроса помимо формул всегда присутствуют все ресурсы регистров, использованные в этих формулах. Они имеют имя (псевдоним) в формате [ИмяРегистра]_[ИмяРесурса]. Конечно же, здесь присутствуют колонки используемых в правиле измерений. Если измерение «общее», то имя колонки запроса будет соответствовать имени этого измерения у первого в списке регистра.
Источниками параметров контролирующего запроса могут быть:
- Записываемый объект документа. Не ссылка, а именно объект.
- Структура ДополнительныеСвойства записываемого объекта документа.
- Любые рассчитанные таблицы ККО.
Параметр должен совпадать по имени с реквизитом объекта, ключом структуры ДополнительныеСвойства объекта или с именем таблицы ККО. При совпадении имен у перечисленных сущностей одно значение будет «затирать» другое в параметрах запроса именно в такой последовательности.
Теперь про рассчитанные таблицы ККО.
Есть единственная общая таблица в разделе «кко_Общие» - ТаблицаИзмененныхНаборовИзмерений. В запросе обращение к ней как к параметру возможно по имени &кко_Общие_ ТаблицаИзмененныхНаборовИзмерений. Она содержит информацию обо всех наборах «общих» измерений, ресурсы которых (контролируемые правилом ККО) были изменены в процессе проведения документа. Эта таблица используется автоматически формируемым запросом правила ККО.
Для каждого указанного в правиле регистра рассчитывается одинаковый набор таблиц. В запросе обращение к ним как к параметрам возможно по именам в формате &[ИмяРегистра]_[ИмяТаблицы]. Имена и краткое описание таблиц:
- «ТаблицаИсходныхДвижений» содержит данные о движениях документа в регистре ДО записи. Колонки таблицы - все указанные в правиле ККО для регистра измерения и ресурсы, а также колонка «ВидДвижения» (приход/расход). Свернута по измерениям и виду движения с расчетом суммы по ресурсам.
- «ТаблицаНовыхДвижений» содержит данные о движениях документа ПОСЛЕ их формирования в процессе обработки проведения документа. Состав колонок аналогичен предыдущей таблице. Эта таблица используется автоматически формируемым запросом правила ККО.
- «ТаблицаИзменений» содержит результат сравнения двух предыдущих таблиц. Сравнение производится по наборам измерений, сравниваются ресурсы. К колонкам таблиц исходных и новых движений добавляется колонка «кко_Знак», содержащая 0 или 1. 0 означает, что строка в таблице новых движений отсутствует относительно таблицы старых, 1 – что строка новая. Проще: если данные по набору измерений не изменились, то в таблице этого набора измерений не будет. Если изменились – будет две строки: одна с кко_Знак = 0 из таблицы исходных движений, другая с кко_Знак = 1 из таблицы новых движений.
- «ТаблицаКорректировок» содержит все данные предыдущей таблицы, но с обнуленными значениями ресурсов по «старым» движениям. Отсутствует колонка «кко_Знак». Свернута по измерениям и виду движения с расчетом суммы по ресурсам.
- «ТаблицаАбсолютныхРазниц» содержит все измененные наборы измерений с рассчитанной разницей в колонках ресурсов между новыми и старыми движениями с учетом вида движения (если кко_Знак = 0 и «приход» или кко_Знак = 1 и «расход», то значение ресурса вычитается из общего результата, наоборот - суммируется). Колонки «кко_Знак» и «ВидДвижения» отсутствуют. Проще: в этой таблице рассчитано абсолютное увеличение или уменьшение остатка по ресурсу в новых движениях относительно старых.
Содержимое всех этих таблиц, а также внутренних таблиц контролирующего запроса можно анализировать при настройке и отладке правил ККО в регистре-логе (открываются по двойному клику на имени таблицы в поле «Данные контроля»):
Кроме этого, запрос ККО использует параметр &кко_ДатаАнализа. По умолчанию его значением является пустая дата, то есть остатки считаются на позицию самого последнего документа в системе. Как это можно изменить я расскажу в следующем разделе.
Автоматически формируемый запрос в правиле ККО можно заменить произвольным запросом или модифицировать, дабы он учитывал специфику работы регистров в вашей конфигурации. Правила использования параметров в запросе останутся те же.
Приведу пример. В старой доброй УТ 10.3 есть Регистр «ПартииТоваровНаСкладах» и измерение в нем «СерияНоменклатуры». Такое же измерение есть в регистре «ТоварыНаСкладах».
Если вы используете оба этих регистра и это измерение в качестве «общего» в одном правиле ККО, то при доработке запроса ККО нужно учесть, что серия номенклатуры может быть заполнена в движениях документа в регистре «ТоварыНаСкладах», но остаться пустой в регистре «ПартииТоваровНаСкладах». За это отвечают реквизиты номенклатуры «Вести учет по сериям» и «Вести партионный учет по сериям».
Для этого нужно получить в запросе (после получения внутренних таблиц, например) эти реквизиты для номенклатур из справочника и использовать их значения в конструкциях ВЫБОР…КОНЕЦ при расчете значений измерения СерияНоменклатуры в запросах пакета.
В некоторых случаях вам может не хватить функциональности одного единственного запроса для описания правила ККО. В этом случае вы можете использовать схему СКД вместо запроса.
СКД позволит вам описать несколько наборов данных в сложных случаях или ограничить область применения ККО отборами (например, проверять только определенные организации или склады, а остальные не проверять).
Главное, чтобы на выходе получилась таблица значений с ожидаемыми ККО колонками. Правила применения параметров к наборам данных в схеме те же, что и для отдельного запроса.
А вот сам механизм использования отличается от традиционного для расчета коллекции данных с помощью СКД.
Если вы в уже настроенном правиле ККО с автоматически сформированным запросом выберете использование схемы СКД и зайдете в редактор схемы (в толстом клиенте, разумеется), то увидите единственный набор записей с несколько модифицированным, относительно первоначального, запросом и единственный вариант настройки схемы с детальными записями:
ВЫБРАТЬ
0 КАК Номенклатура,
0 КАК Характеристика,
0 КАК Назначение,
0 КАК Склад,
0 КАК Помещение,
0 КАК Серия
ПОМЕСТИТЬ ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
0 КАК Номенклатура,
0 КАК Характеристика,
0 КАК Назначение,
0 КАК Склад,
0 КАК Помещение,
0 КАК Серия,
0 КАК ВидДвижения,
0 КАК ВНаличии
ПОМЕСТИТЬ ВТТоварыНаСкладах_ТаблицаНовыхДвижений
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
СУММА(ТоварыНаСкладах.ВНаличии) КАК ВНаличии
ПОМЕСТИТЬ ВТТоварыНаСкладах_Остатки
ИЗ
(ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.ВНаличии
ИНАЧЕ -ТоварыНаСкладах.ВНаличии
КОНЕЦ КАК ВНаличии
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура
И ОбщаяТаблицаИзменений.Характеристика = ТоварыНаСкладах.Характеристика
И ОбщаяТаблицаИзменений.Назначение = ТоварыНаСкладах.Назначение
И ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Помещение = ТоварыНаСкладах.Помещение
И ОбщаяТаблицаИзменений.Серия = ТоварыНаСкладах.Серия
ГДЕ
ТоварыНаСкладах.Период <= &кко_ДатаАнализа
И ТоварыНаСкладах.Активность
И ТоварыНаСкладах.Регистратор <> &Ссылка
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Характеристика,
ТоварыНаСкладах.Назначение,
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Помещение,
ТоварыНаСкладах.Серия,
ВЫБОР
КОГДА ТоварыНаСкладах.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
ТОГДА ТоварыНаСкладах.ВНаличии
ИНАЧЕ -ТоварыНаСкладах.ВНаличии
КОНЕЦ
ИЗ
ВТкко_Общие_ТаблицаИзмененныхНаборовИзмерений КАК ОбщаяТаблицаИзменений
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТТоварыНаСкладах_ТаблицаНовыхДвижений КАК ТоварыНаСкладах
ПО ОбщаяТаблицаИзменений.Номенклатура = ТоварыНаСкладах.Номенклатура
И ОбщаяТаблицаИзменений.Характеристика = ТоварыНаСкладах.Характеристика
И ОбщаяТаблицаИзменений.Назначение = ТоварыНаСкладах.Назначение
И ОбщаяТаблицаИзменений.Склад = ТоварыНаСкладах.Склад
И ОбщаяТаблицаИзменений.Помещение = ТоварыНаСкладах.Помещение
И ОбщаяТаблицаИзменений.Серия = ТоварыНаСкладах.Серия) КАК ТоварыНаСкладах
СГРУППИРОВАТЬ ПО
ТоварыНаСкладах.Номенклатура,
ТоварыНаСкладах.Характеристика,
ТоварыНаСкладах.Назначение,
ТоварыНаСкладах.Склад,
ТоварыНаСкладах.Помещение,
ТоварыНаСкладах.Серия
ИМЕЮЩИЕ
СУММА(ТоварыНаСкладах.ВНаличии) <> 0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТоварыНаСкладах.Номенклатура КАК Номенклатура,
ТоварыНаСкладах.Характеристика КАК Характеристика,
ТоварыНаСкладах.Назначение КАК Назначение,
ТоварыНаСкладах.Склад КАК Склад,
ТоварыНаСкладах.Помещение КАК Помещение,
ТоварыНаСкладах.Серия КАК Серия,
ТоварыНаСкладах.ВНаличии КАК ТоварыНаСкладах_ВНаличии,
ТоварыНаСкладах.ВНаличии КАК ОтрицательноеКоличествоВНаличии
ИЗ
ВТТоварыНаСкладах_Остатки КАК ТоварыНаСкладах
ГДЕ
(ЛОЖЬ
ИЛИ ТоварыНаСкладах.ВНаличии < 0)
В настройке вы можете сразу же указать ограничительные отборы, если это необходимо.
Но я бы хотел вернуться к запросу. В схеме СКД нельзя так запросто использовать в качестве параметров таблицы значений, как это можно делать в простом запросе. Именно поэтому модификации в пакете подвергаются запросы к таблицам-параметрам. Они преобразуются в «заглушки».
В версии платформы 8.3.17 появилась возможность отправлять в СКД таблицы значений через менеджер временных таблиц и без подобных ухищрений можно было бы обойтись. Но система разрабатывалась еще до выхода в свет первой беты платформы 8.3.17.
Возможно, со временем я переделаю механизм, но пока он и его производительность меня устраивает.
Двигаемся дальше. Как же я передаю в СКД таблицы значений? А вот никак. Перед выполнением схемы я получаю результат для каждого набора данных схемы с запросом (если вы вдруг сделаете их несколько) отдельно.
Для этого я получаю текст запроса набора, провожу его «обратное» преобразование для «заглушек», подставляю параметры как в обычный запрос ККО и выполняю, помещая результат в таблицу значений.
Далее модифицирую схему, заменяя наборы данных – запросы наборами-объектами, и подставляю в наборы полученные таблицы. После чего выполняю схему СКД, получая конечный результат.
На тех примерах, что исследовал я, значительной потери производительности от применения подобных «выкрутасов» заметить не удалось. Так что, считаю такой вариант использования вполне жизнеспособным, пока кто-то или что-то не докажет мне обратного.
Помимо уже рассмотренных в примерах, в правиле ККО присутствуют дополнительные параметры, позволяющие расширить возможности системы.
Настройка «Активная» в шапке правила полностью включает или отключает правило.
Настройки в разделе «Использование» («Использовать при оперативном проведении», «Использовать при неоперативном проведении» и «Использовать при отмене проведения») сами все объясняют своим названием.
Вкладка «Границы контроля»:
Табличная часть справочника, представленная на ней, заполняется автоматически при создании нового элемента. Вы можете изменить только реквизит «Уровень контроля» напротив каждого значения границы контроля.
Что означает «граница контроля»? В общем-то, это очевидно, стоит взглянуть на перечень границ. ККО может контролировать остатки на любую из представленных границами дат, рассчитав ее от даты обрабатываемого документа.
Уровни контроля и их назначение:
- Не контролировать. ККО не будет выполняться. Не будет даже произведен анализ текущих движений документа в событии ПередЗаписью.
- Получить результат контроля. ККО будет выполнен, пользователю может быть показано сообщение ККО, если оно настроено разработчиком правила. Никаких ограничений на действия пользователя наложено не будет.
- Отказывать в проведении операции. Пользователю будет отказано в проведении операции при наличии записей в таблице результатов контроля и показом настроенного сообщения. Технически: устанавливается параметр Отказ в значение Истина.
- Вызывать исключение. После показа сообщения ККО (если оно настроено), программным кодом ККО будет сгенерирована ошибка с текстом «Комплексный контроль остатков: недопустимое состояние остатков при выполнении действия!»
С помощью одного правила ККО можно контролировать остатки на несколько дат одновременно. Но нужно понимать, что при этом запрос контроля будет выполняться также несколько раз.
Можно, например, контролировать остатки на одну дату «жестко» (на конец дня, например), на другую - в режиме уведомлений: получать результат контроля на конец месяца и просто сообщать пользователю о потенциальных проблемах.
Вкладка «Настройка документов»:
Здесь можно настроить разный уровень контроля для разных видов документов.
По умолчанию ККО контролирует все документы, которые двигают настроенные в правилах регистры и вызывают обработку событий проведения и отмены проведения.
Но если из-за особенностей бизнес-процессов компании или по еще каким-то причинам нежелательны жесткие ограничения на работу с определенными видами документов, то это можно настроить именно здесь.
Вкладка «Настройка пользователей/прав»:
Настройки на этой вкладке аналогичны настройкам на предыдущей, с той лишь разницей, что касаются они не видов документов, а определенных пользователей и ролей.
Уровень контроля при совпадении условий на разных вкладках правила ККО для текущего сеанса пользователя будет выбираться минимальный из всех возможных.
В приведенных примерах настройки правил ККО я уже показывал, как можно настроить сообщения пользователю в случае непустого результата контроля. Теперь немного про «механику» процесса.
Если в правиле ККО установлен флаг «Выводить сообщения» и результат контроля содержит одну или более записей, то таблица результата контроля копируется в таблицу с именем «ТаблицаСообщений» и к ней добавляется колонка «кко_ТекстСообщения», в которую будет для каждой строки помещен текст сформированного сообщения. Эта таблица также будет сохраняться в регистр-лог вместе с остальными данными ККО.
Разработчику правила предоставлена возможность дополнительной обработки таблицы сообщений перед формированием текстов. Для этого нужно установить флаг «Обработать таблицу сообщений» и в появившееся поле «Текст обработки таблицы сообщений» поместить программный текст самой обработки. В тексте обработки к таблице можно обращаться по ее имени «ТаблицаСообщений».
Например, разработчику может понадобиться свернуть таблицу по определенным измерениям (что и предложит система изначально), поскольку вывод очень уж подробной информации по всем полученным строкам результата контроля в конкретном случае может быть нецелесообразен:
Далее, по каждой строке таблицы сообщений формируется, записывается в таблицу и отображается пользователю само сообщение.
Формируется оно на основании шаблона, находящегося в поле «Текст сообщения». В шаблоне вычисляются участки кода на встроенном языке 1С в квадратных скобках. При этом доступны переменные:
- «СтрокаТаблицыСообщений» - собственно строка, в колонках которой есть все необходимые данные – значения измерений, ресурсов и формул правила
- «Источник» - объект документа
- «ПравилоКонтроля» - ссылка на элемент справочника правил ККО
Подсистема и расширение тестировались на платформах 8.3.14.1779 и 8.3.17.1386 на конфигурациях УТ 10.3 (модифицированной) и ERP 2.4.12.64 соответственно.
Предположу, что подсистема будет работать даже на платформе 8.2, поскольку я старался не использовать относительно новые функции типа СтрРазделить().
Но для этого вам придется перетаскивать объекты подсистемы в свою конфигурацию копированием, поскольку файл Комплексный контроль остатков.cf сохранен в версии платформы 8.3.14.
Что касается расширения, то его использование возможно только начиная с версии платформы 8.3.17. В разработке задействованы подписки на события, использование которых в расширении возможно только начиная с этой версии.
Кроме того, в расширении придется установить те же режимы совместимости, что и в вашей основной конфигурации, а также при сохранении в конфигурацию БД указать соответствие справочника «Пользователи» и роли «ПолныеПрава», использующимся в расширении, объектам вашей конфигурации.
Также нужно снять безопасный режим применения расширения, поскольку в расширениях нельзя использовать привилегированные модули и я использую установку привилегированного режима в ключевых местах. Без этого пришлось бы раздавать права вашим пользователям на объекты расширения.
В расширении в регистре-логе ресурс «Документ» представлен строкой из-за ограничений составных типов в расширении. У вас не получиться «провалиться» в документ из записи лога в отличие от варианта использования полноценной подсистемы в основной конфигурации. Но это вместе с ограничением по версии платформы, пожалуй, и все проблемы использования расширения.
Если в вашей конфигурации отсутствует справочник «Пользователи» или роль «ПолныеПрава», то вам придется сделать собственные модификации в моей разработке. Но такое сейчас большая редкость.
При дополнении (сравнении/объединении из файла) своей основной конфигурации подсистемой ККО не забудьте изначально снять флажки со всех объектов, а затем отметить объекты по подсистеме «Комплексный контроль остатков» файла, чтобы не затереть свои справочник пользователей и роль полных прав.
Так как работа ККО основана на использовании подписок на события документов, то есть пара нюансов, о которых не могу не упомянуть.
Разработчики платформы не обозначают четко последовательность выполнения подписок на события, а как они будут теперь применяться совместно с расширением – так вообще покрыто тайной.
По этому поводу есть публикации и комментарии, но четкого ответа они не предоставляют тоже.
Для правильной работы ККО важно, чтобы подписки «кко_ОбработкаПроведенияДокумента» и «кко_ОбработкаУдаленияПроведенияДокумента» на соответствующие события вызывались после всех событий (включая другие подписки в основной конфигурации или расширениях), которые так или иначе могут влиять на формируемые или удаляемые движения документов.
Поэтому я рекомендую, в соответствии со своими соображениями и мнением некоторых коллег по этой теме, при использовании расширения располагать его в списке расширений вашей конфигурации ниже всех остальных.
При использовании подсистемы в составе вашей основной конфигурации – расположить указанные подписки на события ниже всех остальных подписок вашей конфигурации.
Есть еще один момент, касающийся проведения или отмены проведения документов. ККО выполняется в рамках транзакции записи документа. Если некоторые движения документа формируются с помощью какого-нибудь «отложенного проведения» неким регламентом или каким-то сторонним механизмом, то изменения таких движений ККО проконтролировать не сможет.
Не сможет контролировать ККО и движения документа, который регистры двигает, но событий проведения и отмены проведения не вызывает (проведение запрещено на уровне метаданных документа). Обычно, такую особенность имеют специализированные документы типа «ПереносДанных» или «КорректировкаЗаписейРегистров».
К ограничениям, наверное, можно еще отнести и возможность редактировать схему СКД в правиле ККО только в толстом клиенте.
В целях оптимизации времени получения правил ККО «работает» модуль с повторным использованием. Соответственно для гарантированного применения только что измененных правил ККО, вам придется попросить пользователей зайти в базу заново.
К особенностям можно отнести тот факт, что настраивать, отлаживать и запускать в работу правила ККО должен разработчик очень хорошо знакомый с конкретной конфигурацией вообще и особенностями работы регистров и документов в ней, в частности.
Тут вам придет на помощь логирование событий ККО. Можно настроить некие «стартовые» правила, запустить их в работу в боевой базе «скрытно», не блокируя действия пользователей и не выдавая им диагностических сообщений. И, в итоге, набрать достаточно информации, позволяющей скорректировать правила и определиться со стратегией их использования.
«Штатный» запрос ККО не учитывает влияние движений проверяемого документа на проверяемый результат. То есть, если до ввода в работу правила на складе уже был отрицательный остаток по номенклатуре, то перепроведение существующих документов или проведение новых (даже приходных) с этой номенклатурой может вызвать блокировку действий пользователя.
Чтобы этого избежать перед началом работы правил ККО в боевой базе рекомендуется проверить состояние остатков на потенциальные конфликтные ситуации. Ну, или модифицировать «штатный» запрос ККО, дабы он учитывал влияние документа. Сделать это несложно, все необходимые таблицы находятся в распоряжении разработчика правил.
Приведу еще один вариант использования ККО (упоминал о нем выше).
В той самой УТ 10.3 у клиента есть правило ККО, которое «контролирует» партионный учет, но не блокирует действия пользователя и не выдает ему никаких сообщений. Оно нужно для работы одного регламентного задания, которое «имитирует» восстановление последовательности документов для «правильного» списания партий.
Дело в том, что граница последовательности партионного учета в этой базе зависла где-то в 2014 году и пара попыток «нахрапом» поднять ее к текущей дате не увенчались успехом из-за явных проблем в ведении учета в этих самых «лохматых» годах. Было принято стратегическое решение оставить пока ее там, дабы со временем попробовать разобраться в произошедшем и попытаться посчитать, какие несоответствия и перекосы в итоге претерпел учет себестоимости в организации.
А пока я вывел корректировками товарно-складские регистры в некую «норму» (это тема отдельной статьи, если будет ваш интерес и время для этого) и настроил правила ККО. В том числе и то, про которое веду рассказ. Его задача снабжать данными регламент, который перепроводит документы в незакрытом для редактирования периоде для «приемлемого» варианта списания партий в себестоимость.
В организации очень практикуется, к сожалению, работа в базе «задним» числом (пусть и не очень глубоко), что для правильного списания партий совсем не полезно.
Можно и более правильно, конечно, просто перепроводить последовательно все документы, затрагивающие партионный учет, но было опасение, что на это не хватит технологического окна. Поэтому родилось такое решение.
В начале работы регламентного задания запросом к таблице остатков партий выбираются «кривые» партии – с отрицательным количеством или стоимостью и «зависшей» стоимостью на складе (без количества).
Далее следует запрос, выбирающий в доступном периоде все документы, двигавшие наборы измерений (склад+номенклатура+серия номенклатуры) с указанными «проблемами». Выстраиваем документы по дате и начинаем «веерное» проведение и дополнение последовательности.
ККО хранит все свои данные в структуре ДополнительныеСвойства объекта документа по ключу «кко_ДанныеКонтроля». Именно там регламент после проведения очередного объекта ищет информацию о том, какие еще наборы измерений партионного учета изменил только что перепроведенный документ. И дополняет документами, имеющими движения по этим наборам, обрабатываемую последовательность документов.
Таким образом, количество обрабатываемых регламентом документов сокращается иногда на порядки относительно количества всех документов, которые пришлось бы проводить.
Естественно, это тот еще «костыль» и такого же результата, как штатное восстановление последовательности здесь не добиться никак. Но это компромисс, на который пошло в том числе и руководство компании.
Чистого FIFO по партиям не добиться, но выпадающих из себестоимости сумм или «пересписаний» больше нет, это факт! И период обработки документов в рамках технологического окна более чем приемлем.
Заключение
Итак, комплексный контроль остатков (ККО), представленный в публикации, призван помочь тем, кто не удовлетворен имеющимися у них инструментами контроля остатков в регистрах накопления.
Я предположу, что основное применение ККО найдет в товарно-складских и производственных регистрах.
Но это не значит, что это предел возможностей. Можно, например, попробовать настроить с помощью ККО контроль за договорными обязательствами контрагентов. Думаю, что с помощью СКД это будет сделать несложно.
Если изучить работу ККО поглубже и подумать «коллективно», то наверняка сообщество предложит еще несколько вариантов использования. Буду их, как и конструктивной критики, с нетерпением ждать в комментариях.
Архив содержит и подсистему в виде cf-файла, и расширение в виде cfe-файла.
Естественно, это не первая разработка на подобную тему. Она (тема) волнует и вдохновляет разработчиков на подвиги уже не первый десяток лет применительно только к 1С. Про другие системы говорить не стану…
Не могу не упомянуть похожие разработки, возникающие периодически на Инфостарте. Я их, конечно же, изучал, но в итоге ни одну из них не использовал, а изобрел свой велосипед. Который, как мне кажется, проехал немножко дальше…
Еще я хотел бы поблагодарить сообщество Инфостарта за предоставленные им в своих публикациях и комментариях к ним идеи и разработки, которые я активно использовал в этой публикации.
Список материалов, использованных при разработке концепции и функционала публикации (те, что вспомнил):
- Лучшие методы сравнения таблиц значений. Автор ildarovich
- Пример универсальной функции для создания схемы компоновки данных. Автор dbachinsky
- Динамический вывод таблицы значений на форму. Автор Vlad1917
- Таблицы на управляемых формах: создание, расширение, управление. Автор starik-2005
- Конфигурация Flowcon. Коммерческая публикация, хотя автор всем давно известен ?
- Контроль отрицательных остатков в конфигурациях: УТ 11.4, КА 2.4, ЕРП 2.4. Автор ids79
- Контроль отрицательных остатков [Расширение]. Автор 33lab
- Подсистема "Контроль отрицательных остатков". Автор 33lab
- Механизм контроля отрицательных остатков по регистрам накопления. Коммерческая публикация.