понедельник, 20 января 2014 г.

Новая методика проведения документа в 1С 8.2

Рассмотрим новую методику проведения на платформе 8.2.  Для этого возьмем демо- конфигурацию "Управляемое приложение" и рассмотрим методику проведения документа "РасходТовара", который делает движения по регистру "ТоварныеЗапасы".

Рассмотрим процедуру документа ОбработкаПроведения(Отказ, Режим):

Процедура ОбработкаПроведения(ОтказРежим)

    
// Формирование движений регистров накопления ТоварныеЗапасы и Продажи.
    
Движения.ТоварныеЗапасы.Записывать = Истина;

    Если 
Режим РежимПроведенияДокумента.Оперативный Тогда
        
Движения.ТоварныеЗапасы.БлокироватьДляИзменения = Истина;
    КонецЕсли;

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

    
Запрос.УстановитьПараметр("Ссылка"Ссылка);
    
РезультатУслуги Запрос.Выполнить().Выгрузить();
    
РезультатУслуги.Индексы.Добавить("НомерСтроки");

    Для каждого 
ТекСтрокаТовары Из Товары Цикл

        
Строка РезультатУслуги.Найти(ТекСтрокаТовары.НомерСтроки"НомерСтроки");
        Если 
Строка = Неопределено Тогда

            
// ** 1 - формируем набор записей, как-будто контроля остатков мы не выполняем,
            // т.е. просто списываем товары без контроля
            // и формируем набор записей

            // Не услуга
            
Движение Движения.ТоварныеЗапасы.Добавить();
            
Движение.ВидДвижения ВидДвиженияНакопления.Расход;
            
Движение.Период Дата;
            
Движение.Товар ТекСтрокаТовары.Товар;
            
Движение.Склад Склад;
            
Движение.Количество ТекСтрокаТовары.Количество;

        КонецЕсли;

    КонецЦикла;


    
//** 2 - записываем этот набор в БД
    //Запишем движения
    
Движения.Записать();

    
//Контроль остатков при оперативном проведении
    
Если Режим РежимПроведенияДокумента.Оперативный Тогда

        
//** 3 - и только после этого выбираем запросом актуальные остатки, и только отрицательные
        // таким образом мы определяем какого товара у нас не хватает

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

        
Запрос.УстановитьПараметр("Склад"Склад);
        
Запрос.УстановитьПараметр("Ссылка"Ссылка);
        
РезультатСНехваткой Запрос.Выполнить();

        
ВыборкаРезультатаСНехваткой РезультатСНехваткой.Выбрать();

        
//** 4 - если у нас есть строки, которые ушли в минус, то выдаем сообщения пользователю
        // Выдадим ошибки для строк, в которых не хватает остатка
        
Пока ВыборкаРезультатаСНехваткой.Следующий() Цикл

            
Сообщение = Новый СообщениеПользователю();
            
Сообщение.Текст НСтр("ru = 'Не хватает '""ru")
                + 
ВыборкаРезультатаСНехваткой.Нехватка
                НСтр("ru = ' единиц товара'""ru") + """"
                
ВыборкаРезультатаСНехваткой.ТоварПредставление
                """"
                
НСтр("ru = ' на складе'""ru")
                + 
""""
                
Склад
                """."
                
НСтр("ru = 'Максимальное количество: '""ru")
                + 
ВыборкаРезультатаСНехваткой.МаксимальноеКоличество
                ".";
            
Сообщение.Поле НСтр("ru = 'Товары'""ru")
                + 
"["
                
+ (ВыборкаРезультатаСНехваткой.НомерСтроки 1)
                + 
"]."
                
НСтр("ru = 'Количество'""ru");
            
Сообщение.УстановитьДанные(ЭтотОбъект);
            
Сообщение.Сообщить();

            
//** 5 - соответственно отказываемся от проведения
            
Отказ = Истина;

        КонецЦикла;

    КонецЕсли;

КонецПроцедуры

Почему же именно такая методика? Давайте попробуем с этим разобраться. Для начала рассмотрим значения свойств, которые появились для документов на платформе 8.2:
1) "Удалять движения" - по-умолчанию установлено на "Удалять автоматически при отмене проведения". Это означает, что при отмене проведения будет доступен набор записей предыдущего документа, т.е. перед обработкой проведения очистка движений произведена не будет. В чем преимущество такой записи движений? В том, что мы избавляемся от лишней записи в регистр. Мы перед обработкой проведения, очищение регистра не производим, а производим его только в обработке проведения и то, здесь мы его не очищаем, а перезаписываем. При этом платформа перезапишет старый на новый набор записей максимально эффективно. Таким образом мы избавимся от лишней записи и сократим время проведения.
2) "Запись движений при проведении" -  имеет 2 значения "Записывать выбранные" и "Записывать модифицированные". 
"Записывать модифицированные" - это аналог того как производились движения в платформе 8.1, в 8.2 по-умолчанию используется - "Записывать выбранные". Это означает, что при выходе из обработки проведения или при вызове метода Движения.Записать() будут записаны только те наборы записей, у которых свойство "Записывать" равно Истина ( Движения.ТоварныеЗапасы.Записывать = Истина). Таким образом разработчик может самостоятельно управлять списком регистров, которые должны быть записаны.
3) "Привилегированный режим при проведении" и "Привилегированный режим при отмене проведения" - эти два свойства позволяют проводить и отменять проведение документов без контроля прав. Подразумевается, что пользователю уже дано право  на проведение и отмену проведения документа, значит нет смысла в обработке проведения еще дополнительно контролировать право доступа на объекты, которые используются в этой обработке проведения, поэтому этими свойствами мы проверку прав отключаем и движения будут производиться быстрее.
4) "Режим управления блокировкой данных" - по умолчанию устанавливается "Управляемый" для всех объектов в платформе 8.2. "Управляемый" означает, что все блокировки мы будем устанавливать самостоятельно. Раньше при установке "Автоматического" мы передавали управление блокировками СУБД, но СУБД не всегда правильно с этим справлялась и как следствие - возникали избыточные блокировки,  поэтому с помощью управляемого режима мы можем заблокировать только то, что нам нужно и таким образом  уменьшить вероятность задержек на избыточных блокировках и как результат - уменьшить время проведения документа.
Управляемые блокировки могут устанавливаться автоматически. Это происходит при записи наборов в регистр, т.е. когда мы вызываем метод Движения.Записать(), либо при записи, когда мы выходим из обработки проведения, платформа автоматически устанавливает блокировку  на регистры, по той комбинации измерений, которая была указана в наборе для записи этого регистра. Поэтому тут не нужно работать с объектом БлокировкаДанных и блокировать все вручную - это сделает платформа автоматически.
Единственный случай, когда нужно будет устанавливать вручную, это когда мы читаем данные, с помощью запроса, а потом эти данные модифицируем в обработке проведения. Также как и по старой методике контроля остатков. 
Здесь еще мы видим на первый взгляд такое непонятное свойство "БлокироватьДляИзменения". Зачем оно нужно, если мы сначала пишем и блокировки автоматически установятся? Это свойство актуально в том случае, когда для регистра накопления свойство "Разрешить разделение итогов" равно "Истина".
Разделение итогов означает, что параллельно в один и тот же регистр по одной  и той же комбинации измерений могут писать данные несколько транзакций. А установка этого свойство в значение "Истина" эту возможность отключит, т.е. параллельно другие транзакции писать не смогут, даже если установлен флажок "Разрешить разделение итогов". Таким образом, после того, как мы запишем данные в регистр, дальше никто ничего не сможет изменить и у нас в итоге будут выбраны актуальные остатки, т.е. никто их после нашей записи не изменит.
А могли ли мы воспользоваться старой методикой? Допустим мы сначала будем читать данные из регистра, а затем списывать товар, если остатка хватает. Что в этом случае изменится?
Во-первых в обработке проведения не очищаются наборы записей предыдущих движений, т.к. стоит свойство "Удалять автоматически при отмене проведения", поэтому, чтобы нам прочитать остатки без учета движения этого документа нужно сначала перед чтением остатков записать пустой набор записей, чтобы этот набор очистился:

 // Формирование движений регистров накопления ТоварныеЗапасы и Продажи.
 
Движения.ТоварныеЗапасы.Записывать = Истина;
 Движения.ТоварныеЗапасы.Записать();

Таким образом движения очистятся от предыдущих проведений и мы прочитаем те остатки, которые нам нужны. Но в этом случае смысла в свойстве "Удалять автоматически при отмене проведения" вообще нет никакого, мы ведь устанавливали его для того, чтобы у нас лишних действий при проведении не производилось. А мы этой строкой (Движения.ТоварныеЗапасы.Записать()) это преимущество убираем. Поэтому решением тут является использование новой методики проведения: сначала пишем, потом читаем.
Когда пишем, мы перезаписываем старый набор записей, а потом прочитаем актуальные остатки, причем только те, которые ушли в минус. И также здесь еще одно преимущество -  не нужно устанавливать управляемые блокировки вручную, т.к. при записи они выставляются автоматически. А если бы сначала читали, а потом писали, то нужно было бы использовать объект БлокировкаДанных, заблокировать регистр по набору записей, а потом уже только читать, что уже сложнее, чем написать только одну строку.
Вот такие преимущества у новой методики проведения.


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

2 комментария :

  1. Вот контактные данные г-на Бенджамина, адрес электронной почты, lfdsloans@outlook.com. / Или WhatsApp 1 989-394-3740, который помог мне с займом в 90 000,00 евро, чтобы начать свой бизнес, и я очень благодарен, мне было очень тяжело, пытаясь найти способ, как мать-одиночка, вещи не были легкими со мной, но с помощью мистера Бенджамина улыбнулся мне в лицо, когда я смотрю, как растет и развивается мой бизнес. Я знаю, вы можете удивиться, почему я ставлю такие вещи здесь, но я действительно должен выразить свою благодарность, чтобы любой, кто ищет финансовая помощь или преодоление трудностей с этим бизнесом или желание запустить бизнес-проект могут позаботиться об этом и надеяться на выход из затруднений. Спасибо.

    ОтветитьУдалить
  2. Написано тяжело..
    Лучше не пишите.
    А с ошибками, так вообще не беритесь.

    ОтветитьУдалить