Контроль остатков при отмене проведения?

1. yurowski 33 15.04.15 12:28 Сейчас в теме
Всем привет.

Как малой кровью реализовать контроль остатков организации при отмене проведения документов поступления/перемещения и т.п.?
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. spezc 793 15.04.15 12:56 Сейчас в теме
3. MiniMuk 10 15.04.15 13:00 Сейчас в теме
А на какую дату вы хотите реализовать контроль остатков?
4. ZLENKO 398 15.04.15 13:07 Сейчас в теме
Написать запрос, проверяющий возникновение отрицательных остатков по регистру при отмене проведения :-)
Но чтобы корректно работало во всех случаях (например, при изменении состава документа), то малой кровью не получится :-(
5. MiniMuk 10 15.04.15 13:35 Сейчас в теме
(4) ZLENKO, получить остатки по регистру по всей номенклатуре на дату время каждого документа, помоему на любой приличной базе с движениями за пару лет он просто умрет.
Причем может получиться наприме так что отменяете приход например где на приход ставиться 100 карандашей. а через год у вас случается ситуация когда на остатках на начало дня остается 1 карандаш. Утром вы списываете 2 карандаша, а вечером приходуете 5! Причем с тем приходом который распроводите было все нормально, контроль остатков проходил.
Без него при правильной последовательности тоже все нормально. А вот несоблюдение порядка не дает распровести документ.
8. ZLENKO 398 15.04.15 14:06 Сейчас в теме
(5) MiniMuk, "получить остатки по регистру по всей номенклатуре на дату время каждого документа, помоему на любой приличной базе с движениями за пару лет он просто умрет"

Где я написал что надо по всей номенклатуре получать остатки ? Я реализовывал "сложный" вариант контроля, который ВСЕГДА корректно и достаточно быстро работает на достаточно объемных базах (~350-400 Гб за 5 лет), но необходимо было внести ряд изменений в проведение документов (например, не нужно очищать регистр остатков при перепроведении). Автор спрашивал про "малой кровью" - я написал что не получится чтобы во всех ситуациях работало правильно.
6. spezc 793 15.04.15 14:00 Сейчас в теме
(4) так все-таки на какую дату? на дату документа? на текущую дату?
9. ZLENKO 398 15.04.15 14:11 Сейчас в теме
(6) spezc, "так все-таки на какую дату? на дату документа? на текущую дату?"

Какой смысл в контроле остатков на дату отменяемого прихода ? Ведь все возможные расходы были после него :-)
12. yurowski 33 15.04.15 14:21 Сейчас в теме
(6) spezc, остатки на дату дока и оперативные. (7) spezc, Комплексная автоматизация, редакция 1.1 + CRM, редакция 1.4 (1.1.55/1.4.9)
7. spezc 793 15.04.15 14:06 Сейчас в теме
10. spezc 793 15.04.15 14:11 Сейчас в теме
1. Перед записью документа в дополнительные свойства помещается таблица товаров существующая в базе.
2. В подписках "ОбработкаПроведения" и "ОбработкаУдаленияПроведения" получаете таблицу товаров из п.1 и таблицу товаров из Источника. Объединяете и выполняете по ней запрос к ИБ.
3. Профит
11. ZLENKO 398 15.04.15 14:18 Сейчас в теме
В модуль регистра накопления можно запихнуть такое:
(ВАЖНО: регистр не должен очищаться при перепроведении)

Перем мПериод          Экспорт; // Период движений
Перем мТаблицаДвижений Экспорт; // Таблица движений
// Переменные, используемые в процедурах контроля остатков
Перем МетаданныеДокумента, МетаданныеТабЧасти, ИмяДокумента, ИмяТабличнойЧасти, ИмяТаблицы, Заголовок, СтруктураШапкиДокумента, Отказ; 
Перем ИспользоватьУказаниеСерийНоменклатурыПриРезервировании;

//Z+ 20120303
// таблица движений из базы до записи набора
Перем мТаблицаДвиженийПередЗаписью Экспорт; 
Перем мРегистратор Экспорт; 
Перем мТипЗнчРегистратор Экспорт; 
//Z- 20120303

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

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

Процедура ПриЗаписи(Отказ, Замещение)
	
	//Z+ 20120303
	Если ОбменДанными.Загрузка  Тогда
		Возврат;
	КонецЕсли;		
	
	НаборЗаписей = ЭтотОбъект;
	
	мТаблицаДвиженийПриЗаписи = ЭтотОбъект.Выгрузить();	
	мТаблицаДвиженийПередЗаписьюПриЗаписи = мТаблицаДвиженийПриЗаписи.Скопировать();		
	УправлениеПланированием.ДополнитьТаблицу(мТаблицаДвиженийПередЗаписьюПриЗаписи, мТаблицаДвиженийПередЗаписью);		
	
	мТаблицаДвиженийСклад 						= мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
	мТаблицаДвиженийСклад.Свернуть("Склад");
	
	мТаблицаДвиженийНоменклатура 				= мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
	мТаблицаДвиженийНоменклатура.Свернуть("Номенклатура");	
	
	мТаблицаДвиженийХарактеристикаНоменклатуры 	= мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
	мТаблицаДвиженийХарактеристикаНоменклатуры.Свернуть("ХарактеристикаНоменклатуры");		
	
	мТаблицаДвиженийСерияНоменклатуры 			= мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
	мТаблицаДвиженийСерияНоменклатуры.Свернуть("СерияНоменклатуры");	
	
	мТаблицаДвиженийКачество 					= мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
	мТаблицаДвиженийКачество.Свернуть("Качество");		
	
	ПериодСтарый = Неопределено;
	ПериодНовый = Неопределено;	
	
	Для каждого ТекСтрока Из мТаблицаДвиженийПередЗаписью Цикл
		ПериодСтарый = ТекСтрока.Период;
	КонецЦикла;
	
	Для каждого ТекСтрока Из мТаблицаДвиженийПриЗаписи Цикл
		ПериодНовый = ТекСтрока.Период;	
	КонецЦикла;
	
	//сравним старый момент времени движений и новый
	Если ПериодСтарый = Неопределено Тогда
		//старый момент времени отсутствует			
		Если ПериодНовый = Неопределено Тогда
			//новый момент времени тоже отсутствует
			Возврат;
		Иначе 
			ПериодДвижений = ПериодНовый;				
		КонецЕсли;
	Иначе	
		Если ПериодНовый = Неопределено Тогда
			//есть только старый момент времени
			ПериодДвижений = ПериодСтарый;				
		Иначе 
			//сравним периоды
			Если ПериодСтарый < ПериодНовый Тогда
				ПериодДвижений = ПериодСтарый;
			Иначе
				ПериодДвижений = ПериодНовый;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Запрос = Новый Запрос;		
	Запрос.Текст = "ВЫБРАТЬ
	|	ТоварыНаСкладахОстаткиИОбороты.Регистратор КАК Регистратор,
	|	ТоварыНаСкладахОстаткиИОбороты.Склад КАК Склад,
	|	ТоварыНаСкладахОстаткиИОбороты.Номенклатура.Код КАК Код,	
	|	ТоварыНаСкладахОстаткиИОбороты.Номенклатура.Артикул КАК Артикул,
	|	ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
	|	ТоварыНаСкладахОстаткиИОбороты.Качество КАК Качество,
	|	ТоварыНаСкладахОстаткиИОбороты.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
	|	ТоварыНаСкладахОстаткиИОбороты.СерияНоменклатуры КАК СерияНоменклатуры,
	|	ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
	|ИЗ
	|	РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
	|			&ДатаНач,
	|			,
	|			Регистратор,
	|			Движения,
	|			Склад В (&ТаблицаСклад)
	|				И Номенклатура В (&ТаблицаНоменклатура)
	|				И Качество В (&ТаблицаКачество)
	|				И ХарактеристикаНоменклатуры В (&ТаблицаХарактеристикаНоменклатуры)
	|				И СерияНоменклатуры В (&ТаблицаСерияНоменклатуры)) КАК ТоварыНаСкладахОстаткиИОбороты
	|ГДЕ
	|	ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток < 0
	|
	|УПОРЯДОЧИТЬ ПО
	|	Регистратор";						   
	
	Запрос.УстановитьПараметр("ТаблицаСклад", мТаблицаДвиженийСклад.ВыгрузитьКолонку("Склад"));
	Запрос.УстановитьПараметр("ТаблицаНоменклатура", мТаблицаДвиженийНоменклатура.ВыгрузитьКолонку("Номенклатура"));
	Запрос.УстановитьПараметр("ТаблицаХарактеристикаНоменклатуры", мТаблицаДвиженийХарактеристикаНоменклатуры.ВыгрузитьКолонку("ХарактеристикаНоменклатуры"));
	Запрос.УстановитьПараметр("ТаблицаСерияНоменклатуры", мТаблицаДвиженийСерияНоменклатуры.ВыгрузитьКолонку("СерияНоменклатуры"));
	Запрос.УстановитьПараметр("ТаблицаКачество", мТаблицаДвиженийКачество.ВыгрузитьКолонку("Качество"));
	Запрос.УстановитьПараметр("ДатаНач", Новый Граница(ПериодДвижений, ВидГраницы.Включая));
	
	ТаблицаМинусовыхОстатков = Запрос.Выполнить().Выгрузить();
	
	ОстанавливатьПроведение = Истина;
	
	//Если РольДоступна("ПолныеПраваРасширенные")	ИЛИ мТипЗнчРегистратор = Тип("ДокументСсылка.ОтчетОРозничныхПродажах") Тогда
	//	//для полных прав и "Отчета РП" не запрещаем проведение
	//	ОстанавливатьПроведение = Ложь;
	//КонецЕсли;
	
	Для каждого ТекСтрока Из ТаблицаМинусовыхОстатков Цикл
		Заголовок = "Регистр ""ТоварыНаСкладах"". Отрицательный остаток по документу " + ТекСтрока.Регистратор;
		ТекстСообщения = "" + ТекСтрока.КоличествоКонечныйОстаток + " Склад: " + ТекСтрока.Склад + ", Код: " + ТекСтрока.Код+ ", Артикул: " + ТекСтрока.Артикул + ", Номенклатура: " + ТекСтрока.Номенклатура +  ", Характеристика: " + ТекСтрока.ХарактеристикаНоменклатуры + ", Серия: " + ТекСтрока.СерияНоменклатуры + ", Качество: " + ТекСтрока.Качество + ";";
		ОтборСтрок = Новый Структура();
		ОтборСтрок.Вставить("ВидДвижения",ВидДвиженияНакопления.Приход);
		ОтборСтрок.Вставить("Склад",ТекСтрока.Склад);
		ОтборСтрок.Вставить("Номенклатура",ТекСтрока.Номенклатура);
		ОтборСтрок.Вставить("Качество",ТекСтрока.Качество);
		ОтборСтрок.Вставить("ХарактеристикаНоменклатуры",ТекСтрока.ХарактеристикаНоменклатуры);
		ОтборСтрок.Вставить("СерияНоменклатуры",ТекСтрока.СерияНоменклатуры);
		
		Строки = мТаблицаДвиженийПриЗаписи.НайтиСтроки(ОтборСтрок);
		
		ВидДвиженияНакопленияПриход = Ложь;
		Если Строки.Количество() > 0 Тогда
			ВидДвиженияНакопленияПриход = Истина;
		КонецЕсли;
		Если ОстанавливатьПроведение И НЕ ВидДвиженияНакопленияПриход Тогда	
			ОбщегоНазначения.СообщитьОбОшибке(ТекстСообщения, Отказ, Заголовок); 	
		Иначе
			ОбщегоНазначения.СообщитьИнформациюПользователю(Заголовок + Символы.ПС 
			+ ТекстСообщения);
		КонецЕсли;
	КонецЦикла; 
	//Z- 20120303
	
КонецПроцедуры
Показать
kraynev-navi; +1 Ответить
24. ZLENKO 398 15.04.15 14:59 Сейчас в теме
Код в (11) не особо "красивый" но зато работоспособный. Если бы не надо было сильно типовую "курочить" то "причесал" бы выложил на ИС в качестве готового решения, а так слишком много ньюансов.

Можно конечно "тупой" вариант проверки в самом документе после проведения на минуса по всем товарам и складам, но это реально будет тормозить, хотя для мелких баз вполне жить будет :-)
13. ZLENKO 398 15.04.15 14:27 Сейчас в теме
У документов свойство "Удалять движения" должно быть "Не удалять автоматически"

Процедура УдалитьДвиженияРегистратора(ДокументОбъект, Отказ, ВыборочноОчищатьРегистры = Ложь, РежимПроведенияДокумента = Неопределено)

Вызывать процедуру УдалитьДвиженияРегистратора с ВыборочноОчищатьРегистры = Истина и нужный регистр не должен очищаться.

Список регистров формируется в Функция ПолучитьРегистрыДляОптимизацииПерезаписиДвижений(ТекущийРежимПроведенияДокумента)
yurowski; +1 Ответить
14. spezc 793 15.04.15 14:30 Сейчас в теме
16. ZLENKO 398 15.04.15 14:36 Сейчас в теме
(14) spezc,

Затем чтобы при перепроведении был доступен старый набор движений и новый набор для получения набора значений измерений регистра для контроля. Для того чтобы не контролировать по всем складам/товарам, а только по тем которые были/есть в документе.
18. ZLENKO 398 15.04.15 14:45 Сейчас в теме
(14) spezc,

В случае принудительной очистки движений при перепроведении (регистр записывается несколько раз) появляется проблема что непонятно какой именно из наборов был предыдущим и непонятно надо ли при этом контролировать остаток (при принудительной очистке регистра в процессе перепроведения не надо контролировать возникновение отрицательного остатка)
19. yurowski 33 15.04.15 14:46 Сейчас в теме
(13) ZLENKO, Спасибо. Сейчас протестирую.
23. yurowski 33 15.04.15 14:56 Сейчас в теме
(13) ZLENKO, я в модуль регистра добавил ваш код. ошибок нет. у дока поступления ТУ стоит - не удалять движения. Но при отмене проведения выполнение не попадает в при и после записи регистра. Что ещё нужно было сделать? Наврал.
25. ZLENKO 398 15.04.15 15:02 Сейчас в теме
(23) yurowski, "Но при отмене проведения выполнение не попадает в при и после записи регистра."

У вас в модуле документа есть такое ?


Процедура ОбработкаУдаленияПроведения(Отказ)

ОбщегоНазначения.УдалитьДвиженияРегистратора(ЭтотОбъект, Отказ);

КонецПроцедуры
27. yurowski 33 15.04.15 15:15 Сейчас в теме
29. ZLENKO 398 15.04.15 15:19 Сейчас в теме
(27) yurowski, "нет"

Если движения документа не очищаются автоматически платформой, то они должны очищаться кодом.
Может быть у вас это через обработчик событий документа происходит.
15. ZLENKO 398 15.04.15 14:33 Сейчас в теме
В моем варианте контроля возникновение отрицательных остатков проверяется не за весь период, а начиная с даты проводимого (или перепроводимого) документа. Для варианта изменения существующего документа необходим набор измерений регистра как до изменения так и после изменения, поэтому регистр не должен принудительно очищаться. В типовых конфигурациях регистры остатков принудительно очищаются для того чтобы корректно работал типовой контроль остатков. В данном случае от типового можно отказаться, заменив его на свой контроль по "новой методике" контроля остатков.
17. spezc 793 15.04.15 14:41 Сейчас в теме
(15) вариант неплохой, но мне кажется избыточный. для более менее большой базы это будет близко к "смерти подобно". имхо достаточно проверять на текущую дату. и проверять по таблице товаров до записи и во время.
20. ZLENKO 398 15.04.15 14:48 Сейчас в теме
(17) spezc, "но мне кажется избыточный. для более менее большой базы это будет близко к "смерти подобно". имхо"

Вам "кажется", а у меня работает :-) База продуктового супермаркета 400 Гб за 5 лет достаточно большая ? :-)
21. spezc 793 15.04.15 14:49 Сейчас в теме
22. ZLENKO 398 15.04.15 14:51 Сейчас в теме
(17) spezc, "достаточно проверять на текущую дату. и проверять по таблице товаров до записи и во время."

Ну во первых на текущую дату не достаточно проверять, т.к. итогового минуса может и не возникнуть, но и не надо проверять за весь период, а достаточно только с детализацией до регистратора начиная с даты документа до текущей даты.
26. ZLENKO 398 15.04.15 15:10 Сейчас в теме
Проведение и отмена проведения - простые случаи, т.к. просто записывается набор записей регистра(заполненный или пустой).
А вот при перепроведении набор записей перезаписывается и надо контролировать возникновение минуса и по старому набору записей и по новому набору записей (поменяли товарный состав, поменяли склад в документе, поменяли дату документа)
28. ZLENKO 398 15.04.15 15:16 Сейчас в теме
А есть еще интересная ситуация когда при попытке проведения возникла ошибка и документ не провелся, но движения документа заполнились, а потом пользователь нажимает просто "Записать" (без проведения), но движения записываются...
В результате получаем непроведенный документ с движениями :-)
30. ZLENKO 398 15.04.15 15:29 Сейчас в теме
Для того чтобы такой контроль минимально сказывался на производительности база должна быть в режиме управляемых блокировок.
31. ZLENKO 398 15.04.15 15:51 Сейчас в теме
Если будут вопросы - пишите в скайп: zlenko.pro
yurowski; +1 Ответить
32. yurowski 33 15.04.15 16:22 Сейчас в теме
(31) ZLENKO, всё получилось, только я для контроля остатков организации сделал. Спасибо вам большое!
33. ZLENKO 398 15.04.15 17:09 Сейчас в теме
(32) yurowski, "всё получилось"

Хорошо :-) Рад был помочь :-)
yurowski; +1 Ответить
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот