По теме из базы знаний
- Исправление отрицательных остатков по организациям в УТ 11.4, КА 2.4, ЕРП 2.4. Интеркампани, механизм формирования резервов
- Дополнение к контролю остатков
- На время отключаем контроль остатков и проверку документов
- Комплексный контроль остатков. Для одного или сразу нескольких логически связанных регистров накопления. Универсальное решение уровня данных для контроля не только складских остатков
- Контроль заполнения субконто
Ответы
Подписаться на ответы
Инфостарт бот
Сортировка:
Древо развёрнутое
Свернуть все
Написать запрос, проверяющий возникновение отрицательных остатков по регистру при отмене проведения :-)
Но чтобы корректно работало во всех случаях (например, при изменении состава документа), то малой кровью не получится :-(
Но чтобы корректно работало во всех случаях (например, при изменении состава документа), то малой кровью не получится :-(
(4) ZLENKO, получить остатки по регистру по всей номенклатуре на дату время каждого документа, помоему на любой приличной базе с движениями за пару лет он просто умрет.
Причем может получиться наприме так что отменяете приход например где на приход ставиться 100 карандашей. а через год у вас случается ситуация когда на остатках на начало дня остается 1 карандаш. Утром вы списываете 2 карандаша, а вечером приходуете 5! Причем с тем приходом который распроводите было все нормально, контроль остатков проходил.
Без него при правильной последовательности тоже все нормально. А вот несоблюдение порядка не дает распровести документ.
Причем может получиться наприме так что отменяете приход например где на приход ставиться 100 карандашей. а через год у вас случается ситуация когда на остатках на начало дня остается 1 карандаш. Утром вы списываете 2 карандаша, а вечером приходуете 5! Причем с тем приходом который распроводите было все нормально, контроль остатков проходил.
Без него при правильной последовательности тоже все нормально. А вот несоблюдение порядка не дает распровести документ.
(5) MiniMuk, "получить остатки по регистру по всей номенклатуре на дату время каждого документа, помоему на любой приличной базе с движениями за пару лет он просто умрет"
Где я написал что надо по всей номенклатуре получать остатки ? Я реализовывал "сложный" вариант контроля, который ВСЕГДА корректно и достаточно быстро работает на достаточно объемных базах (~350-400 Гб за 5 лет), но необходимо было внести ряд изменений в проведение документов (например, не нужно очищать регистр остатков при перепроведении). Автор спрашивал про "малой кровью" - я написал что не получится чтобы во всех ситуациях работало правильно.
Где я написал что надо по всей номенклатуре получать остатки ? Я реализовывал "сложный" вариант контроля, который ВСЕГДА корректно и достаточно быстро работает на достаточно объемных базах (~350-400 Гб за 5 лет), но необходимо было внести ряд изменений в проведение документов (например, не нужно очищать регистр остатков при перепроведении). Автор спрашивал про "малой кровью" - я написал что не получится чтобы во всех ситуациях работало правильно.
1. Перед записью документа в дополнительные свойства помещается таблица товаров существующая в базе.
2. В подписках "ОбработкаПроведения" и "ОбработкаУдаленияПроведения" получаете таблицу товаров из п.1 и таблицу товаров из Источника. Объединяете и выполняете по ней запрос к ИБ.
3. Профит
2. В подписках "ОбработкаПроведения" и "ОбработкаУдаленияПроведения" получаете таблицу товаров из п.1 и таблицу товаров из Источника. Объединяете и выполняете по ней запрос к ИБ.
3. Профит
В модуль регистра накопления можно запихнуть такое:
(ВАЖНО: регистр не должен очищаться при перепроведении)
(ВАЖНО: регистр не должен очищаться при перепроведении)
Перем мПериод Экспорт; // Период движений
Перем мТаблицаДвижений Экспорт; // Таблица движений
// Переменные, используемые в процедурах контроля остатков
Перем МетаданныеДокумента, МетаданныеТабЧасти, ИмяДокумента, ИмяТабличнойЧасти, ИмяТаблицы, Заголовок, СтруктураШапкиДокумента, Отказ;
Перем ИспользоватьУказаниеСерийНоменклатурыПриРезервировании;
//Z+ 20120303
// таблица движений из базы до записи набора
Перем мТаблицаДвиженийПередЗаписью Экспорт;
Перем мРегистратор Экспорт;
Перем мТипЗнчРегистратор Экспорт;
//Z- 20120303
Процедура ПередЗаписью(Отказ, Замещение)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если НЕ ОбменДанными.Загрузка Тогда
ОбщегоНазначения.ВыполнитьДвиженияПоРегиструСвободныеОстатки(ЭтотОбъект, Отбор.Регистратор.Значение, Замещение, Перечисления.ВидыРегистровОснованийРегистраСвободныеОстатки.ТоварыНаСкладах, Отказ);
КонецЕсли;
//мРегистратор = ЭтотОбъект.Отбор.Регистратор.Значение;
//мТипЗнчРегистратор = типЗнч(мРегистратор);
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладах.Период,
| ТоварыНаСкладах.Склад,
| ТоварыНаСкладах.Номенклатура,
| ТоварыНаСкладах.ХарактеристикаНоменклатуры,
| ТоварыНаСкладах.СерияНоменклатуры,
| ТоварыНаСкладах.Качество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
|ГДЕ
| ТоварыНаСкладах.Регистратор = &Регистратор";
Запрос.УстановитьПараметр("Регистратор", мРегистратор);
мТаблицаДвиженийПередЗаписью = Запрос.Выполнить().Выгрузить();
//Z- 20120303
КонецПроцедуры
Процедура ПриЗаписи(Отказ, Замещение)
//Z+ 20120303
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
НаборЗаписей = ЭтотОбъект;
мТаблицаДвиженийПриЗаписи = ЭтотОбъект.Выгрузить();
мТаблицаДвиженийПередЗаписьюПриЗаписи = мТаблицаДвиженийПриЗаписи.Скопировать();
УправлениеПланированием.ДополнитьТаблицу(мТаблицаДвиженийПередЗаписьюПриЗаписи, мТаблицаДвиженийПередЗаписью);
мТаблицаДвиженийСклад = мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
мТаблицаДвиженийСклад.Свернуть("Склад");
мТаблицаДвиженийНоменклатура = мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
мТаблицаДвиженийНоменклатура.Свернуть("Номенклатура");
мТаблицаДвиженийХарактеристикаНоменклатуры = мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
мТаблицаДвиженийХарактеристикаНоменклатуры.Свернуть("ХарактеристикаНоменклатуры");
мТаблицаДвиженийСерияНоменклатуры = мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
мТаблицаДвиженийСерияНоменклатуры.Свернуть("СерияНоменклатуры");
мТаблицаДвиженийКачество = мТаблицаДвиженийПередЗаписьюПриЗаписи.Скопировать();
мТаблицаДвиженийКачество.Свернуть("Качество");
ПериодСтарый = Неопределено;
ПериодНовый = Неопределено;
Для каждого ТекСтрока Из мТаблицаДвиженийПередЗаписью Цикл
ПериодСтарый = ТекСтрока.Период;
КонецЦикла;
Для каждого ТекСтрока Из мТаблицаДвиженийПриЗаписи Цикл
ПериодНовый = ТекСтрока.Период;
КонецЦикла;
//сравним старый момент времени движений и новый
Если ПериодСтарый = Неопределено Тогда
//старый момент времени отсутствует
Если ПериодНовый = Неопределено Тогда
//новый момент времени тоже отсутствует
Возврат;
Иначе
ПериодДвижений = ПериодНовый;
КонецЕсли;
Иначе
Если ПериодНовый = Неопределено Тогда
//есть только старый момент времени
ПериодДвижений = ПериодСтарый;
Иначе
//сравним периоды
Если ПериодСтарый < ПериодНовый Тогда
ПериодДвижений = ПериодСтарый;
Иначе
ПериодДвижений = ПериодНовый;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладахОстаткиИОбороты.Регистратор КАК Регистратор,
| ТоварыНаСкладахОстаткиИОбороты.Склад КАК Склад,
| ТоварыНаСкладахОстаткиИОбороты.Номенклатура.Код КАК Код,
| ТоварыНаСкладахОстаткиИОбороты.Номенклатура.Артикул КАК Артикул,
| ТоварыНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстаткиИОбороты.Качество КАК Качество,
| ТоварыНаСкладахОстаткиИОбороты.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
| ТоварыНаСкладахОстаткиИОбороты.СерияНоменклатуры КАК СерияНоменклатуры,
| ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
| &ДатаНач,
| ,
| Регистратор,
| Движения,
| Склад В (&ТаблицаСклад)
| И Номенклатура В (&ТаблицаНоменклатура)
| И Качество В (&ТаблицаКачество)
| И ХарактеристикаНоменклатуры В (&ТаблицаХарактеристикаНоменклатуры)
| И СерияНоменклатуры В (&ТаблицаСерияНоменклатуры)) КАК ТоварыНаСкладахОстаткиИОбороты
|ГДЕ
| ТоварыНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток < 0
|
|УПОРЯДОЧИТЬ ПО
| Регистратор";
Запрос.УстановитьПараметр("ТаблицаСклад", мТаблицаДвиженийСклад.ВыгрузитьКолонку("Склад"));
Запрос.УстановитьПараметр("ТаблицаНоменклатура", мТаблицаДвиженийНоменклатура.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("ТаблицаХарактеристикаНоменклатуры", мТаблицаДвиженийХарактеристикаНоменклатуры.ВыгрузитьКолонку("ХарактеристикаНоменклатуры"));
Запрос.УстановитьПараметр("ТаблицаСерияНоменклатуры", мТаблицаДвиженийСерияНоменклатуры.ВыгрузитьКолонку("СерияНоменклатуры"));
Запрос.УстановитьПараметр("ТаблицаКачество", мТаблицаДвиженийКачество.ВыгрузитьКолонку("Качество"));
Запрос.УстановитьПараметр("ДатаНач", Новый Граница(ПериодДвижений, ВидГраницы.Включая));
ТаблицаМинусовыхОстатков = Запрос.Выполнить().Выгрузить();
ОстанавливатьПроведение = Истина;
//Если РольДоступна("ПолныеПраваРасширенные") ИЛИ мТипЗнчРегистратор = Тип("ДокументСсылка.ОтчетОРозничныхПродажах") Тогда
// //для полных прав и "Отчета РП" не запрещаем проведение
// ОстанавливатьПроведение = Ложь;
//КонецЕсли;
Для каждого ТекСтрока Из ТаблицаМинусовыхОстатков Цикл
Заголовок = "Регистр ""ТоварыНаСкладах"". Отрицательный остаток по документу " + ТекСтрока.Регистратор;
ТекстСообщения = "" + ТекСтрока.КоличествоКонечныйОстаток + " Склад: " + ТекСтрока.Склад + ", Код: " + ТекСтрока.Код+ ", Артикул: " + ТекСтрока.Артикул + ", Номенклатура: " + ТекСтрока.Номенклатура + ", Характеристика: " + ТекСтрока.ХарактеристикаНоменклатуры + ", Серия: " + ТекСтрока.СерияНоменклатуры + ", Качество: " + ТекСтрока.Качество + ";";
ОтборСтрок = Новый Структура();
ОтборСтрок.Вставить("ВидДвижения",ВидДвиженияНакопления.Приход);
ОтборСтрок.Вставить("Склад",ТекСтрока.Склад);
ОтборСтрок.Вставить("Номенклатура",ТекСтрока.Номенклатура);
ОтборСтрок.Вставить("Качество",ТекСтрока.Качество);
ОтборСтрок.Вставить("ХарактеристикаНоменклатуры",ТекСтрока.ХарактеристикаНоменклатуры);
ОтборСтрок.Вставить("СерияНоменклатуры",ТекСтрока.СерияНоменклатуры);
Строки = мТаблицаДвиженийПриЗаписи.НайтиСтроки(ОтборСтрок);
ВидДвиженияНакопленияПриход = Ложь;
Если Строки.Количество() > 0 Тогда
ВидДвиженияНакопленияПриход = Истина;
КонецЕсли;
Если ОстанавливатьПроведение И НЕ ВидДвиженияНакопленияПриход Тогда
ОбщегоНазначения.СообщитьОбОшибке(ТекстСообщения, Отказ, Заголовок);
Иначе
ОбщегоНазначения.СообщитьИнформациюПользователю(Заголовок + Символы.ПС
+ ТекстСообщения);
КонецЕсли;
КонецЦикла;
//Z- 20120303
КонецПроцедуры
Показать
Код в (11) не особо "красивый" но зато работоспособный. Если бы не надо было сильно типовую "курочить" то "причесал" бы выложил на ИС в качестве готового решения, а так слишком много ньюансов.
Можно конечно "тупой" вариант проверки в самом документе после проведения на минуса по всем товарам и складам, но это реально будет тормозить, хотя для мелких баз вполне жить будет :-)
Можно конечно "тупой" вариант проверки в самом документе после проведения на минуса по всем товарам и складам, но это реально будет тормозить, хотя для мелких баз вполне жить будет :-)
У документов свойство "Удалять движения" должно быть "Не удалять автоматически"
Процедура УдалитьДвиженияРегистратора(ДокументОбъект, Отказ, ВыборочноОчищатьРегистры = Ложь, РежимПроведенияДокумента = Неопределено)
Вызывать процедуру УдалитьДвиженияРегистратора с ВыборочноОчищатьРегистры = Истина и нужный регистр не должен очищаться.
Список регистров формируется в Функция ПолучитьРегистрыДляОптимизацииПерезаписиДвижений(ТекущийРежимПроведенияДокумента)
Процедура УдалитьДвиженияРегистратора(ДокументОбъект, Отказ, ВыборочноОчищатьРегистры = Ложь, РежимПроведенияДокумента = Неопределено)
Вызывать процедуру УдалитьДвиженияРегистратора с ВыборочноОчищатьРегистры = Истина и нужный регистр не должен очищаться.
Список регистров формируется в Функция ПолучитьРегистрыДляОптимизацииПерезаписиДвижений(ТекущийРежимПроведенияДокумента)
(14) spezc,
В случае принудительной очистки движений при перепроведении (регистр записывается несколько раз) появляется проблема что непонятно какой именно из наборов был предыдущим и непонятно надо ли при этом контролировать остаток (при принудительной очистке регистра в процессе перепроведения не надо контролировать возникновение отрицательного остатка)
В случае принудительной очистки движений при перепроведении (регистр записывается несколько раз) появляется проблема что непонятно какой именно из наборов был предыдущим и непонятно надо ли при этом контролировать остаток (при принудительной очистке регистра в процессе перепроведения не надо контролировать возникновение отрицательного остатка)
В моем варианте контроля возникновение отрицательных остатков проверяется не за весь период, а начиная с даты проводимого (или перепроводимого) документа. Для варианта изменения существующего документа необходим набор измерений регистра как до изменения так и после изменения, поэтому регистр не должен принудительно очищаться. В типовых конфигурациях регистры остатков принудительно очищаются для того чтобы корректно работал типовой контроль остатков. В данном случае от типового можно отказаться, заменив его на свой контроль по "новой методике" контроля остатков.
(17) spezc, "достаточно проверять на текущую дату. и проверять по таблице товаров до записи и во время."
Ну во первых на текущую дату не достаточно проверять, т.к. итогового минуса может и не возникнуть, но и не надо проверять за весь период, а достаточно только с детализацией до регистратора начиная с даты документа до текущей даты.
Ну во первых на текущую дату не достаточно проверять, т.к. итогового минуса может и не возникнуть, но и не надо проверять за весь период, а достаточно только с детализацией до регистратора начиная с даты документа до текущей даты.
Проведение и отмена проведения - простые случаи, т.к. просто записывается набор записей регистра(заполненный или пустой).
А вот при перепроведении набор записей перезаписывается и надо контролировать возникновение минуса и по старому набору записей и по новому набору записей (поменяли товарный состав, поменяли склад в документе, поменяли дату документа)
А вот при перепроведении набор записей перезаписывается и надо контролировать возникновение минуса и по старому набору записей и по новому набору записей (поменяли товарный состав, поменяли склад в документе, поменяли дату документа)
А есть еще интересная ситуация когда при попытке проведения возникла ошибка и документ не провелся, но движения документа заполнились, а потом пользователь нажимает просто "Записать" (без проведения), но движения записываются...
В результате получаем непроведенный документ с движениями :-)
В результате получаем непроведенный документ с движениями :-)
Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот