Запрос.УстановитьПараметр("СкладВДокументе", Склад);
Иначе
Запрос.Текст =
"ВЫБРАТЬ
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
| ОказаниеУслугиПереченьНоменклатуры.Количество,
| ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
| ОказаниеУслугиПереченьНоменклатуры.Сумма,
| ОстаткиМатериаловОстатки.КоличествоОстаток,
| СтоимостьМатериаловОстатки.СтоимостьОстаток
|ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК ОстаткиМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = ОстаткиМатериаловОстатки.Материал
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента)) КАК СтоимостьМатериаловОстатки
| ПО ОказаниеУслугиПереченьНоменклатуры.Номенклатура = СтоимостьМатериаловОстатки.Материал
|ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|
|ДЛЯ ИЗМЕНЕНИЯ
| РегистрНакопления.ОстаткиМатериалов.Остатки,
| РегистрНакопления.СтоимостьМатериалов.Остатки" ;
КонецЕсли;
Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
Запрос.УстановитьПараметр("СписокНоменклатурыДокумента", ПереченьНоменклатуры.ВыгрузитьКолонку("Номенклатура"));
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Обратите внимание, что для формирования списка номенклатуры документа мы используем метод ВыгрузитьКолонку() объекта ДокументТабличнаяЧасть.ОказаниеУслуги.ПереченьНоменклатуры.
После этого добавим получение результата запроса и цикл его обхода (листинг 7).
Листинг 7. Получение результата запроса и цикл его обхода
ВыборкаРезультатаЗапроса = Запрос.Выполнить().Выбрать();
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
КонецЦикла;
КонецПроцедуры
Теперь, прежде чем начать формирование движений по регистрам, нам нужно проверить наличие на складе достаточного количества номенклатуры в цикле обхода результата запроса (листинг 8).
Листинг 8. Проверка на складе достаточного количества номенклатуры
Пока ВыборкаРезультатаЗапроса.Следующий() Цикл
…
// Проверить остаток при оперативном проведении.
Если Режим = РежимПроведенияДокумента.Оперативный Тогда
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Остаток = ?(ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе = Null, 0, ВыборкаРезультатаЗапроса.КоличествоОстатокНаСкладе);
Если Остаток < ВыборкаРезультатаЗапроса.Количество Тогда
Сообщить("Материала" + СокрЛП(ВыборкаРезультатаЗапроса.Номенклатура) + "имеется только" + Остаток);
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
И в заключение, после проверки остатков на складе, перед самым концом цикла, добавим формирование движений по регистрам накопления (листинг 9).
Листинг 9. Формирование движений по регистрам накопления
// Сформировать движения.
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
// Регистр ОстаткиМатериалов Расход
Движение = Движения.ОстаткиМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Склад = Склад;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
// Регистр СтоимостьМатериалов Расход.
Движение = Движения.СтоимостьМатериалов.Добавить();
Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
Движение.Период = Дата;
Движение.Материал = ВыборкаРезультатаЗапроса.Номенклатура;
// Рассчитать стоимость материала.
СтоимостьМатериала = ?(ВыборкаРезультатаЗапроса.КоличествоОстаток = Null, 0,
ВыборкаРезультатаЗапроса.СтоимостьОстаток / ВыборкаРезультатаЗапроса.КоличествоОстаток);
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
КонецЕсли;
// Регистр Продажи
Движение = Движения.Продажи.Добавить();
Движение.Период = Дата;
Движение.Номенклатура = ВыборкаРезультатаЗапроса.Номенклатура;
Движение.Клиент = Клиент;
Движение.Мастер = Мастер;
Движение.Количество = ВыборкаРезультатаЗапроса.Количество;
Движение.Выручка = ВыборкаРезультатаЗапроса.Сумма;
Если ВыборкаРезультатаЗапроса.ВидНоменклатуры = Перечисления.ВидыНоменклатуры.Материал Тогда
Движение.Стоимость = СтоимостьМатериала * ВыборкаРезультатаЗапроса.Количество;
Иначе
Движение.Стоимость = 0;
КонецЕсли;
А сразу после цикла добавим запись движений регистров (листинг 10).
Листинг 6.10. Запись движений регистров
…
КонецЦикла;
// Записать движения регистров
Движения.ОстаткиМатериалов.Записать();
Движения.СтоимостьМатериалов.Записать();
Движения.Продажи.Записать();
КонецПроцедуры
Запустим 1С:Предприятие в режиме отладки и проверим работу нового обработчика события ОбработкаПроведения, перепроведя все документы Оказание услуги.
В заключение следует сделать небольшое отступление, которое касается задания параметров виртуальных таблиц, использовавшихся в наших запросах.
Как в первом, так и во втором запросах мы использовали условие, что материал должен находиться в списке значений, задаваемом одним из параметров запроса (листинг 11).
Листинг 11. Условие, накладываемое на материал
…
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СтоимостьМатериалов.Остатки(&МоментВремени, Материал В (&СписокНоменклатурыДокумента))
…
Однако при большом количестве строк табличной части документа, из которой формируется список номенклатуры документа, возможно, более эффективным будет не передача номенклатуры документа в списке значений, а выполнение вложенного запроса к временной таблице (листинг 12).
Листинг 12. Запрос во временной таблице
ВЫБРАТЬ * ИЗ НоменклатураДокумента
При этом временная таблица должна формироваться следующим образом (листинг 13):
Листинг 13. Формирование временной таблицы
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Номенклатура
|
|ПОМЕСТИТЬ
| НоменклатураДокумента
|
|ИЗ
| Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК
| ОказаниеУслугиПереченьНоменклатуры
|
|ГДЕ
| ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Запрос.Выполнить();
Выбор решения требует сравнительных тестов и зависит от конкретной информационной базы, размеров документа, количества одновременно работающих пользователей, производительности компьютеров и т. д.