Другие статьи программированию:
«Методика оперативного проведения и управляемые блокировки»
«Улучшения в конфигураторе платформы «1С:Предприятие 8.3»»
«Использование отладчика в системе «1С:Предприятие 8»»
Для тех, кто готовится к Аттестации на 1С:Специалист по ПлатформеПубликуем статью автора и ведущего курса по подготовке к Аттестации на 1С:Специалист по Платформе — Павла Чистова
Изначально статья была опубликована в личном блоге Павла, но, как нам кажется, будет интересна всем программистам 1С.
Новая методика контроля отрицательных остатков при проведении документов
Вводная ситуация
Имеем конфигурацию с одним регистром накопления «ОстаткиТоваров», регистр имеет 2 измерения: «Номенклатура» и «Склад» и один ресурс «Количество».
По регистру движения формируют 2 документа: «Приходная» и «Расходная». Справочники, реквизиты документов и типы данных надеюсь очевидны.
Про «Приходную» писать нечего, там просто формируются в «плюс» остатки. Про «Расходную поговорим подробнее. Для начала вспомним, как формировалась процедура проведения в 8.1.
Для начала мы получали запросом данные табличной части документа, группировали ее, чтобы исключить дубли строк, и соединяли с таблицей остатков регистра:
Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
| РасходнаяТовары.Номенклатура,
| СУММА(РасходнаяТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары КАК РасходнаяТовары
|ГДЕ
| РасходнаяТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РасходнаяТовары.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТЧ.Номенклатура,
| ДокТЧ.Количество,
| ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток,0) КАК Остаток
|ИЗ
| ДокТЧ КАК ДокТЧ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
| ,
| Склад = &Склад
| И Номенклатура В
| (ВЫБРАТЬ
| ДокТЧ.Номенклатура
| ИЗ
| ДокТЧ КАК ДокТЧ)) КАК ОстаткиТоваровОстатки
| ПО ДокТЧ.Номенклатура = ОстаткиТоваровОстатки.Номенклатура»;
Запрос.УстановитьПараметр(«Склад», Склад);
Запрос.УстановитьПараметр(«Ссылка», Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Кроме этого данные табличной части документа мы использовали для дополнительного отбора при расчете виртуальной таблицы.
Обратите также внимание на функцию ЕСТЬNULL, которую мы использовали для гарантии избавления от типа значения NULL в результате запроса. Остатки, которых на складе нет, не присоединятся в таблице документа, и мы поля с остатком заполним значением 0 (ноль).
После того как данные запросом были получены нам оставалось проверить остатки и сформировать движения по регистру. Причем в нашем случае никто не мешает сделать это за один проход.
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.Количество < Выборка.Остаток Тогда
Сообщить("Не хватает товара " + Выборка.Номенклатура + ", из необходимых " + Выборка.Количество + " в наличие имеется только " + Выборка.Остаток;
Отказ = Истина;
КонецЕсли;
Если Не Отказ Тогда
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = Выборка.Количество;
КонецЕсли;
КонецЦикла;
Вроде бы, куда уж проще и быстрее? Однако есть куда!
Разберем новую методику контроля остатоков.
Для начала получим сгруппированную табличную часть документа.
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = «ВЫБРАТЬ
| РасходнаяТовары.Номенклатура,
| СУММА(РасходнаяТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары КАК РасходнаяТовары
|ГДЕ
| РасходнаяТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РасходнаяТовары.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТЧ.Номенклатура,
| ДокТЧ.Количество
|ИЗ
| ДокТЧ КАК ДокТЧ»;
Запрос.УстановитьПараметр(«Ссылка», Ссылка);
РезультатЗапроса = Запрос.Выполнить();
Временная таблица ДокТЧ нам еще пригодится в дальнейшем, для ее использования мы подключили к запросу менеджер временных таблиц.
Далее сформируем движения по регистру.
Движения.ОстаткиТоваров.Записывать = Истина;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = Выборка.Количество;
КонецЦикла;
Движения.Записать();
В приведенном примере я подразумеваю, что для документа установлен режим записи движений «Записывать выбранные». Именно поэтому я перед циклом установил пометку необходимости записи движений (на самом деле это можно было сделать и после цикла).
Движения записываем в регистр. Причем при записи движений я обращаюсь не к конкретному набору записей (Движения.ОстаткиТоваров.Записать()), а ко всей коллекции «Движения».
Подобный вызов записи гарантирует запись данных в регистры в той последовательности, в которой они расположены на дереве метаданных, что в свою очередь резко уменьшает взаимные блокировки и как следствие ошибки DeadLock.
После того как я записал движения в регистр я получу остатки. Обратите внимание, что при чтении данных из регистра у меня сейчас будут обновленные данные с учетом движений самого документа.
Запрос.Текст = «ВЫБРАТЬ
| Номенклатура,
| КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(
| ,
| Склад = &Склад
| И Номенклатура В
| (ВЫБРАТЬ
| ДокТЧ.Номенклатура
| ИЗ
| ДокТЧ КАК ДокТЧ))
|ГДЕ
| КоличествоОстаток < 0";
Запрос.УстановитьПараметр(«Склад», Склад);
РезультатЗапроса = Запрос.Выполнить();
Посмотрите, мы избавились от соединений, и, что не маловажно, от проверки типа значения NULL. Запрос получит данные только по отрицательным остаткам и покажет их пользователю!
Обратимся к результату запроса и известим пользователя о минусах на складе.
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Не хватает товара » + Выборка.Номенклатура + «, после проведения документа остаток составит » + Выборка.Остаток;
Сообщение.Сообщить();
Отказ = Истина;
КонецЦикла;
Вот, собственно, и вся новая методика контроля остатков. Перечислим плюсы этого метода:
- Нет необходимости соединять в запросе таблицу документа и данными регистров.
- Не надо производить проверку на NULL.
- Нет необходимости получать излишние данные (остатки) для проведения документа. Ведь мы чаще все же записываем документ с правильными цифрами, и он проводится, чем документы которые уводят остатки в минус.
Однако не стоит думать, что такая технология может быть применена повсеместно. На секунду задумайтесь, что в этой задаче необходимо еще и себестоимость рассчитать при списании, и Вы придете к выводу, что необходим «старый» метод контроля остатков.
Вот тут Вы можете скачать демобазу с разобранным примером.
автор и тренер курса по подготовке к Аттестации по Платформе 1С 8.2 / 8.3
PDF-версия статьи для участников группы ВКонтакте
Мы ведем группу ВКонтакте — http://vk.com/kursypo1c.
Если Вы еще не вступили в группу — сделайте это сейчас и в блоке ниже (на этой странице) появятся ссылка на скачивание материалов.
[sociallocker id=»136011″]Полезные ссылки:
Все статьи по 1С
Статьи по программированию
Бесплатные материалы

Почему в запросе период не указываем? если перепроводить неоперативно, то получим совсем другие остатки…
И второй вопрос: в первом случае если есть отрицательные остатки, то мы движения не записываем, а во втором случае мы движения записываем, а потом откатываем, если есть отрицательные остатки. не будет ли это наоборот медленнее?
Добрый день, Сергей!
1) По поводу периода в запросе — в ближайшее время мы опубликуем расширенную статью на эту тему. В ней момент с периодом исправлен.
2) Учтите, что в старой методе перед запросом всегда выполняется запись в регистр — чтобы очистить «старые» движения документа.
Поэтому, если остатка недостаточно, то в старой методике — выполняется запись в регистр, далее запрос к БД, далее поиск отрицательных остатков, далее откат транзакции.
В новой статье этот момент будет разобран.
Добрый день!
Ошибка в процедуре _Старая_методика___ОбработкаПроведения:
Если Выборка.Количество < Выборка.Остаток Тогда
Направление знака операции сравнения…
PS: Огромное спасибо за статью и прилагающуюся демо-базу!
Это спец тест, для самых наблюдательных ;)
Добрый день!
Скажите, пожалуйста, отойдя от теоретической части — есть ли реальный выигрыш в производительности для такого решения? В старом способе мы одним запросом выбрали все данные, а тут мы делаем два запроса, т.е. два обращения на сервер — не будет ли это влиять на быстродействие? К тому же мы в старом решении могли обойтись вообще без временных таблиц с помощью вложенного запроса (да, вложенный запрос может работать неоптимально, но тут ему негде работать неоптимально, а временная таблица, насколько я слышал, записывается на диск, что тоже влияет на время работы).
Я теоретик. За практикой обратитесь к экспертам по технической части.
В теории все очень красиво.
Не в обиду Вам, Павел, но зачем нужна теория оторванная от жизни? Ведь все эти штуки и нужны для ускорения быстродействия, уменьшения нагрузки на железо и прочих, чисто практических жизненных вещей. Это, собственно, как мне кажется, самый первый вопрос — как это влияет на производительность? Если положительно, то нобелевская, если отрицательно, то тогда это всё бессмысленная трата времени.
Не хочу, чтобы Вы восприняли это как оскорбление — Ваш вклад в обучение по 1С неоценим, я с увлечением читаю все Ваши статьи.
Эта технология присутствует в последних типовых, в том числе в УТ 11. Как это на что влияет, я вроде рассказал. В любом случае, спросите у 1С как они борются с блокировками.
спасибо за инфу — тока http://курсы-по-1с.рф почему то у меня медленно грузится — что может быть не так?
Были проблемы с серверами, сейчас все в порядке.
Большая просьба, если добавляете куски кода 1С, то отформатируйте и разукрасьте его как это сама 1С, пожалуйста. Воспринимать код будет много удобнее. Бесплатных решений по html форматированию достаточно много, взять хотя бы Разукрашку
Добрый день! Спасибо, Ваша просьба зафиксирована.
Трудно переоценить вклад Павла в развитие специалистов 1С и материал очень интересный. Однако, «новой» методику сложно назвать. Этот прием известен уже на протяжении нескольких лет (от Павла конечно же) и уже давно Спеца сдают с применением этой методики.
Это не пустой флуд — просто увидев заголовок подумал, что изобрели что-то новое, типа — куда уж проще и оптимальнее, чем было …
Добрый день! Данная публикация прилагается в дополнение к статье «Методика оперативного проведения и управляемые блокировки в 1С:Предприятие 8.3″(http://курсы-по-1с.рф/post-2014-03/статья-платформа-блокировки/), которая содержит в себе отсылки к материалу данной статьи. Название было перенесено без изменений.