gifts2017

Автоматическое резервирование в УТ 11 по приходу

Опубликовал Андрей Коваль (hiduk) в раздел Обработки - Обработка документов

В конфигурации УТ 11 нет возможности настроить автоматическое резервирование товара, при его поступлении на склад. Но, как говорится, если очень хочется - то можно.

Предистория.

Внедряли пару лет назад УТ 11.1 (11.1.9.70) на складе. Не обошлось и без заказов клиента. Когда речь зашла о резервировани, выяснили, что проставить резерв можно исключительно руками. Ну и хорошо, подумали мы, программисты. Непозволительно! - воскликнули они, пользователи.

Как говорил наш генеральный - "нужно чуть-чуть поднастроить, программу и всё заработает", при этом, слегка жестикулируя правой рукой. Разве можно отказать генеральному, который исправно платит тебе оклад? Конечно нет, принимая во внимание, что УТ работала в жесткой связке с управленческой базой на 1с 7, и часть бизнес процессов должна была быть идентична в обеих базах.

Постановка задачи.

При поступлении товара на склад, необходимо зарезервировать его в первых (по дате) заказах клиента.

Решение.

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

Однако все оказалось не так уж радужно. Как выяснилось, этот механизм работает с ФОРМОЙ документа, и работает только с одним документом. Он не документирован, сложен, и черт ногу в нем сломит.

Однако путем проб и ошибок его удалось приспособить под собственные нужды.

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

Ниже приведен листинг используемых процедур и функций.

Во вложенном файле все тоже самое, но в формате 1С.

Напоминаю, что механизм разрабатывался под конфигурацию 11.1.9.70.  Не исключено, что подойдет и для других версий.


#Область  ОбработчикиСобытий

// Программный код процедуры необходимо добавить в модуль формы документа Приходный Ордер, в процедуру ПослеЗаписиНаСервере
Процедура ПослеЗаписиНаСервере(Форма, ТекущийОбъект, ПараметрыЗаписи) Экспорт
    
    Если Форма.ИмяФормы = "Документ.ПриходныйОрдерНаТовары.Форма.ФормаДокумента" Тогда 
        РезервированиеАвтоматическое(Форма, ТекущийОбъект, ПараметрыЗаписи);
    КонецЕсли;
        
КонецПроцедуры    

#КонецОбласти

#Область  РезервированиеАвтоматическое

Процедура РезервированиеАвтоматическое(Форма, ТекущийОбъект, ПараметрыЗаписи)
            
    Если ПараметрыЗаписи.РежимЗаписи <> РежимЗаписиДокумента.Проведение Тогда
        Возврат;
    КонецЕсли;
    
    ЕстьЗарезервированныеТовары = Ложь;

    // МассивРаспределяемыхТоваров - будет служить для того, чтобы со временем, прекратить распределение
    МассивРаспределяемыхТоваров = ТекущийОбъект.Товары.ВыгрузитьКолонку("Номенклатура");
        
    // Формируем запрос, выбираем незарезервированные (не обеспеченные) заказы
    РезультатЗапросаТоваровЗаказовКлиентовКОбеспечению = ПолучитьРезультатЗапросаТоваровЗаказовКлиентовКОбеспечению(МассивРаспределяемыхТоваров);
    
    // Обходим выборку, начинаем резервировать товар (обеспечивать заказы)
    ВыборкаЗаказы = РезультатЗапросаТоваровЗаказовКлиентовКОбеспечению.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока ВыборкаЗаказы.Следующий() Цикл
        
        ПереченьВариантов = Новый Массив();
        ИндексыСтрок = Новый Массив();
        ТоварыСтрок = Новый Массив();
        
        ВыборкаСтрокиЗаказа = ВыборкаЗаказы.Выбрать();
        Пока ВыборкаСтрокиЗаказа.Следующий() Цикл
            Если ПереченьВариантов.Найти(ВыборкаСтрокиЗаказа.ВариантОбеспечения) = Неопределено Тогда
                ПереченьВариантов.Добавить(ВыборкаСтрокиЗаказа.ВариантОбеспечения);
            КонецЕсли;
            ИндексыСтрок.Добавить(ВыборкаСтрокиЗаказа.НомерСтроки - 1);
            ТоварыСтрок.Добавить(ВыборкаСтрокиЗаказа.Номенклатура);
        КонецЦикла;
        
        Если ПереченьВариантов.Найти(Перечисления.ВариантыОбеспечения.Отгрузить) = Неопределено Тогда
            ПереченьВариантов.Добавить(Перечисления.ВариантыОбеспечения.Отгрузить);
        КонецЕсли;    
        
        ВыполнитьОбеспечениеЗаказа(ВыборкаЗаказы.Ссылка, ИндексыСтрок, ПереченьВариантов,МассивРаспределяемыхТоваров,ТоварыСтрок,ТекущийОбъект,ЕстьЗарезервированныеТовары);
        
        Если МассивРаспределяемыхТоваров.Количество() = 0 Тогда // все распределили
            Прервать;
        КонецЕсли;
        
    КонецЦикла;
    
    Если ЕстьЗарезервированныеТовары Тогда
        // Если возникнет необходимость выводить сообщение, даже при нажатии на кнопку "Провести и закрыть",
        // это можно будет организовать через оповещение, переместив начало процесса резервирования на клиент,
        // в процедуру послезаписи, на клиенте.
        ТекстСообщения = НСтр("ru = 'Документ ""%ДокументОснование%"" зарезервировал товары.'");
        ТекстСообщения = СтрЗаменить(ТекстСообщения, "%ДокументОснование%", ТекущийОбъект);
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения,ТекущийОбъект);
    КонецЕсли;    
    
КонецПроцедуры    

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

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

Функция ПолучитьЗарезервированныеТовары(ТаблицаОбеспечения,МассивРаспределяемыхТоваров,ТоварыСтрок,ТоварыДокументаДоОбеспечения)
    
    Отбор = Новый Структура();
    Отбор.Вставить("ВариантОбеспечения",Перечисления.ВариантыОбеспечения.Отгрузить);
    Строки = ТаблицаОбеспечения.НайтиСтроки(Отбор);
    ТаблицаЗарезервированныхТоваров = ТаблицаОбеспечения.Скопировать(Строки,"Идентификатор,Количество");
    ТаблицаЗарезервированныхТоваров.Колонки.Добавить("Номенклатура",Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
        
    Для Каждого Строка ИЗ ТаблицаЗарезервированныхТоваров Цикл
        СтрокаДокумента = ТоварыДокументаДоОбеспечения.Найти(Строка.Идентификатор+1,"НомерСтроки");
        Строка.Номенклатура = СтрокаДокумента.Номенклатура;    
    КонецЦикла;
    
    ТаблицаЗарезервированныхТоваров.Колонки.Удалить("Идентификатор");
    
    Для Каждого Товар ИЗ ТоварыСтрок Цикл
        СтрокаТаблицаЗарезервированныхТоваров = ТаблицаЗарезервированныхТоваров.Найти(Товар,"Номенклатура");
        Если СтрокаТаблицаЗарезервированныхТоваров = Неопределено Тогда // этого товара уже нет больше в свободном остатке
            ИндексЭлемента = МассивРаспределяемыхТоваров.Найти(Товар);
            Если ИндексЭлемента <> Неопределено Тогда
                МассивРаспределяемыхТоваров.Удалить(ИндексЭлемента);
            КонецЕсли;    
        КонецЕсли;
    КонецЦикла;    
    
    Возврат ТаблицаЗарезервированныхТоваров;
    
КонецФункции

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

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

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

    ПараметрыЗаполнения = МенеджерДокумента.ПараметрыВыбораОбеспечения(Документ.Статус);
    
    ТаблицаОбеспечения = ОбеспечениеСервер.ТаблицаЗаполнениеОбеспеченияДокумента(Документ, ПереченьВариантов, ПараметрыЗаполнения, ИндексыСтрок);
    
    ВернутьПрежнююДатуОтгрузки(ТаблицаОбеспечения,ТоварыДокументаДоОбеспечения,Документ);

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

#КонецОбласти

Скачать файлы

Наименование Файл Версия Размер
ПрограммныйКод 2
.cf 12,05Kb
20.10.16
2
.cf 12,05Kb Скачать

См. также

Подписаться Добавить вознаграждение
Комментарии
1. A-tomic (A-tomic) 20.11.16 21:12
Отлично сработало на УТ 11.3.1, спасибо.

Было внесено несколько правок: проверка назначения (товар оприходуется под конкретный заказ клиента), ориентация на склад, как реквизит табличной части (используется поступление / реализация с нескольких складов).

Сколько всего времени заняло создание этого кода в днях, если не секрет?
2. Андрей Коваль (hiduk) 21.11.16 09:27
Около 3 дней. Всего задача отняла пару недель - с постановкой задачи, поиском способа реализации, попытками разобраться в типовом механизме резервирования (дыбом волосы стояли), и внедрением. 2 недели, учитывая то что с УТ 11 ковырялся уже год...
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа