Помогите написать запрос на получение таблицы остатков на документ, по товарам в документе
---
($Рег.Склад=:Склад)
(Рег.Склад=:Склад)
???
---
Финальная функция получения остатков на Документ, по товарам в табличной части.
Можно задействовать для проведения документа задним числом, без использования Временного расчета
ТекДок - документ, на начало которого рассчитываем остатки,
ПолеТовар - имя поля, содержащего реквизит документа типа справочника номенклатуры, товара.

Функция ПолучитьОстаткиДокПр(ТекДок,ПолеТовар) Экспорт
 Если МонопольныйРежим()=1 Тогда Возврат 0; КонецЕсли;
 Попытка
        База = СоздатьОбъект("OLEDBData");
        Соединение ="
            |Provider=VFPOLEDB.1;
            |Data Source=" + КаталогИБ() + ";
            |Mode=Read;
            |";
        Рез = База.Соединение(Соединение);
        Запрос = База.СоздатьКоманду();
 Исключение
  Возврат 0;
 КонецПопытки;
 Запрос.Выполнить("EXECSCRIPT('SET ANSI OFF')");
 // Устанавливаем время ожидания захвата таблиц , если во время выполнения запроса кто то проводит документы
 // Очень полезная функция - аналогична времени ожидания в 1С
 Запрос.Выполнить("EXECSCRIPT('SET REPROCESS TO 60 SECONDS')");
 // Убираем буфепизацию, чтобы данные возвращаемые запросам всегда были актуальны
 Запрос.Выполнить("EXECSCRIPT('SET REFRESH TO 0,-1')");
 Запрос.Выполнить("Exec('SET TABLEVALIDATE TO 0')");// Отключили блокировки
 ТекстЗапроса = "
|SEL ECT
| $Док.Работы as [Товар $Справочник.Каталог],
| SUM(Рег.Количество) as Количество,
| SUM(Рег.Сумма) as Сумма,
| SUM(Рег.СуммаВалюта) as СуммаВалюта
|FR OM
| $ДокументСтроки." + ТекДок.Вид() + " as Док
|INNER JOIN
| $Справочник.Каталог as СпрН ON СпрН.ID = $Док." + ПолеТовар + " AND $СпрН.ВидНоменклатуры = :ВидНом
|LEFT JOIN
| (SEL ECT
| $Р.Товар AS Товар,
| $Р.Количество AS Количество,
| $Р.Сумма AS Сумма,
| $Р.СуммаВалюта AS СуммаВалюта
| FR OM
| $РегистрИтоги.Товары as Р
| WHERE
| (period = :ПредМесяц~~)
| AND ($Р.Склад=:Склад)
|
| UNI ON ALL
|
| SEL ECT
| $Р.Товар AS Товар,
| $Р.Количество * (1 - Р.debkred * 2) AS Количество,
| $Р.Сумма * (1 - Р.debkred * 2) AS Сумма,
| $Р.СуммаВалюта * (1 - Р.debkred * 2) AS СуммаВалюта
| FR OM
| $Регистр.Товары AS Р
| INNER JOIN
| 1sjourn jr ON Р.iddoc = jr.iddoc
| AND (DTOS(jr.date)+jr.time+jr.iddoc BETWEEN :НачалоМесяца AND :ПредДата~)
| WH ERE
| ($Р.Склад=:Склад)
| ) AS Рег
| ON
| ($Док."+ ПолеТовар + " = Рег.Товар)
|WHERE
| Док.IDDOC = :ВыбДок
|GROUP BY
| $Док."+ ПолеТовар + "
| ";
 Запрос.УстановитьТекстовыйПараметр("Склад",ТекДок.Склад);
 Запрос.УстановитьТекстовыйПараметр("ВыбДок",ТекДок);
 Запрос.УстановитьТекстовыйПараметр("ВидНом",Перечисление.ВидыНоменклатуры.Товар);
 Запрос.УстановитьТекстовыйПараметр("ПредДата",СформироватьПозициюДокумента(ТекДок, -1));
 Запрос.УстановитьТекстовыйПараметр("НачалоМесяца",начМесяца(ТекДок.ДатаДок));
 Запрос.УстановитьТекстовыйПараметр("ПредМесяц",начМесяца(начМесяца(ТекДок.ДатаДок)-1));
 ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
 Если ТЗ.КоличествоСтрок() > 0 тогда
 Иначе
  ТЗ.НоваяСтрока();
  ТЗ.Количество = 0;
 КонецЕсли;
 Возврат ТЗ
КонецФункции

Для получения результата в модуле проведения, в конфигураторе документа отключаем Автоматическое удаление движений.
Далее, в обработке проведения, в начале процедуры пишем:

Процедура ОбработкаПроведения()
 ТзОст = ПолучитьОстаткиДокПр(ТекущийДокумент(),"Работы"); // У меня так называется реквизит типа номенклатура
 ОчиститьДвижения();
.......

Пользуйтесь!
---
Помогите написать запрос на получение таблицы остатков на документ, по товарам в документе

Речь про Регистр Бухгалтерии или Регистр накопления?
---
в 8-ке нет 1С++, 1С++ - это огород 77
---
регистр остатков Товары. Измерения: Товар, Склад. Ресурсы: Количество, Сумма, СуммаВалюта.
---
https://www.1cpp.ru/forum/YaBB.pl?board=query
---
Суть - перед проведением получить остатки товаров, входящих в состав табличной части, с регистра на текущий документ, для правильного списания по балансовой цене.

```1c
    ТекстЗапроса = "
    |SELECT
    | Рег.Товар as [Товар $Справочник.Каталог],
    | Рег.Количество as Количество,
    | Рег.Сумма as Сумма,
    | Рег.СуммаВалюта as СуммаВалюта,
    |
    |FR OM
    | $ДокументСтроки." + Вид() + " as Док
    |INNER JOIN
    | $Справочник.Каталог as СпрН ON СпрН.ID = $Док.Работы AND
    | $СпрН.ВидНоменклатуры = :$Перечисление.ВидыНоменклатуры.Товар
    |
    |LEFT JOIN
    | $РегистрОстатки.Товары("+?(ИтогиАктуальны()=1,",",":ДатаРасчета~,")+"
    | (Склад, Товар), (Количество, Сумма, СуммаВалюта)) as Рег
    |
    | WH ERE
    | (Док.IDDOC = :ВыбДок) AND
    | ($Рег.Склад=:Склад)
    | ";
    Запрос.УстановитьТекстовыйПараметр("ДатаРасчета",СформироватьПозициюДокумента(ТекущийДокумент(), -1));
    Запрос.УстановитьТекстовыйПараметр("ВыбДок",ТекущийДокумент());
    Запрос.УстановитьТекстовыйПараметр("Склад",Склад);
    ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
```

Выдает ошибку:
ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
{Документ.ПроизводствоПоНормативу.Модуль Документа(63)}: Meta name parser error: неизвестное метаимя или алиас "$Рег"
---
($Рег.Склад=:Склад)
(Рег.Склад=:Склад)
???
---
а как нужно? Это первый мой запрос...
---
Теперь ошибка такая:
FAILED! ICommandText::Execute(): Command contains unrecognized phrase/keyword.
---
Немного переделал:

```1c
    ТекстЗапроса = "
    |SELECT
    | Рег.Товар as [Товар $Справочник.Каталог],
    | Рег.Количество as Количество,
    | Рег.Сумма as Сумма,
    | Рег.СуммаВалюта as СуммаВалюта
    |FR OM
    | $ДокументСтроки." + Вид() + " as Док
    |INNER JOIN
    | $Справочник.Каталог as СпрН ON СпрН.ID = Товар AND
    | $СпрН.ВидНоменклатуры = :$Перечисление.ВидыНоменклатуры.Товар
    |
    |LEFT JOIN
    | $РегистрОстатки.Товары("+?(ИтогиАктуальны()=1,",",":ДатаРасчета~,")+" ,
    | Склад= :Склад,
    | (Товар), (СуммаВалюта, Сумма, Количество)) as Рег
    | ON
    | $Док.Работы = Рег.Товар
    | WH ERE
    | Док.IDDOC = :ВыбДок
    |GROUP BY
    | $Док.Работы
    | ";
    Запрос.УстановитьТекстовыйПараметр("ДатаРасчета",СформироватьПозициюДокумента(ТекущийДокумент(), -1));
    Запрос.УстановитьТекстовыйПараметр("ВыбДок",ТекущийДокумент());
    Запрос.УстановитьТекстовыйПараметр("Склад",Склад);
    ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
```

Но ошибка теперь: FAILED! ICommandText::Execute(): Missing operand.
---
|FR OM
Оно?
---
Нет, это так скопировалось. Такое впечатление, что
 | $РегистрОстатки.Товары("+?(ИтогиАктуальны()=1,",",":ДатаРасчета~,")+" ,
| Склад= :Склад,
| (Товар), (СуммаВалюта, Сумма, Количество)) as Рег

Не работает. Я уже упрощал к виду:

```1c
    Функция ПолучитьОстаткиДокПр()
    Если МонопольныйРежим()=1 Тогда Возврат 0; КонецЕсли;
    Попытка
    База = СоздатьОбъект("OLEDBData");
    Соединение ="
    |Provider=VFPOLEDB.1;
    |Data Source=" + КаталогИБ() + ";
    |Mode=Read;
    |";
    Рез = База.Соединение(Соединение);
    Запрос = База.СоздатьКоманду();
    Исключение
    Возврат 0;
    КонецПопытки;
    ТекстЗапроса = "
    |SELECT
    | РегСН.Товар AS [Товар $Справочник.Каталог],
    | РегСН.Склад AS [Склад $Справочник.Склады],
    | РегСН.Количество AS Количество,
    | РегСН.Сумма AS Сумма,
    | РегСН.СуммаВалюта AS СуммаВалюта
    |FROM
    | $РегистрОстатки.Товары(:ДатаРасчета~,,,(Товар, Склад),(Количество, Сумма, СуммаВалюта)) AS РегСН
    |";
    Запрос.УстановитьТекстовыйПараметр("ДатаРасчета",СформироватьПозициюДокумента(ТекущийДокумент(), -1));
    ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    Если ТЗ.КоличествоСтрок() > 0 тогда
    Иначе
    ТЗ.НоваяСтрока();
    ТЗ.Количество = 0;
    КонецЕсли;
    ТЗ.ВыбратьСтроку(,",);
    Возврат ТЗ
    КонецФункции
```

Получаю ошибку:
ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
{Документ.ПроизводствоПоНормативу.Модуль Документа(77)}: FAILED! ICommandText::Execute(): Syntax error.
---
Я, так понял, что РегистрОстатки - это не для dbf базы. Нужно копать в сторону РегистрИтоги... Может кто сталкивался?
---
Немного переделал:
ТекстЗапроса = "
|SELECT
| Рег.Товар as [Товар $Справочник.Каталог],
| Рег.Количество as Количество,
| Рег.Сумма as Сумма,
| Рег.СуммаВалюта as СуммаВалюта
|FR OM
| $ДокументСтроки." + Вид() + " as Док
|INNER JOIN
| $Справочник.Каталог as СпрН ON СпрН.ID = Товар AND
| $СпрН.ВидНоменклатуры = :$Перечисление.ВидыНоменклатуры.Товар
|
|LEFT JOIN
| $РегистрОстатки.Товары("+?(ИтогиАктуальны()=1,",",":ДатаРасчета~,")+" ,
| Склад= :Склад,
| (Товар), (СуммаВалюта, Сумма, Количество)) as Рег
| ON
| $Док.Работы = Рег.Товар
| WH ERE
| Док.IDDOC = :ВыбДок
|GROUP BY
| $Док.Работы
| ";
Запрос.УстановитьТекстовыйПараметр("ДатаРасчета",СформироватьПозициюДокумента(ТекущийДокумент(), -1));
Запрос.УстановитьТекстовыйПараметр("ВыбДок",ТекущийДокумент());
Запрос.УстановитьТекстовыйПараметр("Склад",Склад);
ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);

Но ошибка теперь: FAILED! ICommandText::Execute(): Missing operand.
---
Наконец-то въехал!!! Конструкция:

```1c
    | $РегистрОстатки.Товары("+?(ИтогиАктуальны()=1,",",":ДатаРасчета~,")+" ,
    | Склад= :Склад,
    | (Товар), (СуммаВалюта, Сумма, Количество)) as Рег
```

расчитана для СКЛ версии базы.
---
Получил остатки регистра на Документ (пока все остатки):

```1c
    Функция ПолучитьОстаткиДокПр(ТекДок) Экспорт
    Если МонопольныйРежим()=1 Тогда Возврат 0; КонецЕсли;
    Попытка
    База = СоздатьОбъект("OLEDBData");
    Соединение ="
    |Provider=VFPOLEDB.1;
    |Data Source=" + КаталогИБ() + ";
    |Mode=Read;
    |";
    Рез = База.Соединение(Соединение);
    Запрос = База.СоздатьКоманду();
    Исключение
    Возврат 0;
    КонецПопытки;
    Запрос.Выполнить("EXECSCRIPT('SET ANSI OFF')");
    // Устанавливаем время ожидания захвата таблиц , если во время выполнения запроса кто то проводит документы
    // Очень полезная функция - аналогична времени ожидания в 1С
    Запрос.Выполнить("EXECSCRIPT('SET REPROCESS TO 60 SECONDS')");
    // Убираем буфепизацию, чтобы данные возвращаемые запросам всегда были актуальны
    Запрос.Выполнить("EXECSCRIPT('SET REFRESH TO 0,-1')");
    Запрос.Выполнить("Exec('SET TABLEVALIDATE TO 0')");// Отключили блокировки
    ТекстЗапроса = "
    |SEL ECT
    | Рег.Товар as [Товар $Справочник.Каталог],
    | SUM(Рег.Количество) as Количество,
    | SUM(Рег.Сумма) as Сумма,
    | SUM(Рег.СуммаВалюта) as СуммаВалюта
    |FR OM
    | (SEL ECT
    | $Р.Товар AS Товар,
    | $Р.Количество AS Количество,
    | $Р.Сумма AS Сумма,
    | $Р.СуммаВалюта AS СуммаВалюта
    | FR OM
    | $РегистрИтоги.Товары as Р
    | WHERE
    | (period = :ПредМесяц~~)
    | AND ($Р.Склад=:Склад)
    |
    | UNI ON ALL
    |
    | SEL ECT
    | $Р.Товар AS Товар,
    | $Р.Количество * (1 - Р.debkred * 2) AS Количество,
    | $Р.Сумма * (1 - Р.debkred * 2) AS Сумма,
    | $Р.СуммаВалюта * (1 - Р.debkred * 2) AS СуммаВалюта
    | FR OM
    | $Регистр.Товары AS Р
    | INNER JOIN
    | 1sjourn jr ON Р.iddoc = jr.iddoc
    | AND (DTOS(jr.date)+jr.time+jr.iddoc BETWEEN :НачалоМесяца AND :ПредДата~)
    | WH ERE
    | ($Р.Склад=:Склад)
    | ) AS Рег
    |GROUP BY
    | Рег.Товар
    | ";
    Запрос.УстановитьТекстовыйПараметр("Склад",ТекДок.Склад);
    Запрос.УстановитьТекстовыйПараметр("ПредДата",СформироватьПозициюДокумента(ТекДок, -1));
    Запрос.УстановитьТекстовыйПараметр("НачалоМесяца",начМесяца(ТекДок.ДатаДок));
    Запрос.УстановитьТекстовыйПараметр("ПредМесяц",начМесяца(начМесяца(ТекДок.ДатаДок)-1));
    ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
    Если ТЗ.КоличествоСтрок() > 0 тогда
    Иначе
    ТЗ.НоваяСтрока();
    ТЗ.Количество = 0;
    КонецЕсли;
    ТЗ.ВыбратьСтроку(,",);
    Возврат ТЗ
    КонецФункции
```

Это остатки для DBF базы!!!
---
Финальная функция получения остатков на Документ, по товарам в табличной части.
Можно задействовать для проведения документа задним числом, без использования Временного расчета
ТекДок - документ, на начало которого рассчитываем остатки,
ПолеТовар - имя поля, содержащего реквизит документа типа справочника номенклатуры, товара.

Функция ПолучитьОстаткиДокПр(ТекДок,ПолеТовар) Экспорт
 Если МонопольныйРежим()=1 Тогда Возврат 0; КонецЕсли;
 Попытка
        База = СоздатьОбъект("OLEDBData");
        Соединение ="
            |Provider=VFPOLEDB.1;
            |Data Source=" + КаталогИБ() + ";
            |Mode=Read;
            |";
        Рез = База.Соединение(Соединение);
        Запрос = База.СоздатьКоманду();
 Исключение
  Возврат 0;
 КонецПопытки;
 Запрос.Выполнить("EXECSCRIPT('SET ANSI OFF')");
 // Устанавливаем время ожидания захвата таблиц , если во время выполнения запроса кто то проводит документы
 // Очень полезная функция - аналогична времени ожидания в 1С
 Запрос.Выполнить("EXECSCRIPT('SET REPROCESS TO 60 SECONDS')");
 // Убираем буфепизацию, чтобы данные возвращаемые запросам всегда были актуальны
 Запрос.Выполнить("EXECSCRIPT('SET REFRESH TO 0,-1')");
 Запрос.Выполнить("Exec('SET TABLEVALIDATE TO 0')");// Отключили блокировки
 ТекстЗапроса = "
|SEL ECT
| $Док.Работы as [Товар $Справочник.Каталог],
| SUM(Рег.Количество) as Количество,
| SUM(Рег.Сумма) as Сумма,
| SUM(Рег.СуммаВалюта) as СуммаВалюта
|FR OM
| $ДокументСтроки." + ТекДок.Вид() + " as Док
|INNER JOIN
| $Справочник.Каталог as СпрН ON СпрН.ID = $Док." + ПолеТовар + " AND $СпрН.ВидНоменклатуры = :ВидНом
|LEFT JOIN
| (SEL ECT
| $Р.Товар AS Товар,
| $Р.Количество AS Количество,
| $Р.Сумма AS Сумма,
| $Р.СуммаВалюта AS СуммаВалюта
| FR OM
| $РегистрИтоги.Товары as Р
| WHERE
| (period = :ПредМесяц~~)
| AND ($Р.Склад=:Склад)
|
| UNI ON ALL
|
| SEL ECT
| $Р.Товар AS Товар,
| $Р.Количество * (1 - Р.debkred * 2) AS Количество,
| $Р.Сумма * (1 - Р.debkred * 2) AS Сумма,
| $Р.СуммаВалюта * (1 - Р.debkred * 2) AS СуммаВалюта
| FR OM
| $Регистр.Товары AS Р
| INNER JOIN
| 1sjourn jr ON Р.iddoc = jr.iddoc
| AND (DTOS(jr.date)+jr.time+jr.iddoc BETWEEN :НачалоМесяца AND :ПредДата~)
| WH ERE
| ($Р.Склад=:Склад)
| ) AS Рег
| ON
| ($Док."+ ПолеТовар + " = Рег.Товар)
|WHERE
| Док.IDDOC = :ВыбДок
|GROUP BY
| $Док."+ ПолеТовар + "
| ";
 Запрос.УстановитьТекстовыйПараметр("Склад",ТекДок.Склад);
 Запрос.УстановитьТекстовыйПараметр("ВыбДок",ТекДок);
 Запрос.УстановитьТекстовыйПараметр("ВидНом",Перечисление.ВидыНоменклатуры.Товар);
 Запрос.УстановитьТекстовыйПараметр("ПредДата",СформироватьПозициюДокумента(ТекДок, -1));
 Запрос.УстановитьТекстовыйПараметр("НачалоМесяца",начМесяца(ТекДок.ДатаДок));
 Запрос.УстановитьТекстовыйПараметр("ПредМесяц",начМесяца(начМесяца(ТекДок.ДатаДок)-1));
 ТЗ=Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
 Если ТЗ.КоличествоСтрок() > 0 тогда
 Иначе
  ТЗ.НоваяСтрока();
  ТЗ.Количество = 0;
 КонецЕсли;
 Возврат ТЗ
КонецФункции

Для получения результата в модуле проведения, в конфигураторе документа отключаем Автоматическое удаление движений.
Далее, в обработке проведения, в начале процедуры пишем:

Процедура ОбработкаПроведения()
 ТзОст = ПолучитьОстаткиДокПр(ТекущийДокумент(),"Работы"); // У меня так называется реквизит типа номенклатура
 ОчиститьДвижения();
.......

Пользуйтесь!