Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
30 мая 2025, 10:46

Результат выполнения одного подзапроска как параметр ВиртТабл "Остатки" РегНакопл другого подзапроса ?

Автор oooo800, 27 мая 2025, 23:27

0 Пользователей и 1 гость просматривают эту тему.

oooo800

Самописная платформа, на УФ; платформа 8.3.27.1508.

Регистр накопления вида "Остатки" с 2 регистраторами (документами) : Приходная накладная и Списание в производство, которые, соответственно, делают приходные и расходные движения по регистру, оба содержат табличные части деталей - наименования и их количества.

Например, рассмотрим для одной детали:
Приходная накладная № 1 от 05.05.2025 - Деталь1 = 10 шт.
Приходная накладная № 2 от 07.05.2025 - Деталь1 = 5 шт.
Списание в производство № 1 от 10.05.2025 г. - Деталь1 = 13 шт.
Приходная накладная № 3 от 11.05.2025 - Деталь1 = 8 шт.
больше документов Списания в производство нет.


Для избежания появления отрицательных остатков при отмене проведения Приходной накладной "задним числом" при уже проведенных Списаниях в производство, в модуле объекта, в обработчике "ОбработкаУдаленияПроведения" делаю проверку - то есть, если кто-то решил отменить проведение Приходной накладной № 3, да и ладно.
Но если, отменяется проведение Приходной накладной № 1 или № 2, тут оно должно быть выполнено только после соответствующей проверки.

Для этого:
1. в качестве параметра имеем ссылку на документ, проведение которого "Хочется" отменить;
2. для каждой детали из ТЧ этого документа отбираем самый ближайший к текущей дате документ Списания в производство с этой деталью, но дата которого должна быть после документа п. 1.
3. По каждому такому полученному в п. 2 документу берем дату и на эту дату + 1 секунда получаем остатки этой детали по регистру накопления.
4. Полученные в п. 3 остатки детали сверяем, по количеству, в документе, проведение которого отменяем.
5. если остатки п. 3 < количества детали п. 4, отмену проведения ЗАПРЕЩАЕМ !
Если остатки > , отменяем.


Для этого сделал первый «глобальный» запрос:
ВЫБРАТЬ
    |    ДеталиДокумент.Ссылка КАК ДетальСсылка,
    |    ДеталиДокумент.ДетальКод КАК ДетальКод
    |ПОМЕСТИТЬ ДеталиВременная
    |ИЗ
    |    Документ.ПриходнаяНакладная.ДеталиТЧ КАК ДеталиДокумент
    |ГДЕ
    |    ДеталиДокумент.Ссылка = &ДокументСсылка
    |
    |СГРУППИРОВАТЬ ПО
    |    ДеталиДокумент.Ссылка,
    |    ДеталиДокумент.ДетальКод
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    ДетальСсылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ ПЕРВЫЕ 1
    |    ДеталиВременная.ДетальСсылка КАК ДетальСсылка,
    |    ДеталиОстатки.Регистратор КАК Регистратор,
    |    ДеталиОстатки.Регистратор ССЫЛКА Документ.СписаниеПроизводствоИзделия КАК СписаниеПроизводствоИзделияСсылка,
    |    ДеталиОстатки.Регистратор.Дата > ДеталиВременная.ДетальСсылка.Дата КАК ДатаБольше
    |ИЗ
    |    ДеталиВременная КАК ДеталиВременная
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДеталиОстатки КАК ДеталиОстатки
    |        ПО ДеталиВременная.ДетальКод.Ссылка = ДеталиОстатки.Детали.Ссылка
    |
    |УПОРЯДОЧИТЬ ПО
    |    ДеталиОстатки.Регистратор.Дата УБЫВ

Параметром для которого является
&ДокументСсылка = ДокументСсылка.ПриходнаяНакладная, планируемая к отмене проведения:
Запрос.УстановитьПараметр("ДокументСсылка", ЭтотОбъект.Ссылка);

Результатом является «набор» документов – регистраторов Списание в производство для каждой детали из указанной Приходной накладной.

Далее в
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаДетали = РезультатЗапроса.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл

И, второй «глобальный» запрос:
ВЫБРАТЬ
        |    ДеталиДокумент.ДетальКод КАК ДетальКод,
        |    СУММА(ДеталиДокумент.Количество) КАК Количество
        |ПОМЕСТИТЬ ДеталиВременная
        |ИЗ
        |    Документ.ПриходнаяНакладная.ДеталиТЧ КАК ДеталиДокумент
        |ГДЕ
        |    ДеталиДокумент.Ссылка = &ДокументСсылка
        |
        |СГРУППИРОВАТЬ ПО
        |    ДеталиДокумент.ДетальКод
        |
        |ИНДЕКСИРОВАТЬ ПО
        |    ДетальКод
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |    ДеталиВременная.ДетальКод КАК ДетальКод,
        |    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДеталиВременная.ДетальКод.Наименование) КАК ДетальПредставлениеНаименование,
        |    ДеталиВременная.Количество КАК Количество,
        |    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток,
        |    Остатки.КоличествоОстаток < ДеталиВременная.Количество КАК РазницаОстатков
        |ИЗ
        |    ДеталиВременная КАК ДеталиВременная
        |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДеталиОстатки.Остатки(
        |                &МоментВремени,
        |                Детали В
        |                    (ВЫБРАТЬ
        |                        ДеталиВременная.ДетальКод КАК ДетальКод
        |                    ИЗ
        |                        ДеталиВременная КАК ДеталиВременная)) КАК Остатки
        |        ПО ДеталиВременная.ДетальКод = Остатки.Детали

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

Пробовал делать левое соединение 2 половины второго глобального запроса с 1 глобальным, но не знаю, как передать МоментВремени = МоментВремени Реистратора, полученного из запроса + 1 секунду в виртуальную таблицу регистра накопления «Остатки»


Такую ситуацию не считаю оптимальной с точки зрения быстродействия.
В связи с этим хотел уточнить у гуру, особенно в плане написания запросов: есть ли более оптимальный вариант запросов, может по другому расположить подзапросы или  они будут другие ?
Или может вообще, изменить все глобально, методику, подойти с другой стороны, с какой ?
Или просто оставить все, как есть, в смысле вариант:
    |ВЫБРАТЬ
        |    ДеталиВременная.ДетальКод КАК ДетальКод,
        |    ПРЕДСТАВЛЕНИЕССЫЛКИ(ДеталиВременная.ДетальКод.Наименование) КАК ДетальПредставлениеНаименование,
        |    ДеталиВременная.Количество КАК Количество,
        |    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток,
        |    Остатки.КоличествоОстаток < ДеталиВременная.Количество КАК РазницаОстатков
        |ИЗ
        |    ДеталиВременная КАК ДеталиВременная
        |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ДеталиОстатки.Остатки(
        |                &МоментВремени,
        |                Детали В
        |                    (ВЫБРАТЬ
        |                        ДеталиВременная.ДетальКод КАК ДетальКод
        |                    ИЗ
        |                        ДеталиВременная КАК ДеталиВременная)) КАК Остатки
        |        ПО ДеталиВременная.ДетальКод = Остатки.Детали
,
который «прицепить» к первому глобальному запросу, но как сюда передать нужный момент времени ?

antoneus

Не успел в личке ответить, потому что неправильно почти всё)

Цитата: oooo800 от 27 мая 2025, 23:27Результатом является «набор» документов – регистраторов Списание в производство для каждой детали из указанной Приходной накладной.

Проверял? Вообще-то, результатом второго запроса пакета будет один документ для какой-то одной детали.

Последние периоды можно собрать как-то типа так: выбрать деталь, максимум(период) из регистра с отбором по списку деталей и регистратор ссылка списание, положить во временную таблицу. Потом соединиться с виртуальной таблицей остатков и оборотов по деталь = деталь и последний период = период и получить конечный остаток. Одним запросом решается.

oooo800

Цитата: antoneus от 28 мая 2025, 07:05Проверял?


Более того, в таком виде, с 2-мя глобальными запросами работает.

У меня выведены сообщения, что для такой-то детали не может быть отмена документа.

"Забивал" несколько деталей в отменяемый приход, все отрабатывало.

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

Проверю еще раз.

oooo800

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

antoneus

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

ВЫБРАТЬ
"Деталь 1" КАК Деталь,
ДАТАВРЕМЯ(2025, 5, 1) КАК Дата
ПОМЕСТИТЬ ДеталиВременная

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
"Деталь 2",
ДАТАВРЕМЯ(2025, 5, 1)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
"Деталь 3",
ДАТАВРЕМЯ(2025, 5, 1)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
"Деталь 1" КАК Деталь,
"Документ 25" КАК Документ,
ДАТАВРЕМЯ(2025, 3, 1) КАК Дата
ПОМЕСТИТЬ ДеталиОстатки

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
"Деталь 1",
"Документ 44",
ДАТАВРЕМЯ(2025, 5, 18, 3, 15, 20)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
"Деталь 3",
"Документ 22",
ДАТАВРЕМЯ(2025, 2, 2, 2, 2, 2)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
"Деталь 3",
"Документ 34",
ДАТАВРЕМЯ(2025, 5, 22, 4, 20, 6)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ ПЕРВЫЕ 1
ДеталиВременная.Деталь КАК Деталь,
ЕСТЬNULL(ДеталиОстатки.Дата, ДАТАВРЕМЯ(1, 1, 1)) КАК Дата
ИЗ
ДеталиВременная КАК ДеталиВременная
ЛЕВОЕ СОЕДИНЕНИЕ ДеталиОстатки КАК ДеталиОстатки
ПО (ДеталиВременная.Деталь = ДеталиОстатки.Деталь
И ДеталиОстатки.Дата > ДеталиВременная.Дата)

УПОРЯДОЧИТЬ ПО
Дата УБЫВ

Теги: остатки 

Похожие темы (5)

Рейтинг@Mail.ru

Поиск