Новая методика контроля отрицательных остатков при проведении документов в системе 1С:Предприятие 8.2
(бесплатная статья по Программированию в 1С)

Другие статьи программированию:

«Методика оперативного проведения и управляемые блокировки»

«Улучшения в конфигураторе платформы «1С:Предприятие 8.3»»

«Использование отладчика в системе «1С:Предприятие 8»»

Для тех, кто готовится к Аттестации на 1С:Специалист по Платформе

Публикуем статью автора и ведущего курса по подготовке к Аттестации на 1С:Специалист по Платформе Павла Чистова

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

Новая методика контроля отрицательных остатков при проведении документов

Вводная ситуация

Имеем конфигурацию с одним регистром накопления «ОстаткиТоваров», регистр имеет 2 измерения: «Номенклатура» и «Склад» и один ресурс «Количество».

По регистру движения формируют 2 документа: «Приходная» и «Расходная». Справочники, реквизиты документов и типы данных надеюсь очевидны.

Про «Приходную» писать нечего, там просто формируются в «плюс» остатки. Про «Расходную поговорим подробнее. Для начала вспомним, как формировалась процедура проведения в 8.1.

Для начала мы получали запросом данные табличной части документа, группировали ее, чтобы исключить дубли строк, и соединяли с таблицей остатков регистра:


Запрос = Новый Запрос;
Запрос.Текст = «ВЫБРАТЬ
| РасходнаяТовары.Номенклатура,
| СУММА(РасходнаяТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары КАК РасходнаяТовары
|ГДЕ
| РасходнаяТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РасходнаяТовары.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТЧ.Номенклатура,
| ДокТЧ.Количество,
| ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток,0) КАК Остаток
|ИЗ
| ДокТЧ КАК ДокТЧ
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
| ,
| Склад = &Склад
| И Номенклатура В
| (ВЫБРАТЬ
| ДокТЧ.Номенклатура
| ИЗ
| ДокТЧ КАК ДокТЧ)) КАК ОстаткиТоваровОстатки
| ПО ДокТЧ.Номенклатура = ОстаткиТоваровОстатки.Номенклатура»;

Запрос.УстановитьПараметр(«Склад», Склад);
Запрос.УстановитьПараметр(«Ссылка», Ссылка);
РезультатЗапроса = Запрос.Выполнить();

Кроме этого данные табличной части документа мы использовали для дополнительного отбора при расчете виртуальной таблицы.

Обратите также внимание на функцию ЕСТЬNULL, которую мы использовали для гарантии избавления от типа значения NULL в результате запроса. Остатки, которых на складе нет, не присоединятся в таблице документа, и мы поля с остатком заполним значением 0 (ноль).

После того как данные запросом были получены нам оставалось проверить остатки и сформировать движения по регистру. Причем в нашем случае никто не мешает сделать это за один проход.

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

Если Не Отказ Тогда
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = Выборка.Количество;
КонецЕсли;
КонецЦикла;

Вроде бы, куда уж проще и быстрее? Однако есть куда!

Разберем новую методику контроля остатоков.

Для начала получим сгруппированную табличную часть документа.

Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст = «ВЫБРАТЬ
| РасходнаяТовары.Номенклатура,
| СУММА(РасходнаяТовары.Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
| Документ.Расходная.Товары КАК РасходнаяТовары
|ГДЕ
| РасходнаяТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РасходнаяТовары.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ДокТЧ.Номенклатура,
| ДокТЧ.Количество
|ИЗ
| ДокТЧ КАК ДокТЧ»;

Запрос.УстановитьПараметр(«Ссылка», Ссылка);
РезультатЗапроса = Запрос.Выполнить();

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

Далее сформируем движения по регистру.

Движения.ОстаткиТоваров.Записывать = Истина;
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Движение = Движения.ОстаткиТоваров.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Номенклатура = Выборка.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = Выборка.Количество;
КонецЦикла;
Движения.Записать();

В приведенном примере я подразумеваю, что для документа установлен режим записи движений «Записывать выбранные». Именно поэтому я перед циклом установил пометку необходимости записи движений (на самом деле это можно было сделать и после цикла).

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

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

После того как я записал движения в регистр я получу остатки. Обратите внимание, что при чтении данных из регистра у меня сейчас будут обновленные данные с учетом движений самого документа.

Запрос.Текст = «ВЫБРАТЬ
| Номенклатура,
| КоличествоОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(
| ,
| Склад = &Склад
| И Номенклатура В
| (ВЫБРАТЬ
| ДокТЧ.Номенклатура
| ИЗ
| ДокТЧ КАК ДокТЧ))
|ГДЕ
| КоличествоОстаток < 0";

Запрос.УстановитьПараметр(«Склад», Склад);
РезультатЗапроса = Запрос.Выполнить();

Посмотрите, мы избавились от соединений, и, что не маловажно, от проверки типа значения NULL. Запрос получит данные только по отрицательным остаткам и покажет их пользователю!
Обратимся к результату запроса и известим пользователя о минусах на складе.

Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Не хватает товара » + Выборка.Номенклатура + «, после проведения документа остаток составит » + Выборка.Остаток;
Сообщение.Сообщить();
Отказ = Истина;
КонецЦикла;

Вот, собственно, и вся новая методика контроля остатков. Перечислим плюсы этого метода:

  • Нет необходимости соединять в запросе таблицу документа и данными регистров.
  • Не надо производить проверку на NULL.
  • Нет необходимости получать излишние данные (остатки) для проведения документа. Ведь мы чаще все же записываем документ с правильными цифрами, и он проводится, чем документы которые уводят остатки в минус.

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

Вот тут Вы можете скачать демобазу с разобранным примером.

PDF-версия статьи для участников группы ВКонтакте

Мы ведем группу ВКонтакте — http://vk.com/kursypo1c.

Если Вы еще не вступили в группу — сделайте это сейчас и в блоке ниже (на этой странице) появятся ссылка на скачивание материалов.

[sociallocker id=»136011″]
Статья по программированию - в PDF-формате

Статья в PDF-формате

Вы можете скачать эту статью в формате PDF по следующей ссылке: Курсы-по-1С — Новая методика контроля отрицательных остатков при проведении документов в системе 1СПредприятие 8.2.pdf

[/sociallocker]
Если Вы уже участник группы — нужно просто повторно авторизоваться в ВКонтакте, чтобы скрипт Вас узнал. В случае проблем решение стандартное: очистить кеш браузера или подписаться через другой браузер.

Комментарии / обсуждение (14):

  1. Сергей

    Почему в запросе период не указываем? если перепроводить неоперативно, то получим совсем другие остатки…
    И второй вопрос: в первом случае если есть отрицательные остатки, то мы движения не записываем, а во втором случае мы движения записываем, а потом откатываем, если есть отрицательные остатки. не будет ли это наоборот медленнее?

    • Евгений Гилев (Мастер-тренер)

      Добрый день, Сергей!

      1) По поводу периода в запросе — в ближайшее время мы опубликуем расширенную статью на эту тему. В ней момент с периодом исправлен.
      2) Учтите, что в старой методе перед запросом всегда выполняется запись в регистр — чтобы очистить «старые» движения документа.
      Поэтому, если остатка недостаточно, то в старой методике — выполняется запись в регистр, далее запрос к БД, далее поиск отрицательных остатков, далее откат транзакции.

      В новой статье этот момент будет разобран.

  2. Павел Невасилевский (Paul_Nevada)

    Добрый день!

    Ошибка в процедуре _Старая_методика___ОбработкаПроведения:
    Если Выборка.Количество < Выборка.Остаток Тогда
    Направление знака операции сравнения…

    PS: Огромное спасибо за статью и прилагающуюся демо-базу!

  3. Серхио

    Добрый день!

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

    • GROOVY

      Я теоретик. За практикой обратитесь к экспертам по технической части.
      В теории все очень красиво.

      • Серхио

        Не в обиду Вам, Павел, но зачем нужна теория оторванная от жизни? Ведь все эти штуки и нужны для ускорения быстродействия, уменьшения нагрузки на железо и прочих, чисто практических жизненных вещей. Это, собственно, как мне кажется, самый первый вопрос — как это влияет на производительность? Если положительно, то нобелевская, если отрицательно, то тогда это всё бессмысленная трата времени.

        Не хочу, чтобы Вы восприняли это как оскорбление — Ваш вклад в обучение по 1С неоценим, я с увлечением читаю все Ваши статьи.

        • GROOVY

          Эта технология присутствует в последних типовых, в том числе в УТ 11. Как это на что влияет, я вроде рассказал. В любом случае, спросите у 1С как они борются с блокировками.

  4. Vid1

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

  5. nodalt

    Трудно переоценить вклад Павла в развитие специалистов 1С и материал очень интересный. Однако, «новой» методику сложно назвать. Этот прием известен уже на протяжении нескольких лет (от Павла конечно же) и уже давно Спеца сдают с применением этой методики.
    Это не пустой флуд — просто увидев заголовок подумал, что изобрели что-то новое, типа — куда уж проще и оптимальнее, чем было …

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

 Ознакомлен с условиями Публичной оферты и Пользовательского соглашения
 Согласен на обработку персональных данных (Политика обработки ПДн)