← Назад к вопросам
Вычисление количества дней товаров на складе
1.8 Middle🔥 131 комментариев
#Запросы и оптимизация
Условие
Напишите запрос или обработку для вычисления количества дней нахождения товаров на складе.
Требования:
- Для каждого товара определить дату последнего поступления
- Рассчитать количество дней от поступления до текущей даты
- Выделить товары, которые лежат на складе более 90 дней
Пример результата
| Товар | Дата поступления | Дней на складе | Статус |
|---|---|---|---|
| Товар 1 | 01.09.2024 | 120 | Залежалый |
| Товар 2 | 15.11.2024 | 45 | Норма |
| Товар 3 | 01.10.2024 | 90 | Критично |
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Вычисление дней товаров на складе
Решение с использованием регистра движения товаров
Функция ПолучитьДолгоЛежащиеТовары(ДатаОтчета, Склад = Неопределено)
Запрос = Новый Запрос();
Запрос.Текст =
"ВЫБРАТЬ
| МахДокумент.Товар,
| Номенклатура.Наименование КАК ТоварНаименование,
| МахДокумент.ДатаПоступления,
| РАЗНОСТЬДАТ(МахДокумент.ДатаПоступления, &ДатаОтчета, ДЕНЬ) КАК ДнейНаСкладе,
| СЛУЧАЙ
| КОГДА РАЗНОСТЬДАТ(МахДокумент.ДатаПоступления, &ДатаОтчета, ДЕНЬ) > 90
| ТОГДА \"Залежалый\"
| КОГДА РАЗНОСТЬДАТ(МахДокумент.ДатаПоступления, &ДатаОтчета, ДЕНЬ) = 90
| ТОГДА \"Критично\"
| ИНАЧЕ \"Норма\"
| КОНЕЦ КАК Статус
|ИЗ
| (ВЫБРАТЬ
| ДвижениеТоваров.Товар,
| МАКСИМУМ(ДвижениеТоваров.Период) КАК ДатаПоступления
| ИЗ РегистрНакопления.ДвижениеТоваров КАК ДвижениеТоваров
| ГДЕ ДвижениеТоваров.ВидДвижения = ЗНАЧЕНИЕ(Перечисления.ВидДвижения.Поступление)";
Если ЗначениеЗаполнено(Склад) Тогда
Запрос.Текст = Запрос.Текст + " И ДвижениеТоваров.Склад = &Склад";
КонецЕсли;
Запрос.Текст = Запрос.Текст +
" ГРУППИРОВАТЬ ПО
| ДвижениеТоваров.Товар
| ) КАК МахДокумент
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО МахДокумент.Товар = Номенклатура.Ссылка
|ГДЕ РАЗНОСТЬДАТ(МахДокумент.ДатаПоступления, &ДатаОтчета, ДЕНЬ) >= 90
|УПОРЯДОЧИТЬ ПО
| ДнейНаСкладе УБЫВ";
Запрос.УстановитьПараметр("ДатаОтчета", ДатаОтчета);
Если ЗначениеЗаполнено(Склад) Тогда
Запрос.УстановитьПараметр("Склад", Склад);
КонецЕсли;
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецФункции
Ключевые функции:
РАЗНОСТЬДАТ()— вычисляет разницу между датами в дняхМАКСИМУМ()— находит последнюю дату поступленияСЛУЧАЙ/КОГДА— определяет статус товара- Подзапрос находит последнее поступление для каждого товара
Более точный вариант с реальными документами поступления
Функция ПолучитьТоварыСоДняхНаСкладе(ДатаОтчета, Склад = Неопределено)
Запрос = Новый Запрос();
Запрос.Текст =
"ВЫБРАТЬ
| ПриходНоменклатура.Номенклатура,
| Номенклатура.Наименование,
| МАКСИМУМ(ПриходНоменклатура.ДатаДокумента) КАК ДатаПоступления,
| РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) КАК ДнейНаСкладе,
| СУММА(ПриходНоменклатура.Количество) КАК КоличествоНаСкладе,
| СЛУЧАЙ
| КОГДА РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) > 90
| ТОГДА \"Залежалый\"
| КОГДА РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) = 90
| ТОГДА \"Критично\"
| ИНАЧЕ \"Норма\"
| КОНЕЦ КАК Статус
|ИЗ Документ.ПриходТовара.Товары КАК ПриходНоменклатура
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ПриходНоменклатура.Номенклатура = Номенклатура.Ссылка
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.ПриходТовара КАК ПриходДокумент
| ПО ПриходНоменклатура.Ссылка = ПриходДокумент.Ссылка
| И ПриходДокумент.Проведен = ИСТИНА
|ГДЕ ПриходНоменклатура.ДатаДокумента <= &ДатаОтчета";
Если ЗначениеЗаполнено(Склад) Тогда
Запрос.Текст = Запрос.Текст + " И ПриходДокумент.Склад = &Склад";
КонецЕсли;
Запрос.Текст = Запрос.Текст +
" ГРУППИРОВАТЬ ПО
| ПриходНоменклатура.Номенклатура,
| Номенклатура.Наименование
| ИМЕЮЩИЕ РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) >= 90
| УПОРЯДОЧИТЬ ПО
| ДнейНаСкладе УБЫВ";
Запрос.УстановитьПараметр("ДатаОтчета", ДатаОтчета);
Если ЗначениеЗаполнено(Склад) Тогда
Запрос.УстановитьПараметр("Склад", Склад);
КонецЕсли;
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецФункции
Вариант с учётом остатков (более точный)
Функция ПолучитьТоварыСОстаткамиНаСкладе(ДатаОтчета, Склад)
// Получаем остатки товаров на складе
Запрос = Новый Запрос();
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиИОбороты.Товар,
| ОстаткиИОбороты.Номенклатура,
| ОстаткиИОбороты.ОстатокНаКонецПериода КАК ОстатокТовара,
| МАКСИМУМ(ПриходНоменклатура.ДатаДокумента) КАК ДатаПоследнегоПоступления,
| РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) КАК ДнейНаСкладе
|ИЗ
| (ВЫБРАТЬ
| ДвижениеТоваров.Товар,
| Номенклатура.Наименование КАК Номенклатура,
| СУММА(СЛУЧАЙ
| КОГДА ДвижениеТоваров.ВидДвижения = ЗНАЧЕНИЕ(Перечисления.ВидДвижения.Поступление)
| ТОГДА ДвижениеТоваров.КоличествоПриход
| ИНАЧЕ -ДвижениеТоваров.КоличествоРасход
| КОНЕЦ) КАК ОстатокНаКонецПериода
| ИЗ РегистрНакопления.ДвижениеТоваров КАК ДвижениеТоваров
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ДвижениеТоваров.Товар = Номенклатура.Ссылка
| ГДЕ ДвижениеТоваров.Склад = &Склад
| И ДвижениеТоваров.Период <= &ДатаОтчета
| ГРУППИРОВАТЬ ПО
| ДвижениеТоваров.Товар,
| Номенклатура.Наименование
| ИМЕЮЩИЕ СУММА(СЛУЧАЙ
| КОГДА ДвижениеТоваров.ВидДвижения = ЗНАЧЕНИЕ(Перечисления.ВидДвижения.Поступление)
| ТОГДА ДвижениеТоваров.КоличествоПриход
| ИНАЧЕ -ДвижениеТоваров.КоличествоРасход
| КОНЕЦ) > 0
| ) КАК ОстаткиИОбороты
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриходТовара.Товары КАК ПриходНоменклатура
| ПО ОстаткиИОбороты.Товар = ПриходНоменклатура.Номенклатура
| И ПриходНоменклатура.ДатаДокумента <= &ДатаОтчета
|ГРУППИРОВАТЬ ПО
| ОстаткиИОбороты.Товар,
| ОстаткиИОбороты.Номенклатура,
| ОстаткиИОбороты.ОстатокНаКонецПериода
|ИМЕЮЩИЕ
| ОстаткиИОбороты.ОстатокНаКонецПериода > 0
| И РАЗНОСТЬДАТ(МАКСИМУМ(ПриходНоменклатура.ДатаДокумента), &ДатаОтчета, ДЕНЬ) >= 90
|УПОРЯДОЧИТЬ ПО
| ДнейНаСкладе УБЫВ";
Запрос.УстановитьПараметр("ДатаОтчета", ДатаОтчета);
Запрос.УстановитьПараметр("Склад", Склад);
Результат = Запрос.Выполнить();
Возврат Результат.Выгрузить();
КонецФункции
Обработка для анализа залежей
Процедура ПроанализироватьЗалежиТовара(ДатаОтчета, Склад)
Таблица = ПолучитьТоварыСОстаткамиНаСкладе(ДатаОтчета, Склад);
КритическиеТовары = Новый Массив();
ЗалежалыеТовары = Новый Массив();
Для Каждого Строка Из Таблица Цикл
Если Строка.ДнейНаСкладе > 90 Тогда
ЗалежалыеТовары.Добавить(Строка);
ИначеЕсли Строка.ДнейНаСкладе = 90 Тогда
КритическиеТовары.Добавить(Строка);
КонецЕсли;
КонецЦикла;
СообщитьОСтатистике(ЗалежалыеТовары, КритическиеТовары);
КонецПроцедуры
Процедура СообщитьОСтатистике(ЗалежалыеТовары, КритическиеТовары)
Текст = "Товары на складе свыше 90 дней: " + ЗалежалыеТовары.Количество() + ОК;
Для Каждого Товар Из ЗалежалыеТовары Цикл
Текст = Текст + Товар.Номенклатура + " - " + Товар.ДнейНаСкладе + " дней\n";
КонецЦикла;
Сообщить(Текст);
КонецПроцедуры
Оптимизация для больших объёмов
// Используем ВРЕМЕННУЮ ТАБЛИЦУ для кэширования результатов
Процедура РассчитатьИКэшироватьДанные(ДатаОтчета, Склад)
Запрос = Новый Запрос();
Запрос.Текст =
"ВЫБРАТЬ
| ТекущаяДата() КАК ДатаРасчета,
| ДанныеТовара.Товар,
| ДанныеТовара.Наименование,
| ДанныеТовара.ДатаПоступления,
| ДанныеТовара.ДнейНаСкладе,
| ДанныеТовара.Статус
|ПОМЕСТИТЬ ДолгоЛежащиеТовары
|ИЗ (ВЫБРАТЬ ... ) КАК ДанныеТовара;
"""SELECT INTO таблица для быстрого доступа
Запрос.Выполнить();
КонецПроцедуры
Ключевые моменты
- РАЗНОСТЬДАТ() — основная функция для расчёта дней
- МАКСИМУМ() — находит последнее поступление
- ИМЕЮЩИЕ — фильтрует по условиям после группировки
- ВНУТРЕННЕЕ СОЕДИНЕНИЕ — гарантирует наличие данных
- Кэширование — ускоряет работу при частых вызовах