Thursday, June 15, 2006

Асинхронная работа с регистром остатков 1С: полезные алгоритмы

Асинхронная работа с регистром остатков 1С: полезные алгоритмы

Асинхронные события и их обработчики (аналог в системе Windows - очередь оконных сообщений) позволяют исключительно просто реализовать полезные алгоритмы: контроль отрицательных остатков, восстановление последовательностей, история сохранения документа, автоматическое обновление формы отчета при закрытии документа.
Автор статьи: romix | Редакторы: Волшебник
Последняя редакция №3 от 16.02.06 | История
URL: http://kb.mista.ru/article.php?id=68


Ключевые слова: ОбработкаВнешнегоСобытия, восстановление последовательности, проведение документов, отрицательные остатки


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

Как правило, пользователи 1С:Предприятие 7.7 хотят
  • Контролировать остаток товара на складе (или остаток чего-либо в другой предметной области), как минимум, выдавая сообщение при отрицательных остатках.

  • Видеть историю документа (когда, кто и что сохранял)
  • Не иметь особенных трудностей, когда нарушена последовательность документов (многие пользователи вообще с трудом понимают, что это такое)

  • Сохраняя документ, открытый из отчета, видеть заново сформированную форму отчета (например, отчета по остаткам).
  • И, разумеется, видеть остатки в справочнике номенклатуры.



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

В качестве теста я использую простую конфигурацию для учета товаров на складе, где есть приходная и расходная накладные, регистр остатков и отчет по остаткам. Речь, разумеется, может идти не только о товарах и складах. Есть множество других предметных областей, где действует этот же механизм, и применим регистр остатков (в терминологии 1С:Предприятие 8.0 – регистр накопления).

Чтобы было понятнее, о чем идет речь, откройте тестовую конфигурацию для 1С:Предприятие 7.7, ссылка на которую приведена в конце этой статьи, и проделайте следующие опыты:

1) В документе приходной накладной №1 от 09.06.2005 измените стоимость товара «Ветчина "Любительская", нарезка 360 гр.» на несколько рублей или копеек. Проведите документ. Теперь загляните в справочник «Контроль последовательности» - в нем появились ссылки на все документы, содержащие эту ветчину, которые были проведены после измененного документа. Запустите обработку «Восстановление последовательности» - она перепроведет все «некошерные» документы с ветчиной и очистит этот справочник. Я уже описывал подобный режим имитации последовательностей, хотя сильно сомневаюсь, что кто-то понял, о чем тогда шла речь – здесь приведена более простая и быстродействующая реализация, которая не «нагружает» модуль проведения, а реализует контроль движений «до» и «после» с использованием событий.

2) Откройте документ приходной накладной и нажмите на кнопку История. Обработка для ведения истории документа универсальна для документов любого вида, и фиксирует, в данном исполнении, только конечное (после завершения или отката всех транзакций) состояние документа. Сведения хранятся вне базы данных, во внешних файлах, т.к. они нужны, как и файл журнала регистрации mlg, главным образом, для успокоения пользователей, и придания им уверенности в своих действиях. Вы можете использовать этот же трюк не только для показа истории документа, но и в других областях применения, где нужно фиксировать конечное состояние объектов ИБ (по сокращению, которое я здесь применил, вы можете догадаться, какие именно области применения я имею в виду).

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

4) Откройте справочник Номенклатура и посмотрите значения в колонке «Остаток». Эта колонка не обновляется из регистра, но, некоторым образом, содержит реальный остаток товара. Поэтому, в отличие от традиционной реализации этого пользовательского пожелания, когда для отображения остатков используется регистр, вы не заметите в справочнике «тормозов». Установите галочку «Имеющиеся». Вы увидите только те товары, по которым есть ненулевой остаток (и которые не помечены на удаление). Снимите эту галочку – вы опять увидите все товары. Даже если вы заблокируете (откроете на редактирование) карточку товара, то остаток по этому товару будет корректно обновлен после закрытия карточки. Про трюк с остатками в справочнике я уже рассказывал в другой статье – здесь же приведена его более универсальная и быстродействующая реализация.

5) Откройте отчет «Остатки товара». Дважды щелкните мышью по документу в отчете, например, «Расходная накладная 1». Измените количество товара (например, с 5 на 7) и проведите документ. Убедитесь, что отчет корректно обновился, и теперь показывает новые цифры. Вы не обновляли отчет, но он обновился сам после записи открытого из него документа – как такое могло быть?

Вы очень удивитесь, когда узнаете, сколько строк кода занимает реализация всех этих механизмов.

Обработки:

ДвиженияДокументаДоПроведения – 43 строки
ДвиженияДокументаПослеПроведения – 38 строк
КонтрольОтрицательногоОстатка – 47 строк
КонтрольПоследовательности – 62 строки
ИзменитьОстаткиСправочникаТоваров – 33 строки
История_Записать – 93 строки (универсальный для документов любого вида)
История_Просмотр – 45 строк (универсальный для документов любого вида)

Это полный код, включая пустые строчки, избыточный код, добавленный для ясности, и все комментарии.

Глобальный модуль - 123 строки (включая весь код)

Модули проведения документов не содержат ничего, что относилось бы к указанным функциям, а модули формы наших документов (приходной и расходной накладных) содержат дополнительные 4 строки вызова обработки в процедуре ПриЗаписи():

Если ПустоеЗначение(ТекущийДокумент())=1 Тогда
Записать();
КонецЕсли;
ОткрытьФормуМодально("Обработка.ДвиженияДокументаДоПроведения", ТекущийДокумент());


Наверное, можно было бы сократить код вызова до 1 строки, передавая контекст, но для ясности я делаю вызов в 4 строки.

Код вышеуказанных обработок универсален для всех документов, но он «заточен» под определенный регистр остатков. В данном примере, регистр остатков содержит единственное измерение «Товар» и ресурсы «Количество» и «Сумма». Если вы увеличите сложность регистра, то увеличится и объем кода, но не намного (пожалуй, добавятся по 1-2 строки кода на каждое измерение или ресурс).

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

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

///////////////////////////////////////////////////////////////////////
//Предопределенная процедура
Процедура ОбработкаВнешнегоСобытия(прм_Источник,прм_Событие,прм_Данные)
//...
КонецПроцедуры


Чтобы сгенерировать событие, я использую внешнюю компоненту, которая поддерживает вызов наподобие:

fakir.ВызватьСобытие("fakir", "ИзменениеДокумента",  ЗначениеВСтрокуВнутр(док));


Генерация событий является штатным механизмом, описанным в «Технологии создания внешних компонент» для 1С:Предприятия, и поддерживается как в версии 7.7, так и в версии 8.0. Исходный код внешней компоненты на языке Delphi приложен в архиве конфигурации. Для первого запуска конфигурации в системе Windows необходимы права администратора или привилегированного пользователя.

Я использую свойство асинхронности внешних событий – их можно вызвать в любой момент времени, но сработают они после завершения работы программного кода 1С. Так, я могу сгенерировать событие в процедуре ПриЗаписи(), а сработает оно только после «устаканивания» всех транзакций, когда реальные (т.е. строго после проведения или отмены проведения документа) остатки уже можно читать из регистра. Сравнивая состояния движений регистра по документу «до» и «после», я выполняю различные полезные действия.



Конфигурация для скачивания:
http://x-romix.narod.ru/Fakir3.rar
(217 КБ, скачивать левой кнопкой мыши)

1 comment:

Unknown said...

The King Casino | Ventureberg
Discover 토토 사이트 홍보 the rise and fall of the king casino, one of the gri-go.com world's largest wooricasinos.info ventureberg.com/ The Casino is operated by the King Casino Group. You can herzamanindir.com/