У нас в конторе долго шли баталии по поводу резервов, все сводилось к тому, что складкие товарищи, не желали своевременно указывать заказы в поступлении, а уж когда шел предворительный документ заказ поставщику да еще со ссылкой на заказ покупателя, то все труба... Решил я найти альтернативу предложенный в штатной торговле. Принцип алгоритма такой:
Правда реализованный только в документе поступления, остальные движения прихода я не трогал (оприходование, перемещение, возвраты)
Анализируется приход продукции, по каждой номенклатуре ищем заказы покупателя, если поле склад не заполнено, значит имеем предзаказ, тут важно что при проведении поступлении анализируются остатки итоговые, т.е. приход + то что было (+ вычеты уже текущих резервов, т.е. получаем свободный остаток), что позволяет раскидать реальный остаток продукции по заказам. Предположим на остатках 5 штук, в заказе 6, тогда дублируется строка, в первой будет 5 под резерв, 6 будет ожидать поступления. (принцип как при Заполнить и провести, в заказе покупателя)
Есть один существенный минус, в принципе тут ничего нового, при отмене поступелния, резервы пойдут в минус, но они и при штатной операции отмены, в минус уйдут.
Также у меня в документах заказы покупателея, стоит новый реквизит "НапоминаниеРезерва", в котром менегеры ставят дату, по какое число контролировать резерв, забыли поставить, не будет резерва, а такж есть обработка, которые им выводит эти резервы 2 раза в день, просроченныые красным, текущие зеленым, и там же они могут закрыть эти заказы, в случае их необходимости (кому надо могу выложить)
вот процедура, у меня стоит в обработке проведения, но можно поставить просто на кнопку.
НЕ забудьте в заказе добаить реквизит "НапоминаниеРезерва" и выставить дату выше текущий, либо уберите проверку этого реквизита из кода.
Процедура РезервированиеПродукции()
// Если нужно вызвать диалог утверждение в операции, то разкомментирвать ниже
///ОтветНаВопрос = Вопрос("Провести автоматическое резервирование товара?", РежимДиалогаВопрос.ДаНет);
СвободноДляРезервов = 0;
//Если ОтветНаВопрос = КодВозвратаДиалога.Нет
// Тогда
// Возврат
// КонецЕсли;
Для каждого СтрокаТЧ Из Товары Цикл
ПотребностьОстатков = 0;
ЗапросОстатков = Новый Запрос;
запросОстатков.УстановитьПараметр("Номенклатура",СтрокаТЧ.Номенклатура);
запросОстатков.УстановитьПараметр("ХарактеристикаНоменклатуры",СтрокаТЧ.ХарактеристикаНоменклатуры);
ЗапросОстатков.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры,
| ТоварыНаСкладахОстатки.КоличествоОстаток,
| ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток КАК КоличествоОстаток1,
| ВЫБОР
| КОГДА ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток ЕСТЬ NULL
| ТОГДА ТоварыНаСкладахОстатки.КоличествоОстаток
| ИНАЧЕ ВЫБОР
| КОГДА ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток < 0
| ТОГДА -1
| ИНАЧЕ ТоварыНаСкладахОстатки.КоличествоОстаток - ТоварыВРезервеНаСкладахОстатки.КоличествоОстаток
| КОНЕЦ
| КОНЕЦ КАК ИтогоСвободно
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезервеНаСкладах.Остатки КАК ТоварыВРезервеНаСкладахОстатки
| ПО ТоварыНаСкладахОстатки.Номенклатура = ТоварыВРезервеНаСкладахОстатки.Номенклатура
| И ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры = ТоварыВРезервеНаСкладахОстатки.ХарактеристикаНоменклатуры
|ГДЕ
| ТоварыНаСкладахОстатки.Номенклатура = &Номенклатура
| И ТоварыНаСкладахОстатки.ХарактеристикаНоменклатуры = &ХарактеристикаНоменклатуры";
КонтрольНоменклатуры = Ложь;
Результат = ЗапросОстатков.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
СвободноДляРезервов = Результат.ИтогоСвободно + СтрокаТЧ.Количество;
КонтрольНоменклатуры = Истина
КонецЦикла;
Если НЕ КонтрольНоменклатуры
Тогда
СвободноДляРезервов = СтрокаТЧ.Количество
КонецЕсли;
Если СвободноДляРезервов Тогда
Если СвободноДляРезервов = -1
Тогда
Сообщить("По номенклатуре: " + СтрокаТЧ.Номенклатура + " | " + СтрокаТЧ.ХарактеристикаНоменклатуры + "минусовой резерв")
Иначе
Сообщить("По номенклатуре: " + СтрокаТЧ.Номенклатура + " | " + СтрокаТЧ.ХарактеристикаНоменклатуры + " на остатках = " + СвободноДляРезервов);
КонецЕсли;
Продолжить
КонецЕсли;
Запрос= Новый Запрос;
запрос.УстановитьПараметр("Номенклатура",СтрокаТЧ.Номенклатура);
запрос.УстановитьПараметр("ХарактеристикаНоменклатуры",СтрокаТЧ.ХарактеристикаНоменклатуры);
запрос.УстановитьПараметр("Размещение", Неопределено );
запрос.УстановитьПараметр("НапоминаниеРезерва", ТекущаяДата() );
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказыПокупателейОстатки.ЗаказПокупателя,
| ЗаказыПокупателейОстатки.Номенклатура,
| ЗаказыПокупателейОстатки.КоличествоОстаток,
| ЗаказыПокупателейОстатки.ХарактеристикаНоменклатуры
|ИЗ
| РегистрНакопления.ЗаказыПокупателей.Остатки КАК ЗаказыПокупателейОстатки
|ГДЕ
| ЗаказыПокупателейОстатки.Номенклатура = &Номенклатура
| И ЗаказыПокупателейОстатки.ХарактеристикаНоменклатуры = &ХарактеристикаНоменклатуры
| И ЗаказыПокупателейОстатки.ЗаказПокупателя.Товары.Размещение = &Размещение
| И ЗаказыПокупателейОстатки.ЗаказПокупателя.НапоминаниеРезерва >= &НапоминаниеРезерва";
Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
ЗаписатьЗаказ = ложь;
Заказ = Результат.ЗаказПокупателя.ПолучитьОбъект();
ЗаказФорма = Заказ.ПолучитьФорму();
ТоварыЗаказаПокупателя = Заказ.Товары.Выгрузить();
Для каждого СтрокаТЧЗазаков Из ТоварыЗаказаПокупателя Цикл
Если (СтрокаТЧЗазаков.Размещение = Неопределено) И (СтрокаТЧЗазаков.Номенклатура = СтрокаТЧ.Номенклатура) И (СтрокаТЧЗазаков.ХарактеристикаНоменклатуры = СтрокаТЧ.ХарактеристикаНоменклатуры)
Тогда
Если СтрокаТЧЗазаков.Количество Тогда
СтрокаТЧЗазаков.Размещение = Ссылка.СкладОрдер; //Справочники.Склады.НайтиПоКоду("00001");
СвободноДляРезервов = СвободноДляРезервов - СтрокаТЧЗазаков.Количество;
ЗаписатьЗаказ = Истина;
Заказ.Товары.Загрузить(ТоварыЗаказаПокупателя);
Сообщить("Номенклатура " + СтрокаТЧЗазаков.Номенклатура + " | " + СтрокаТЧЗазаков.ХарактеристикаНоменклатуры + "В заказе № " + Заказ.Номер + " от " + Заказ.Дата + " ," + Заказ.Организация + " ," + Заказ.Контрагент);
Сообщить("Полностью зарезервирована");
Сообщить("--------------------------------------------------------------------------------------------");
Иначе
Если СвободноДляРезервов <> 0
Тогда
НаОстатках = СвободноДляРезервов;
ОстатокДляРезерва = СтрокаТЧЗазаков.Количество - СвободноДляРезервов;
Требуется = СтрокаТЧЗазаков.Количество;
СтрокаТЧЗазаков.Количество = СтрокаТЧЗазаков.Количество - ОстатокДляРезерва;
СтрокаТЧЗазаков.Размещение = Ссылка.СкладОрдер;
СтрокаТЧЗазаков.Сумма = СтрокаТЧЗазаков.Количество * СтрокаТЧЗазаков.Цена;
КоличествоМест = ?((СтрокаТЧЗазаков.ЕдиницаИзмеренияМест.Коэффициент = 0) ИЛИ (СтрокаТЧЗазаков.Количество = 0), 0, СтрокаТЧЗазаков.Количество / СтрокаТЧЗазаков.ЕдиницаИзмеренияМест.Коэффициент);
СтрокаТЧЗазаков.КоличествоМест = ?((КоличествоМест % 2 = 0) ИЛИ (КоличествоМест % 2 = 1), КоличествоМест, 0);
ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(СтрокаТЧЗазаков, Заказ);
Заказ.Товары.Загрузить(ТоварыЗаказаПокупателя);
НоваяЗапись = Заказ.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяЗапись,СтрокаТЧЗазаков);
НоваяЗапись.Количество = ОстатокДляРезерва;
НоваяЗапись.Сумма = НоваяЗапись.Количество * СтрокаТЧЗазаков.Цена;
КоличествоМест = ?((НоваяЗапись.ЕдиницаИзмеренияМест.Коэффициент = 0) ИЛИ (НоваяЗапись.Количество = 0), 0, НоваяЗапись.Количество / НоваяЗапись.ЕдиницаИзмеренияМест.Коэффициент);
НоваяЗапись.КоличествоМест = ?((КоличествоМест % 2 = 0) ИЛИ (КоличествоМест % 2 = 1), КоличествоМест, 0);
ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(НоваяЗапись, Заказ);
НоваяЗапись.Размещение = Неопределено;
ЗаписатьЗаказ = Истина;
Сообщить("Номенклатура " + СтрокаТЧЗазаков.Номенклатура + " | " + СтрокаТЧЗазаков.ХарактеристикаНоменклатуры + " в заказе № " + Заказ.Номер + " от " + Заказ.Дата + " ,организация: " + Заказ.Организация + " ,контрагент: " + Заказ.Контрагент + " | недостаточно на складе" );
Сообщить("Для резерва требуется: " + Требуется + " , на складе доступно: " + НаОстатках + ".");
Сообщить("В заказе произошли изменения: " + СтрокаТЧЗазаков.Номенклатура + " | " + СтрокаТЧЗазаков.ХарактеристикаНоменклатуры + " в резерве, в количестве: " + СтрокаТЧЗазаков.Количество + ". Недостающая продукция, в количестве: " + НоваяЗапись.Количество + " ожидает нового поступления");
Сообщить("--------------------------------------------------------------------------------------------");
Иначе
Сообщить("В заказе: " + Заказ.Номер + " требуется " + СтрокаТЧЗазаков.Количество);
Сообщить("Остатков по номенклатуре " + СтрокаТЧ.Номенклатура + " | " + СтрокаТЧ.ХарактеристикаНоменклатуры + " = " + СвободноДляРезервов + " Резервирование по данной позиции остановлено");
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ЗаписатьЗаказ
Тогда
Попытка
Заказ.Записать(РежимЗаписиДокумента.Проведение);
Сообщить(Заказ);
Сообщить("СОХРАНЕН");
Сообщить("*********************************************")
Исключение
Сообщить("Произошла ошибка при сохранении заказа");
Сообщить("*********************************************")
КонецПопытки
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры