Что такое оперативное и неоперативное проведение в 1с
Что такое оперативное и неоперативное проведение в 1с
Этот вопрос задает себе каждый пользователь, который слышит эти слова.
Немного прописных истин:
Что такое вообще проведение документа? Это как подпись документа в реальной жизни. Документу придали силу. До подписи (проведения) — это просто бумажка, после — событие!
Оперативное проведение — это проведение документа текущим временем.
Неоперативное — это проведение документа ранее текущего времени. Даже в тот же день, тот же час, пусть на секунду раньше текущего времени — это уже неоперативно. Классический вариант — перепроведение документов прошедшей датой.
Позже текущего времени, или как говорят, «будущей датой», в 8-ке документ провести нельзя в принципе.
Опыт, накопленный годами:
Фирма 1C по пятнадцатилетнему опыту развития и поддержки 7-ки решила, что в 8-ке контроль остатков (товаров, взаиморасчетов и т.д.) будет проводиться только при оперативном проведении. В случает отсутствия остатков, документ не будет проведен. Внимание! А при неоперативном проведении документ будет проведен всегда! Последнее предложение надо перечитать несколько раз.
Как же так, спросите вы? А если товара нет, какие движения сформирует документ?! Такие, какие сможет.
Чтобы это понять (и принять), у меня ушло два месяца. А еще спустя полгода, я понял всю силу такого подхода. Это действительно хорошее решение!
Смысл в том, что контроль имеет смысл только при оперативной работе. А если задним числом что-то съехало — это результат работы задним числом. Кто ломал, тот пусть и делает.
В частности, в результате такого подхода меняется характер работы с базой. Теперь база перепроводится на ура, но в ней надо искать ошибки. Для этого существует серия обработок для проверки.
В заключение хочется отметить, что такая методика работы не связана с самой платформой 1С 8. В 8-ке можно было бы сохранить методику, заложенную в 7-ке. И в 7-ке можно было бы реализовать рассмотренную здесь методику. Поменялся именно подход к работе с базой.
Получается, что в 7-ке, где в одном отчете о продажах за день может быть 1000 позиций и не проводится только из-за одной, не проводится весь документ.
А в 8-ке, где в одном отчете о продажах за день может быть 1000 позиций, и ругается только по одной, ошибка только по этой позиции.
Подробнее о записи и проведении документов.
Оперативное и неоперативное проведение документов в 1С 8.3
Режим проведения документа
В первом случае файл проводится с учетом нынешнего времени, благодаря этому программа может контролировать многие торговые процессы, к примеру, списание товаров или их продажа. Данный режим стоит применять, если нужна информация на текущий момент, так как если провести операцию чуть позже, данные будут уже совсем другими. Новый документ автоматически будет работать в данном режиме.
Неоперативное проведение ведет работу с прошлым или будущим, не ведя учет остатков. Часто бывает, что пользователь создал документ, но еще не провел его. Именно для таких случаев и предназначен этот режим, он позволяет избежать контроля программы, но это может привести к некоторым ошибкам или неточности учета. Например, будут списаны товары, которых уже нет в наличии. Так что лучше доверить выбор режима проводки 1С, программа сама подберет нужный способ.
Значения свойства «Оперативное проведение» у документов: «Разрешить» и «Запретить»
Рассмотрим, какие действия нужно провести чтобы включить оперативную настройку в программе «1С: Бухгалтерия предприятия 3.0». В предыдущих версиях порядок будет идентичным.
Запускаем программу через режим «Конфигуратор», открываем конфигурацию. Далее, находим дерево метаданных, раздел «Документы» и открываем свойство любого файла.
Для того, чтобы проводка была совершенна немедленно, ставим параметр «Разрешить». Проводить документы таким способом можно в обоих режимах. Регистры не влияют на оперативный вариант. С установленным значением «Разрешить» проводка может осуществляться как в прошлом, так и нынешнем времени. В случае использования прошедшей даты документ будет проведен в неоперативном режиме.
Крайне не рекомендуется менять настройки установленные разработчиком, так как это может повлиять на процессы проведения документов и сбить алгоритмы программы. Не стоит изменять системное время и день проведения работы в 1С для того, чтобы поменять дату оперативного проведения. Это приведет к неправильным бухгалтерским расчетам, которые в дальнейшем вызовут вычислительные ошибки в учете.
Назначение и методика использования механизма оперативного проведения документов
Для ввода в систему информации о событиях, происходящих в жизни предприятия, таких, как отгрузка товара, приход денег на счет и т.д. в 1С:Предприятии используются документы. Для отражения событий в различных учетных механизмах (регистрах) существует механизм проведения документов. В процессе проведения документ записывает движения в различные регистры. Проведение может выполняться в оперативном и неоперативном режиме. Таким образом, оперативное проведение является частью механизма проведения документов.
Механизм оперативного проведения предназначен для того, чтобы разделить случаи, когда документ проводится в реальном времени, и случаи, когда проведение документа отражает уже свершившийся факт.
Проведение в реальном времени необходимо тогда, когда ввод и проведение документа не просто фиксируют в системе произошедшее событие, а участвуют в его формировании, помогая оператору правильно ввести информацию. Разумеется, это имеет смысл только в тот момент, когда данное событие происходит в реальной жизни.
Классическим примером является ввод и проведение документа, отражающего продажу товаров со склада. При вводе такого документа в задачу оператора входит не только правильный ввод списка товаров, которые приобретает покупатель, но и выполнение различных проверок. Прежде всего, необходимо проверить, что запрашиваемый товар имеется на указанном складе. При этом очень важно, чтобы проверка учитывала тот факт, что одновременно с этим оператором работают и другие операторы, которые могут одновременно выписывать те же самые товары. Соответственно задачей системы является не допустить продажу одного и того же товара двум покупателям. Кроме того, может потребоваться и проверка доступного покупателю размера кредита или наличие факта оплаты счета, а также другие самые разнообразные проверки.
Однако, если документ вводится задним числом, то есть в момент его ввода известно, что такое событие уже произошло в жизни предприятия, например, конкретный товар уже отгружен клиенту, необходимость в таких проверках отпадает и нужно просто отразить в учете произошедшее событие. В этом случае проведение документа только фиксирует событие, а не участвует в его формировании.
Таким образом, задача механизма оперативного проведения заключается в разделении этих двух вариантов проведения и с точки зрения пользователя, чтобы он понимал, какой вид проведения выполняется, и с точки зрения алгоритма проведения документа, чтобы тот отработал действия, соответствующие текущему варианту проведения.
Рассмотрим, как система обеспечивает поддержку данного механизма.
Саму возможность оперативного проведения нужно устанавливать в метаданных для конкретного вида документов (свойство «Оперативное проведение»). По умолчанию, возможность оперативного документа включена. Соответственно, для тех документов, для которых оперативное документа не имеет смысла, его следует в метаданных отключить. Тогда любое проведение документа будет считаться неоперативным.
Однако кроме передачи информации в обработчик при оперативном проведении выполняется также автоматическое изменение времени документа. Для этого используется поддерживаемый системой механизм оперативной отметки времени. Он позволяет при одновременной работе нескольких пользователей получать возрастающую последовательность значений типа Дата в пределах дня. Механизм оперативной отметки выдает текущее время или большее на одну секунду последней выданной какому-либо пользователю отметки, если последняя выданная отметка больше или равна текущему времени.
Оперативная отметка позволяет расставить документы в той хронологической последовательности, в которой реально происходили события в жизни предприятия. Это весьма полезно для того, чтобы порядок следования документов и их движений в информационной базе соответствовал реальной последовательности событий, а, следовательно, адекватно бы отражался в различных учетных задачах зависящих от последовательности движений, например, в задачах списания товаров по методам LIFO и FIFO. При записи документа с оперативным проведением система получает очередную оперативную отметку времени и присваивает ее свойству Дата документа. Соответственно, в процессе оперативного проведения документ перемещается в пределах дня на время, выданное механизмом оперативной отметки. Таким образом, все оперативно проводимые документы располагаются в пределах дня в порядке их проведения, то есть в том порядке, в котором происходили события в жизни предприятия.
При оперативном проведении документа система меняет время документа, однако не меняет день. Это объясняется тем, что дата документа (без времени) имеет, как правило, юридический смысл и должна вводиться пользователем в явном виде. Подробнее про работу механизма оперативной отметки времени можно прочитать в статье «Особенности использования системной даты компьютера при оперативном проведении документов».
Так как неоперативное проведение является более ответственной операцией, то система предоставляет разработчику возможность отдельно регулировать права пользователей на такой вид проведения. Для этого используется право «Интерактивное проведение неоперативное». Следует заметить, что это право действует только при использовании стандартных команд, предоставляемых расширениями форм. Если вызов проведения выполняется средствами встроенного языка, то данное право следует проверять в модулях самостоятельно.
В обработчике ОбработкаПроведения() разработчик, получая текущий режим проведения в качестве значения параметра, должен самостоятельно реализовать изменение алгоритма проведения в зависимости от значения данного параметра. При этом рекомендуется для оперативного проведения выполнять различные проверки, которые необходимы для определения правомерности совершаемой операции. Это может быть проверка наличия товаров на складе, проверка задолженности покупателя и т.д. В этих проверках следует обращаться к текущим остаткам регистров, а не получать итоги на момент времени документа. Система поддерживает текущие остатки в актуальном состоянии, поэтому обращение к текущим остаткам должно выполняться быстро и такое обращение должно обеспечивать высокую параллельность, так как транзакционные блокировки будут накладываться на записи (а точнее, диапазоны ключей) соответствующие запрашиваемым данным.
При неоперативном проведении не рекомендуется выполнять такого рода проверки. С одной стороны, расчет итогов на момент времени документа может занять продолжительное время, а с другой стороны такая проверка не имеет большого смысла. Например, проверяя наличие товаров на некоторый момент времени, мы можем проверить только правомерность выписки конкретного документа, но при этом изменятся условия проведения всех последующих документов и, соответственно, необходимо проверять все последующие документы, в которых отпускались данные товары.
Кроме того, если документ вводится по уже совершенной операции, то в системе отражается уже свершившийся факт, и даже если при этом получаются, например, отрицательные текущие остатки, то ошибка может быть совсем не в этом документе, а в любом другом. Таким, образом, речь уже не идет о проверке правомерности совершения операции и соответственно проверки, выполняемые при оперативном проведении делать не нужно.
В любом случае, необходимо понимать, что проверки которые будут выполняться при неоперативном проведении это не проверки правомерности совершения операции, а проверки правильности ввода документа и при анализе целесообразности включения таких проверок следует соотносить затраты времени на такие проверки и их эффективность. Проверки отдельных документов могут выявить только незначительное количество ошибок и требуют при этом достаточно больших затрат времени, что может существенно сказаться на производительности всей системы.
Для проверки правильности заполнения документов после изменения задним числом, если это необходимо, можно предусмотреть специальную регламентную обработку, которая будет проверять все документы за период и, соответственно, не будет замедлять текущую работу при вводе этих документов.
Наряду с вводом документов задним числом можно записывать документы и их движения будущим временем, то есть вводить информацию, о еще не произошедших событиях. Однако следует учитывать, что это нарушает логику работы механизма оперативного проведения, так как текущие остатки регистров при этом перестают отражать реальное состояние учета (складских остатков, задолженностей и т.д.) и в этом случае проверки текущих остатков при оперативном проведении не будут выдавать адекватной информации. Стандартные команды форм не разрешают пользователю проводить оперативно документы, введенные будущей датой, и не предлагают для них при автоматическом выборе режима проведения выполнить неоперативное проведение. Если выполняется попытка программно вызвать оперативное проведение документа будущей датой (относительно текущей даты или оперативной отметки времени), то выдается соответствующее сообщение.
Разумеется, накладываемые ограничения это только предлагаемая методология оперативного проведения. Существует возможность вызвать неоперативное проведение программно и предоставить пользователю возможность в форме самостоятельно выбрать режим неоперативного проведения. Однако рекомендуется, без особых оснований, не нарушать логику работы оперативного проведения и обеспечивать наличие движений в регистрах только по уже совершенным операциям (не допуская наличия движений по еще не совершенным операциям). Тогда текущие итоги регистров будут отражать реальное состояние учета, и это позволит при оперативном проведении получать адекватные результаты при проверке текущих итогов регистров.
Также не рекомендуется разрешать пользователям менять системную дату компьютера для изменения логики работы механизма оперативного проведения. Подробнее этот момент отражен в статье «Особенности использования системной даты компьютера при оперативном проведении документов».
Следует заметить, что, как и сам механизм проведения, оперативное проведение является только предлагаемой платформой методологией. Разработчик прикладного решения может использовать ее, или нет для каждого вида документов по своему усмотрению. Однако, использование стандартной методологии в прикладных решениях для тех задач, для которых она предназначена, позволяет, с одной стороны, решить задачу достаточно быстро, а с другой стороны, делает создаваемое решение понятным для любого разработчика, которому будет необходимо в нем разобраться.
Оперативное и неоперативное проведение документов в 1С 8.3
Режим проведения документа
В первом случае файл проводится с учетом нынешнего времени, благодаря этому программа может контролировать многие торговые процессы, к примеру, списание товаров или их продажа. Данный режим стоит применять, если нужна информация на текущий момент, так как если провести операцию чуть позже, данные будут уже совсем другими. Новый документ автоматически будет работать в данном режиме.
Неоперативное проведение ведет работу с прошлым или будущим, не ведя учет остатков. Часто бывает, что пользователь создал документ, но еще не провел его. Именно для таких случаев и предназначен этот режим, он позволяет избежать контроля программы, но это может привести к некоторым ошибкам или неточности учета. Например, будут списаны товары, которых уже нет в наличии. Так что лучше доверить выбор режима проводки 1С, программа сама подберет нужный способ.
Значения свойства «Оперативное проведение» у документов: «Разрешить» и «Запретить»
Рассмотрим, какие действия нужно провести чтобы включить оперативную настройку в программе «1С: Бухгалтерия предприятия 3.0». В предыдущих версиях порядок будет идентичным.
Запускаем программу через режим «Конфигуратор», открываем конфигурацию. Далее, находим дерево метаданных, раздел «Документы» и открываем свойство любого файла.
Для того, чтобы проводка была совершенна немедленно, ставим параметр «Разрешить». Проводить документы таким способом можно в обоих режимах. Регистры не влияют на оперативный вариант. С установленным значением «Разрешить» проводка может осуществляться как в прошлом, так и нынешнем времени. В случае использования прошедшей даты документ будет проведен в неоперативном режиме.
Крайне не рекомендуется менять настройки установленные разработчиком, так как это может повлиять на процессы проведения документов и сбить алгоритмы программы. Не стоит изменять системное время и день проведения работы в 1С для того, чтобы поменять дату оперативного проведения. Это приведет к неправильным бухгалтерским расчетам, которые в дальнейшем вызовут вычислительные ошибки в учете.
Методика оперативного проведения и управляемые блокировки в 1С:Предприятие 8.3 (обновление 2017 года)
Для внедренцев, которые работают с типовыми или собственными конфигурациями – и тех, кто готовится к Аттестации на 1С:Специалист по платформе.
В статье мы разберем:
Время на прочтение – 20 минут.
Итак, две методики контроля остатков в 1С:Предприятии 8.3
Давайте начнем с того, что обозначения “старая методика” и “новая методика” достаточно условны. В самом деле, если “новая методика” используется с 2010 года – она уже не очень новая 🙂
Однако, мы еще раз вынуждены на этом остановиться, потому что различать эти подходы нужно и это имеет критическое значение.
“Старая методика” – это подход к контролю остатков, который использовался со времен «1С:Предприятие 8.0».
C 2010 года, с развитием платформы и добавлением новых возможностей с «1С:Предприятие 8.2» – применяется “новая методика” (однако – не везде).
В чем разница?
Принципиальная разница – в моменте контроля остатков:
Детально преимущества и недостатки новой методики раскрыты в отдельной статье, поэтому ограничимся лишь общим тезисом – новая методика более оптимальна с точки зрения производительности и масштабируемости.
Ok, значит, старая методика ушла в прошлое и это удел УТ 10.3?
Нет, это не совсем так.
Новую методику можно использовать, когда при списании товаров все необходимые данные есть в документе и их не нужно вычислять.
Например, когда количество для списания известно из табличной части документа. Проблема возникает с себестоимостью, ведь её нужно рассчитать до записи в регистр, то есть выполнить запрос к базе данных.
Поэтому новая методика может успешно применяться в случае, если данные по количеству и себестоимости хранятся в отдельных регистрах.
Однако встречаются конфигурации, где и количество, и стоимость учитываются на одном регистре. И вот здесь-то обоснованно остается работать старая методика контроля остатков!
Вот пример одного регистра и для количества, и для себестоимости:
А что насчет типовых конфигураций? Там ведь только новая методика, верно?
Вот, например, в «1C:Управление торговлей 11.3» есть 2 регистра:
При проведении документов отгрузки регистр «Себестоимость товаров» не заполняется вообще. Данные в этот регистр попадают только при выполнении регламентных операций по закрытию месяца.
В УТ 11 используется новая методика, так как все данные для проведения документов можно получить, не обращаясь к контролируемым регистрам.
Что касается «1C:Бухгалтерии», то там и количество, и себестоимость хранятся в одном регистре бухгалтерии, на соответствующих счетах БУ.
Поэтому в БП 3.0 используется старая методика.
В рамках текущей статьи мы разберем блокировки и для старой, и для новой методики контроля остатков.
Про оперативное проведение документов
В этом простом вопросе часто встречаются заблуждения.
Оперативное проведение можно анализировать при контроле остатков, но не обязательно.
Оперативное проведение – это возможность документа регистрировать возникающие события здесь и сейчас, то есть в реальном времени.
Настраивается оно с помощью специального свойства документа:
Что значит «регистрировать здесь и сейчас»? Платформа для оперативно проводимых документов выполняет ряд действий:
Но главное другое – система передает признак оперативности проведения документа в обработку проведения:
Далее, в зависимости от значения этого параметра можно организовать запрос для получения остатков.
Для оперативно проводимых документов можно не указывать параметр в запросе, будут получаться актуальные остатки на 31.12.3999 год:
Актуальные остатки хранятся в системе и получаются максимально быстро (остатки на другие даты в большинстве случаев получаются расчетным путем).
Таким образом оперативное проведение можно принять и для старой, и для новой методики контроля остатков.
В УТ 11 документам, списывающим номенклатуру, запрещено проводиться оперативно. Например, это документы «Реализация товаров и услуг», «Сборка товаров», «Перемещение товаров», «Внутреннее потребление товаров» и другие.
Почему так сделано?
В системе контроль остатков всегда выполняется на актуальный момент времени (параметр Период в запросе не задается). А отсутствие оперативного проведения позволяет вводить документы будущим числом, такая задача часто требуется клиентам.
Контроль остатков по новой методике – без блокировок
Коротко рассмотрим алгоритм контроля остатков при проведении документа «Реализация товаров и услуг» на модельной конфигурации.
Для контроля остатков товаров достаточно работы с регистром «Свободные остатки».
Код обработки проведения будет выглядеть таким образом:
Процедура ОбработкаПроведения(Отказ, Режим)
Запрос = Новый Запрос;
// 1. Инициализация менеджера временных таблиц
#Область Область1
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
#КонецОбласти
// 3. Загрузка таблицы значений в набор записей
#Область Область3
Движения.СвободныеОстатки.Загрузить(РезультатЗапроса.Выгрузить());
#КонецОбласти
// 4. Запись движений в БД
#Область Область4
Движения.СвободныеОстатки.Записывать = Истина;
Движения.Записать();
#КонецОбласти
Менеджер будет необходим, чтобы созданная в запросе временная таблица была доступна и в следующих запросах.
Таким образом, данные табличной части получаются один раз, сохраняются во временную таблицу и далее используются многократно.
В запросе выбираются сгруппированные данные табличной части.
Обратите внимание, что выбирается и номер строки документа – он потребуется для контекстной привязки сообщения об ошибке. Для номера строки используется агрегатная функция МИНИМУМ() – то есть сообщение будет привязано к первой строке, где встречается указанная номенклатура.
В первом запросе пакета создается временная таблица. Во втором запросе выбираются данные временной таблицы и добавляются 2 поля, необходимые для каждой записи регистра – Период и ВидДвижения.
Одной командой происходит загрузка движений в набор записей.
Плюсы такого подхода:
Запись можно было бы выполнить одной командой (вместо двух) – Движения.СвободныеОстатки.Записать().
И в нашем случае, когда записывается один регистр, разницы не будет никакой.
Но более универсальным является такой подход:
После выполнения команды «Движения.Записать()» флаг Записывать у всех наборов сбросится в Ложь.
Также нужно помнить, что в конце транзакции (после ОбработкиПроведения) система автоматически запишет в БД только те наборы записей, у которых флаг Записывать установлен в значение Истина.
Метод Записать() коллекции Движения записывает наборы записей в одинаковой последовательности даже для разных документов.
Запись же движений вручную может привести к проблемам.
Если в документе «Реализация» выполнить запись так:
А в документе «Перемещение товаров» изменить порядок:
То это может привести к взаимоблокировке документов на пересекающихся наборах номенклатуры.
Приведенный подход записи движений можно использовать, если указано соответствующее значение записи движений в свойствах документа:
В запросе выбираются отрицательные остатки по номенклатуре из документа.
Отрицательный остаток – это и есть нехватка (дефицит) товара.
Если бы мы не планировали делать привязку сообщений к полям документа, запрос можно сильно упросить – будут получаться данные из одной таблицы (остатков регистра).
Вот здесь нам пригодилось оперативное проведение.
Если документ проводится оперативно, то момент для получения остатков – Неопределено, что означает получение актуальных остатков.
Если это неоперативное проведение, то мы получаем момент времени «после» документа – чтобы учесть только что сделанные движения.
Именно в этом и заключается выигрыш оперативно проводимых документов.
В цикле обходим все отрицательные остатки и выводим сообщение привязанной к строкам табличной части.
Вот так будет выглядеть диагностическое сообщение:
Если была хоть одна ошибка – выходим из процедуры.
Поскольку нет смысла продолжать проведение, транзакция всё равно не будет зафиксирована (а дальше у нас будет разработан код по списанию партий).
Реализация списания себестоимости по партиям
После того, как проверка остатков прошла успешно, можно приступать к списанию партий.
Код для списания по FIFO будет таким:
// I. Анализ смещения даты документа вперед
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если РежимЗаписи = РежимЗаписиДокумента.Проведение
И НЕ ЭтотОбъект.ЭтоНовый()
И ЭтотОбъект.Проведен Тогда
Запрос = Новый Запрос;
Запрос.Текст =
«ВЫБРАТЬ
| Документ.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Ссылка = &Ссылка»;
Запрос.УстановитьПараметр(«Ссылка», ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокумент = РезультатЗапроса.Выбрать();
ВыборкаДокумент.Следующий();
Иначе
ЭтотОбъект.ДополнительныеСвойства.Вставить(«ДатаДокументаСдвинутаВперед», Ложь);
КонецЕсли;
Если НЕ ЭтотОбъект.ДополнительныеСвойства.Свойство(«ДатаДокументаСдвинутаВперед») Тогда
Процедура ОбработкаПроведения(Отказ, Режим)
Запрос = Новый Запрос;
// 1. Инициализация менеджера временных таблиц
#Область Область1
.
#КонецОбласти
// 2. Запрос, группирующий данные табличной части
#Область Область2
.
#КонецОбласти
// 3. Загрузка таблицы значений в набор записей
#Область Область3
.
#КонецОбласти
// 4. Запись движений в БД
#Область Область4
.
#КонецОбласти
// 5. Запрос, получающий отрицательные остатки
#Область Область5
.
#КонецОбласти
// 6. Определение момента времени для контроля остатков
#Область Область6
.
#КонецОбласти
// 7. Если запрос не пустой, значит образовались отрицательные остатки
#Область Область7
.
#КонецОбласти
// 8. Если есть ошибки, то возвращаемся из обработчика события
#Область Область8
.
#КонецОбласти
// II. Подготовка наборов записей регистра «Себестоимость товаров»
#Область ОбластьII
Если ДополнительныеСвойства.ДатаДокументаСдвинутаВперед Тогда
Движения.СебестоимостьТоваров.Записывать = Истина;
Движения.СебестоимостьТоваров.Очистить();
Движения.Записать();
КонецЕсли;
Движения.СебестоимостьТоваров.Записывать = Истина;
#КонецОбласти
// III. Запрос получающий остатки партий для списания по FIFO
#Область ОбластьIII
Запрос.Текст =
«ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.Количество КАК Количество,
| ТоварыДокумента.НомерСтроки КАК НомерСтроки,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Остатки.СуммаОстаток, 0) КАК СуммаОстаток,
| Остатки.Партия КАК Партия
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура
| ИЗ
| ТоварыДокумента КАК Т)) КАК Остатки
| ПО ТоварыДокумента.Номенклатура = Остатки.Номенклатура
|
|УПОРЯДОЧИТЬ ПО
| Остатки.Партия.МоментВремени
|ИТОГИ
| МАКСИМУМ(Количество),
| СУММА(КоличествоОстаток)
|ПО
| Номенклатура»;
МоментКонтроляОстатков =
?(Режим = РежимПроведенияДокумента.Оперативный,
Неопределено,
Новый Граница(МоментВремени(), ВидГраницы.Исключая));
Запрос.УстановитьПараметр(«МоментВремени», МоментКонтроляОстатков);
РезультатЗапроса = Запрос.Выполнить();
#КонецОбласти
Разберем ключевые точки алгоритма списания партий по FIFO.
Здесь мы понимаем, сдвигается ли дата проведенного документа вперед. Эта информация будет полезна ниже, при очистке движений.
Для анализа сдвига даты документа потребуется 2 события:
Данные между событиями передаем через специальную коллекцию объекта – «ДополнительныеСвойства». Она существует пока текущая версия объекта находится в памяти, то есть доступна для всех событий при проведении.
Почему в БП не нужно задействовать «При записи»?
Всё просто – документы отгрузки в бухгалтерии не могут проводиться оперативно. А это значит, что время документа не будет принимать оперативную отметку (если документ перепроводится текущим днем), поэтому и старую и новую дату документа можно получить в событии «Перед записью».
Для документа установлен режим удаления движений – “При отмене проведения”:
Таким образом, есть вероятность, что при перепроведении мы можем учесть движения самого документа. НО произойдет это только в случае сдвига даты документа вперед. То есть очистку движений имеет смысл делать только при сдвиге даты документа вперед.
Если не будет удаления старых движений, то система сообщит о нехватке 6 мониторов, поскольку текущие движения документа уже списали 8 из 10 имеющихся мониторов.
Но это неправильно: ситуации изменения «неоперативных» документов (вчерашних и более ранних) они не учтут.
То есть проблема «нехватки 6 мониторов» (см. выше) будет в этом случае решена только для документов изменяемых сегодняшним числом.
В запросе обращаемся к остаткам по партиям, при этом накладываем итоги по номенклатуре.
На уровне итогов получается количество из документа – МАКСИМУМ(Количество) и остаток партии – СУММА(КоличествоОстаток).
Если движения по регистрам “СвободныеОстатки” и “СебестоимостьТоваров” по количеству делаются синхронно (и приход, и расход), то такой ситуации возникнуть не может. На это мы и будем закладываться при списании партий.
Благодаря итогам в запросе во внешнем цикле обходим номенклатуру из документа.
Запомним, какое количество нужно списать. Далее это количество будет уменьшаться.
Вложенный цикл будет содержать партии по текущей номенклатуре.
Далее будет производиться деление на количественный остаток. Деление на ноль приведет к ошибке во время исполнения.
Поэтому принимаем решение, что такие ошибочные партии будем пропускать. При желании можно выдать диагностику пользователю.
Количество для списания — это минимальное значение между остатком партии и тем, что осталось списать.
Сумма рассчитывается элементарной пропорцией.
То есть НЕ нужно делать дополнительных проверок (иногда дают такой совет) на то, что списывается все количество. Этот совет даже имеет своё название – «проблема копеек».
А тем, кто дает вредные советы имеет смысл заглянуть в конфигурацию «1С:Бухгалтерия 8». Там (о, ужас!) нет проверки на то, что списывается партия целиком 🙂
Вот скрин общего модуля «Учет товаров», метод «СписатьОстаткиТоваров»:
Нужно понять, сколько еще осталось списать. Для этого вычтем количество из движения регистра.
Зачем нужны управляемые блокировки?
Вот мы и дошли до управляемых блокировок.
Казалось бы, представленные выше алгоритмы работают, как часы. Можете сами их потестировать (ссылки на выгрузки баз в конце статьи).
Но при реальной многопользовательской эксплуатации начнутся проблемы, причем, как это часто бывает, проблемы будут обнаружены не сразу…
Приведем пример наиболее типичной проблемы при списании товара, когда 2 пользователя практически одновременно пытаются списать товар (оформить продажу):
В этом примере два пользователя почти одновременно проводят продажу товаров – документ №2 начал проводиться чуть позже документа 1.
При получении остатка система сообщает, что остаток 10 шт., и оба документа успешно проводятся. Печальный итог – на складе минус 5 мониторов LG.
Но при этом контроль остатков работает! То есть, если документ №2 будет проводиться после окончания проведения документа №1, система не проведет документ №2:
Это очень опасное рассуждение.
Даже, два пользователя могут проводить документы практически одновременно, например, если один из них выполняет групповое проведение документов.
Кроме этого, нельзя быть застрахованным от увеличения количества пользователей. Если бизнес пойдет «в гору», то нужны будут новые продажники, кладовщики, логисты и так далее. Поэтому нужно сразу создавать решения, которые будут устойчиво работать в многопользовательской среде.
Как решить проблему при параллельном проведении документов?
Решение простое – заблокировать мониторы LG в момент времени Т1, так чтобы другие транзакции не могли обратиться к остаткам по этому товару.
Тогда в момент времени Т2 система будет ждать, когда монитор LG будет разблокирован. И после этого система получит актуальный остаток товаров и будет выполнено (или не выполнено) списание товаров.
Существует 2 типа блокировок:
Если говорить просто, то объектные блокировки не позволяют интерактивно изменить двум пользователям один объект (элемент справочника или документ).
А транзакционные блокировки позволяют программно оперировать актуальными данными при выполнении движений по регистрам.
В этой статье нас будут интересовать именно транзакционные блокировки, далее просто блокировки.
Когда нужно накладывать блокировки?
Задача установки блокировок становится актуальной, как только в базе начинает работать более одного пользователя.
Блокировки нужно устанавливать в транзакциях, а когда возникают транзакции? Правильно, самый частый случай – проведение документов.
То есть блокировки нужно накладывать при проведении всех документов?
Ни в коем случае. Устанавливать блокировки «на всякий случай» точно не стоит. Ведь сами по себе блокировки снижают параллельность работы пользователей (масштабируемость системы).
Блокировки нужно накладывать на ресурсы (строки таблицы), которые читаются и изменяются в транзакциях. Например, при проведении документов.
В примере выше таким ресурсом является остаток по товару. Система должна была заблокировать остаток с момента получения данных об остатке (Т1) до окончания транзакции (Т3).
Пример, когда не нужно накладывать блокировку – проведение документа «Поступление товаров». В этом случае нет никакой конкуренции за ресурсы (остатки, …), поэтому блокировка будет вредна: она уменьшит масштабируемость системы.
Автоматические и управляемые блокировки
Здесь мы не будем вдаваться в теорию (это тема отдельной статьи), а скажем лишь, что управляемые блокировки являются более оптимальными.
Вместо теории можем привести пруф – все современные типовые конфигурации работают на управляемых блокировках.
Поэтому в нашей модельной конфигурации будет выбран соответствующий режим:
Управляемые блокировки в новой технологии контроля остатков
Блокировку будем накладывать на регистр “Свободные остатки” и только на номенклатурные позиции, встречающиеся в документе.
Причем правильный вариант наложения блокировки – как можно позднее.
В новой методике контроля остатков это нужно сделать перед записью (или в момент записи) движений в регистр “Свободные остатки”, чтобы другие транзакции не смогли изменить этот разделяемый ресурс.
Блокировку можно накладывать вручную (программным образом) и чуть позже мы покажем, как это делается.
Но дополнительный бонус новой технологии контроля остатков в том, что для блокировки разделяемых ресурсов нужна лишь одна строка кода.
Нужно просто установить свойство БлокироватьДляИзменения у набора записей регистра:
.
// 3. Загрузка таблицы значений в набор записей
#Область Область3
Движения.СвободныеОстатки.Загрузить(РезультатЗапроса.Выгрузить());
#КонецОбласти
// 3.1. Блокировка остатков регистра
#Область Область3_1
Движения.СвободныеОстатки.БлокироватьДляИзменения = Истина;
#КонецОбласти
// 4. Запись движений в БД
#Область Область4
Движения.СвободныеОстатки.Записывать = Истина;
Движения.Записать();
#КонецОбласти
.
В результате 2 транзакции не смогут изменять свободные остатки по одной номенклатуре.
Но для нашей статье принципиально следующее – система установит блокировку на комбинацию записываемых в регистр данных. А детально работу свойства БлокироватьДляИзменения мы рассмотрим в отдельной статье.
Кстати, в типовой УТ 11 не так-то просто найти установку свойства БлокироватьДляИзменения для регистра “Свободные остатки”. Дело в том, что это выполняется в модуле набора записей регистра, в событии “Перед записью”.
Вот и всё, одной строкой кода была обеспечена корректная работа системы!
Почему? Такая блокировка являлась бы излишней (а это определенная нагрузка на сервер 1С), поскольку движения в регистры “Свободные остатки” и “Себестоимость товаров” выполняются всегда синхронно, то есть последовательно друг за другом.
Поэтому, заблокировав товары из “Свободных остатков”, мы не допустим другие транзакции до этих товаров и в регистре “Себестоимость товаров”.
Но для старой методики контроля остатков блокировка будет накладываться по-другому. Для начала разберем алгоритм партионного списания для этого случая.
Старая методика контроля остатков
Напомним, что старая методика может применяться, если количество и стоимость учитываются в одном регистре.
Пусть это будет регистр “Себестоимость товаров”:
Тогда алгоритм проведения документа “Реализация товаров” будет выглядеть вот так:
// 1. Обработчик события «Перед записью»
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если РежимЗаписи = РежимЗаписиДокумента.Проведение
И НЕ ЭтотОбъект.ЭтоНовый()
И ЭтотОбъект.Проведен Тогда
Запрос = Новый Запрос;
Запрос.Текст =
«ВЫБРАТЬ
| Документ.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Ссылка = &Ссылка»;
Запрос.УстановитьПараметр(«Ссылка», ЭтотОбъект.Ссылка);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокумент = РезультатЗапроса.Выбрать();
ВыборкаДокумент.Следующий();
Иначе
ЭтотОбъект.ДополнительныеСвойства.Вставить(«ДатаДокументаСдвинутаВперед», Ложь);
КонецЕсли;
Если НЕ ЭтотОбъект.ДополнительныеСвойства.Свойство(«ДатаДокументаСдвинутаВперед») Тогда
Процедура ОбработкаПроведения(Отказ, Режим)
// 2. Удаление «старых» движений документа
Если ДополнительныеСвойства.ДатаДокументаСдвинутаВперед Тогда
Движения.СебестоимостьТоваров.Записывать = Истина;
Движения.СебестоимостьТоваров.Очистить();
Движения.Записать();
КонецЕсли;
// 3. Установка флага для записи движений в конце транзакции
Движения.СебестоимостьТоваров.Записывать = Истина;
// 4. Запрос, получающий остатки по партиям на момент времени документа
Запрос = Новый Запрос;
Запрос.Текст =
«ВЫБРАТЬ
| РеализацияТовары.Номенклатура КАК Номенклатура,
| СУММА(РеализацияТовары.Количество) КАК Количество,
| МИНИМУМ(РеализацияТовары.НомерСтроки) КАК НомерСтроки
|ПОМЕСТИТЬ ТоварыДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РеализацияТовары.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.Количество КАК Количество,
| ТоварыДокумента.НомерСтроки КАК НомерСтроки,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Остатки.СуммаОстаток, 0) КАК СуммаОстаток,
| Остатки.Партия КАК Партия
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура
| ИЗ
| ТоварыДокумента КАК Т)) КАК Остатки
| ПО ТоварыДокумента.Номенклатура = Остатки.Номенклатура
|
|УПОРЯДОЧИТЬ ПО
| Остатки.Партия.МоментВремени
|ИТОГИ
| МАКСИМУМ(Количество),
| СУММА(КоличествоОстаток)
|ПО
| НомерСтроки»;
МоментКонтроляОстатков =
?(Режим = РежимПроведенияДокумента.Оперативный,
Неопределено,
Новый Граница(МоментВремени(), ВидГраницы.Исключая));
Запрос.УстановитьПараметр(«МоментВремени», МоментКонтроляОстатков);
Если ДефицитНоменклатуры>0 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = «Недостаточно товара в количестве: «+ДефицитНоменклатуры;
Сообщение.Поле = «Товары[«+(ВыборкаНоменклатура.НомерСтроки-1)+»].Количество»;
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
Если Отказ Тогда
Продолжить;
КонецЕсли;
// 6. Получим количество для списания
ОсталосьСписать = ВыборкаНоменклатура.Количество;
ВыборкаПартии = ВыборкаНоменклатура.Выбрать();
// 7. Цикл по партиям
Пока ВыборкаПартии.Следующий() И ОсталосьСписать>0 Цикл
// 8. Проверка на ноль (дальше будет выполняться деление)
Если ВыборкаПартии.КоличествоОстаток=0 Тогда
Продолжить;
КонецЕсли;
Движение = Движения.СебестоимостьТоваров.ДобавитьРасход();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаПартии.Номенклатура;
Движение.Партия = ВыборкаПартии.Партия;
// 9. Расчет количества для списания
Движение.Количество = Мин(ОсталосьСписать, ВыборкаПартии.КоличествоОстаток);
// 10. Расчет суммы списания
Движение.Сумма = Движение.Количество*
ВыборкаПартии.СуммаОстаток/ВыборкаПартии.КоличествоОстаток;
Комментарии по ключевым моментам алгоритма.
Здесь мы понимаем, сдвигается ли дата проведенного документа вперед. Эта информация будет полезна ниже, при очистке движений.
Напомним, что для документа установлен режим удаления движений – “При отмене проведения”.
Поэтому позаботиться об очистке движений должен разработчик.
Благодаря этому сформированные движения запишутся в момент окончания транзакции.
Запрос состоит из двух пакетов.
В первом получаем сгруппированные данные табличной части. Номер строки выбираем, чтобы была возможность привязать сообщение об ошибке к конкретной строке документа.
Во втором запросе обращаемся к остаткам по партиям, при этом накладываем итоги по номеру строки. Таким образом, возможен контроль остатков на верхнем уровне (без анализа партий).
Именно здесь мы проверяем достаточность товаров.
Если их не хватает, то параметр “Отказ” выставляется в “Истину” и дальнейший анализ партий не будет выполняться.
В отдельной переменной запомним количество для списания. Далее в цикле по партиям оно будет уменьшаться.
Организуем списание по партиям.
Причем количества партий гарантированно будет хватать – проверка на достаточность количества была выше.
Страховка от деления на ноль – очень важное дело 🙂
Количество для списания – это минимальное значение между остатком партии и тем, что осталось списать.
Сумма рассчитывается пропорцией.
Нужно понять, сколько еще осталось списать.
Блокировки в старой методике контроля остатков
С помощью блокировки мы как бы говорим системе, что только эта транзакция может работать с этим списком товаров (накладываем блокировку). Если другая транзакция будет пытаться наложить блокировку хоть на один из ранее заблокированных товаров, она попадет в очередь ожидания. Через некоторое время (тайм-аут) будет сделана еще одна попытка наложить блокировку.
Сейчас мы не будем предельно точно расписывать механику работы системы при ожидании на блокировке. Здесь важно другое – блокировки не позволят читать неактуальные остатки из-за параллельной работы пользователей. То есть транзакции будут выстраиваться в очередь для получения актуальных остатков.
Но при этом транзакции по непересекающемуся набору товаров будут выполняться параллельно.
В какой момент нужно накладывать блокировку?
Наша задача – получить актуальные остатки. Поэтому блокировку нужно накладывать ДО запроса, получающего остатки.
То есть в нашем коде запрос нужно разбить на два:
И между этими запросами должна быть наложена блокировка.
Вот так изменится код:
// I. Инициализация менеджера временных таблиц
Запрос.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос.Текст =
«ВЫБРАТЬ
| РеализацияТовары.Номенклатура КАК Номенклатура,
| СУММА(РеализацияТовары.Количество) КАК Количество,
| МИНИМУМ(РеализацияТовары.НомерСтроки) КАК НомерСтроки
|ПОМЕСТИТЬ ТоварыДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
|ГДЕ
| РеализацияТовары.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
| РеализацияТовары.Номенклатура
|
|ИНДЕКСИРОВАТЬ ПО
| Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента»;
Запрос.УстановитьПараметр(«Ссылка», Ссылка);
РезультатЗапроса = Запрос.Выполнить();
// II. Установка блокировки
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить(«РегистрНакопления.СебестоимостьТоваров»);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
ЭлементБлокировки.ИсточникДанных = РезультатЗапроса;
ЭлементБлокировки.ИспользоватьИзИсточникаДанных(«Номенклатура», «Номенклатура»);
Блокировка.Заблокировать();
// III. Выполняем запрос к остаткам партий
Запрос.Текст =
«ВЫБРАТЬ
| ТоварыДокумента.Номенклатура КАК Номенклатура,
| ТоварыДокумента.Количество КАК Количество,
| ТоварыДокумента.НомерСтроки КАК НомерСтроки,
| ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
| ЕСТЬNULL(Остатки.СуммаОстаток, 0) КАК СуммаОстаток,
| Остатки.Партия КАК Партия
|ИЗ
| ТоварыДокумента КАК ТоварыДокумента
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СебестоимостьТоваров.Остатки(
| &МоментВремени,
| Номенклатура В
| (ВЫБРАТЬ
| Т.Номенклатура КАК Номенклатура
| ИЗ
| ТоварыДокумента КАК Т)) КАК Остатки
| ПО ТоварыДокумента.Номенклатура = Остатки.Номенклатура
|
|УПОРЯДОЧИТЬ ПО
| Партия
|ИТОГИ
| МАКСИМУМ(Количество),
| СУММА(КоличествоОстаток)
|ПО
| НомерСтроки
|АВТОУПОРЯДОЧИВАНИЕ»;
Прокомментируем ключевые моменты.
Созданную временную таблицу мы будем использовать во втором запросе. Чтобы была такая возможность, нужно создать менеджер временных таблиц.
К этому мы шли всю статью.
Товары для блокировки берутся из результата запроса. Далее сопоставляются поле из регистра и поле запроса (в нашем случае оба называются – Номенклатура).
Теперь можно выполнять запрос, получающий остатки. В этот момент времени гарантированно только одна транзакция работает с остатками по конкретному набору товаров.
Подведение итогов
Установку управляемых блокировок нужно обязательно выполнять на конкурирующие ресурсы, которые используются в транзакциях (в частности при проведении документов).
Мы рассмотрели установку блокировок для старой и новой методики контроля остатков:
Новая методика используется в УТ 11, старая – в БП 3.0.
Но это не значит, что в УТ 11 не накладываются блокировки программным образом. Например, для регистров взаиморасчетов используется блокировка через объект “Блокировка данных”.
И не забывайте про блокировки на экзамене “1С:Специалист” по платформе! 🙂
Выгрузки ИБ и PDF-версия статьи для участников группы ВКонтакте
Если Вы еще не вступили в нее – сделайте это сейчас, и в блоке ниже (на этой странице) появятся ссылки на скачивание материалов.
Статья в PDF-формате
Вы можете скачать эту статью в формате PDF по следующей ссылке: Ссылка доступна для зарегистрированных пользователей)
ИБ с новой методикой контроля остатков:
Ссылка доступна для зарегистрированных пользователей)
ИБ со старой методикой контроля остатков:
Ссылка доступна для зарегистрированных пользователей)
ИБ разрабатывались на платформе 1С:Предприятие 8.3.9.1850.