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

Массовое создание РеализацияТоваровУслуг

Автор nexting, 31 июл 2025, 07:49

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

nexting

Здравствуйте!
Может кто-нибудь помочь с вопросом?
Обучаюсь на курсе 1с, есть задание, где длительные операции нужно массово создать РеализацияТоваровУслуг.
Создал общий модуль с кодом:


НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = МассивДанных[0].Период;
НовыйДокумент.Контрагент = Строка.Договор.Владелец;
НовыйДокумент.Договор = Строка.Договор;
ЗаполнитьЗначенияСвойств(НовыйДокумент, Строка.Договор);
НовыйДокумент.ВыполнитьАвтозаполнение();
Если НЕ НовыйДокумент.ПроверитьЗаполнение() Тогда
Возврат Ложь;
КонецЕсли;
НовыйДокумент.Записать();

В модуле объекта РеализацияТоваровУслуг есть процедура ВыполнитьАвтозаполнение()

Процедура ВыполнитьАвтозаполнение() Экспорт

НоменклатураАП = Константы.ВКМ_НоменклатураАбонентскаяПлата.Получить();
НоменклатураРС = Константы.ВКМ_НоменклатураРаботыСпециалиста.Получить();

ЭтотОбъект.Товары.Очистить();
ЭтотОбъект.Услуги.Очистить();

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СУММА(ВКМ_ВыполненныеКлиентуРаботыОбороты.СуммаКОплатеПриход) КАК СуммаКОплатеПриход
|ИЗ
| РегистрНакопления.ВКМ_ВыполненныеКлиентуРаботы.Обороты(
| НачалоПериода(&Дата,МЕСЯЦ),
| КонецПериода(&Дата,МЕСЯЦ),
| Период, Клиент = &Клиент И Договор = &Договор) КАК ВКМ_ВыполненныеКлиентуРаботыОбороты";

Запрос.УстановитьПараметр("Дата", ЭтотОбъект.Дата);
Запрос.УстановитьПараметр("Клиент", ЭтотОбъект.Контрагент);
Запрос.УстановитьПараметр("Договор", ЭтотОбъект.Договор);
РезультатЗапроса = Запрос.Выполнить();

ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

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

НоваяСтрокаТЧУслуги = ЭтотОбъект.Услуги.Добавить();
НоваяСтрокаТЧУслуги.Номенклатура = НоменклатураАП;
НоваяСтрокаТЧУслуги.Количество = ВыборкаДетальныеЗаписи.СуммаКОплатеПриход;
НоваяСтрокаТЧУслуги.Цена = НоменклатураРС;
НоваяСтрокаТЧУслуги.Сумма = НоваяСтрокаТЧУслуги.Количество * НоваяСтрокаТЧУслуги.Цена;

КонецЦикла;

КонецПроцедуры

Проблема в том, что раньше сохранял документ в процедуре ВыполнитьАвтозаполнение(), но по требованию преподавателя перенес сохранение и проверку заполнения из Модуля объекта в Общий модуль. Теперь у меня Общий модуль и Модуль объекта живут каждый своей жизнью.
Проверка НовыйДокумент.ПроверитьЗаполнение() не проходит. Задал вопрос преподавателю, но он отвечает крайне долго. Может тут есть знающие люди? Подскажите что не так делаю?

bsn-chita

Что не получается? Предположим что ВыполнитьАвтозаполнение() работает и делает все как надо (чем то заполняет табличную часть), а первый кусок кода создает и записывает документ.
Из кода ни чего не понятно, из текста не понятно что в итоге должно получиться. Вроде должно создаваться несколько документов (массовое все таки), длительная операция это то что создаваться она будет долго или что выполняться оно будет как фоновое задание.

nexting

bsn-chita, "первый кусок кода" это вы про Общий модуль?
Да, в нем должно быть сохранение и Проверка заполнения. Ранее, сохранение и Проверка заполнения выполнялись в ВыполнитьАвтозаполнение() и все работало, то есть документы сохранялись и проверка проходила успешно.
Сейчас, сохранение и Проверку заполнения перенес из ВыполнитьАвтозаполнение() в Общий модуль ("первый кусок кода") и теперь не работает.
Не пойму что не так.

bsn-chita

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();// Создаем документ
НовыйДокумент.Дата = МассивДанных[0].Период; // Что откуда взялос, а есть ли там дата, если нет то и документ не проидет проверку на заполнение и не запишется.
//Далее что то заполняем, но если для реквизитов не включена "Выдавать ошибку", то нам опять не интересно
НовыйДокумент.Контрагент = Строка.Договор.Владелец;
НовыйДокумент.Договор = Строка.Договор;
ЗаполнитьЗначенияСвойств(НовыйДокумент, Строка.Договор);
НовыйДокумент.ВыполнитьАвтозаполнение(); //если табличная часть не проверяется см. пункт выше(не интересно)
Если НЕ НовыйДокумент.ПроверитьЗаполнение() Тогда //здесь можно начинать ставить точку останова и вычислять выражение.
    Возврат Ложь; //Или тут и если мы сюда попали то документ не записали.
КонецЕсли;
НовыйДокумент.Записать(); //Записываем документ

Или кусок кода побольше или ставим точки останова (можно в самом начале процедуры/функции) и идем по шагам и смотрим куда зашли или не зашли.

nexting

bsn-chita,
Падаю вот на этой проверке в Общем модуле. У меня возвращается Ложь. Это видно и в журнале регистрации:

Если НЕ НовыйДокумент.ПроверитьЗаполнение() Тогда //здесь можно начинать ставить точку останова и вычислять выражение.
    Возврат Ложь; //Или тут и если мы сюда попали то документ не записали.
КонецЕсли;

А вот по порядку:
НовыйДокумент.Дата = МассивДанных[0].Период; // Что откуда взялос, а есть ли там дата, если нет то и документ не проидет проверку на заполнение и не запишется.

Заполнение массива выполняется в форме обработки создания массовых документов, где кликаем команду Создать.

Вот код формы МассовогоСозданияАктов:



&НаКлиенте
Процедура СоздатьРеализации(Команда)

Если НЕ ЗначениеЗаполнено(Объект.Период) Тогда
Сообщить("Не заполнен период");
Возврат;
КонецЕсли;

// --> алгоритм должен выполняться с использованием механизма длительных операций БСП
ПараметрыВыполнения = Новый Структура;
ЛогЗагрузки = "";

ПараметрыЗапуска = Новый Структура("ПараметрыВыполнения", ПараметрыВыполнения);

СтруктураФоновогоЗадания = СоздатьРеализацииНаСервере(ПараметрыЗапуска, УникальныйИдентификатор);
ИДЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;
ИдентификаторЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;

ПараметрыОжидания  = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
ПараметрыОжидания.Интервал = 1;

ДлительныеОперацииКлиент.ОжидатьЗавершение(СтруктураФоновогоЗадания, Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект, ЛогЗагрузки), ПараметрыОжидания);
// <--

КонецПроцедуры

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

ДоговорыКонтрагентов = ПолучитьДоговорыКонтрагентов();

Если ДоговорыКонтрагентов.Количество() > 0 Тогда
Для Каждого Договор Из ДоговорыКонтрагентов Цикл
НоваяСтрока = Объект.Данные.Добавить();
НоваяСтрока.Договор = Договор;
КонецЦикла;
КонецЕсли;

КонецПроцедуры

Функция ПолучитьДоговорыКонтрагентов()

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления";

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

МассивДоговоров = Новый Массив;

Пока Выборка.Следующий() Цикл
МассивДоговоров.Добавить(Выборка.Ссылка);
КонецЦикла; 

Возврат МассивДоговоров;

КонецФункции

Функция СоздатьРеализацииНаСервере(ПараметрыЗапуска, УникальныйИдентификатор)

НаименованиеЗадания = "Запуск длительной операции";
ВыполняемыйМетод = "ВКМ_ДлительныеОперации.СозданиеРеализаций";
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияПроцедуры();
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НаименованиеЗадания;
ПараметрыВыполнения.ЗапуститьВФоне = Истина;

// для отладки
//ПараметрыВыполнения.ЗапуститьВФоне   = Ложь;
//ПараметрыВыполнения.ЗапуститьНеВФоне = Истина;

МассивДанных = Новый Массив;
СтруктураРеквизитов = Новый Структура("Период", Объект.Период);
МассивДанных.Добавить(СтруктураРеквизитов);
ТЗ = Объект.Данные.Выгрузить();
МассивСтруктур = ТаблицаЗначенийВМассив(ТЗ);
МассивДанных.Добавить(МассивСтруктур);

ПараметрыЗапуска.Вставить("ДанныеОбъекта", МассивДанных);

СтруктураФоновогоЗадания = ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, ВыполняемыйМетод, ПараметрыЗапуска.ПараметрыВыполнения, ПараметрыЗапуска.ДанныеОбъекта);

Возврат СтруктураФоновогоЗадания;

КонецФункции 

&НаКлиенте
Процедура ОбработатьДанные(Результат, ЛогЗагрузки) Экспорт

ЗаполнитьРеализацииНаСервере();
а=1;

КонецПроцедуры

Функция ТаблицаЗначенийВМассив(ТаблицаЗначений) Экспорт
   
    Массив = Новый Массив();
    СтруктураСтрокой = "";
    НужнаЗапятая = Ложь;
    Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
        Если НужнаЗапятая Тогда
            СтруктураСтрокой = СтруктураСтрокой + ",";
        КонецЕсли;
        СтруктураСтрокой = СтруктураСтрокой + Колонка.Имя;
        НужнаЗапятая = Истина;
    КонецЦикла;
    Для Каждого Строка Из ТаблицаЗначений Цикл
        НоваяСтрока = Новый Структура(СтруктураСтрокой);
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
        Массив.Добавить(НоваяСтрока);
    КонецЦикла;
    Возврат Массив;

КонецФункции

Процедура ЗаполнитьРеализацииНаСервере()

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоговорыКонтрагентов.Ссылка КАК Договор,
| РеализацияТоваровУслуг.Ссылка КАК Реализация
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
| ПО РеализацияТоваровУслуг.Договор = ДоговорыКонтрагентов.Ссылка
|ГДЕ
| НЕ ДоговорыКонтрагентов.ПометкаУдаления
| И РеализацияТоваровУслуг.Дата = &Дата";

Запрос.УстановитьПараметр("Дата", Объект.Период);

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Договор");
ТЗ.Колонки.Добавить("Реализация");

Пока Выборка.Следующий() Цикл
НоваяСтрока = ТЗ.Добавить();
НоваяСтрока.Договор = Выборка.Договор;
НоваяСтрока.Реализация = Выборка.Реализация;
КонецЦикла; 

Для Каждого Строка Из Объект.Данные Цикл
СтрокаТЗ = ТЗ.Найти(Строка.Договор);
Если ЗначениеЗаполнено(СтрокаТЗ) Тогда
Строка.Реализация = СтрокаТЗ.Реализация;
КонецЕсли;
КонецЦикла;

КонецПроцедуры




//Далее что то заполняем, но если для реквизитов не включена "Выдавать ошибку", то нам опять не интересно

Проверил, в основных реквизитах документа РеализацияТоваровУслуг установлено Выдавать ошибку (в реквизитах Комментарий, Ответственный и СуммаДокумента нет).


И вот полный код Общего модуля:

Функция СозданиеРеализаций(ДанныеСтруктуры, МассивДанных) Экспорт

ЕстьРеализации = ПроверитьРеализациюНаПериод(МассивДанных[0].Период);

Если ЕстьРеализации Тогда
Сообщить("Уже созданы реализации за этот период");
Возврат Ложь;
КонецЕсли;

Если МассивДанных[1].Количество() > 0 Тогда
 
Для Каждого Строка Из МассивДанных[1] Цикл

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = МассивДанных[0].Период;
НовыйДокумент.Контрагент = Строка.Договор.Владелец;
НовыйДокумент.Договор = Строка.Договор;

ЗаполнитьЗначенияСвойств(НовыйДокумент, Строка.Договор);

НовыйДокумент.ВыполнитьАвтозаполнение();


Если НЕ НовыйДокумент.ПроверитьЗаполнение() Тогда
Возврат Ложь;
КонецЕсли;

НовыйДокумент.Записать();

КонецЦикла;
КонецЕсли;


КонецФункции

Функция ПроверитьРеализациюНаПериод(Период)

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| НЕ РеализацияТоваровУслуг.ПометкаУдаления
| И РеализацияТоваровУслуг.Дата = &Дата";

Запрос.УстановитьПараметр("Дата", Период);

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

Если Выборка.Следующий() Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;

КонецФункции


bsn-chita

В демонстрационной конфигурации БСП 3.1 упрощено сделал пример (имена метаданных похожи, но не идентичны).
Начинаем с копирования примера из комментария к методу ВыполнитьФункцию общего модуля ДлительныеОперации.
// Пример:
//  В общем виде процесс запуска и обработки результата длительной операции в модуле формы выглядит следующим образом:
//
//   1) Функция, которая будет исполняться в фоне, располагается в модуле менеджера объекта или в серверном общем модуле:
//    Функция РассчитатьЗначение(Знач МойПараметр1, Знач МойПараметр2) Экспорт
//     ...
//     Возврат Результат;
//    КонецФункции
//
//   2) Запуск операции на сервере и подключение обработчика ожидания:
//    &НаКлиенте
//    Процедура РассчитатьЗначение()
//     ДлительнаяОперация = НачатьВыполнениеНаСервере();
//     ОповещениеОЗавершении = Новый ОписаниеОповещения("ОбработатьРезультат", ЭтотОбъект);
//     ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
//     ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
//    КонецПроцедуры
//
//    &НаСервере
//    Функция НачатьВыполнениеНаСервере()
//     ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
//     Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, "Обработка.МояОбработка.РассчитатьЗначение",
//      МойПараметр1, МойПараметр2);
//    КонецФункции
//   
//   3) Обработка результата длительной операции:
//    &НаКлиенте
//    Процедура ОбработатьРезультат(Результат, ДополнительныеПараметры) Экспорт
//     Если Результат = Неопределено Тогда
//      Возврат;
//     КонецЕсли;
//     Если Результат.Статус = "Ошибка" Тогда
//      СтандартныеПодсистемыКлиент.ВывестиИнформациюОбОшибке(Результат.ИнформацияОбОшибке);
//      Возврат;
//     КонецЕсли;
//     ВывестиРезультат(Результат.АдресРезультата);
//    КонецПроцедуры
Делаем минимальные правки.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)   
ДоговорыКонтрагентов = ПолучитьДоговорыКонтрагентов(); 
Если ДоговорыКонтрагентов.Количество() > 0 Тогда
Для Каждого Договор Из ДоговорыКонтрагентов Цикл
НоваяСтрока = Объект.Данные.Добавить();
НоваяСтрока.Договор = Договор;
КонецЦикла;
КонецЕсли;   
КонецПроцедуры

&НаСервере
Функция ПолучитьДоговорыКонтрагентов()   
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    _ДемоДоговорыКонтрагентов.Ссылка КАК Ссылка
|ИЗ
|    Справочник._ДемоДоговорыКонтрагентов КАК _ДемоДоговорыКонтрагентов
|ГДЕ
|    НЕ _ДемоДоговорыКонтрагентов.ПометкаУдаления";   
РезультатЗапроса = Запрос.Выполнить(); 
Выборка = РезультатЗапроса.Выбрать();
МассивДоговоров = Новый Массив; 
Пока Выборка.Следующий() Цикл
МассивДоговоров.Добавить(Выборка.Ссылка);
КонецЦикла;     
Возврат МассивДоговоров;       
КонецФункции

&НаКлиенте
Процедура СоздатьРеализации(Команда)
Если НЕ ЗначениеЗаполнено(Объект.Период) Тогда
Сообщить("Не заполнен период");
Возврат;
КонецЕсли;
    // Вызываем метод из примера
РассчитатьЗначение();
КонецПроцедуры

&НаКлиенте
Процедура РассчитатьЗначение()
ДлительнаяОперация = НачатьВыполнениеНаСервере();
ОповещениеОЗавершении = Новый ОписаниеОповещения("ОбработатьРезультат", ЭтотОбъект);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
КонецПроцедуры

&НаСервере
Функция НачатьВыполнениеНаСервере()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
ВыполняемыйМетод = "ВКМ_ДлительныеОперации.СозданиеРеализаций";
ПараметрДанные = Объект.Данные.Выгрузить().Выгрузитьколонку("Договор");//Можно и ТЗ оставить все равно на сервере крутимся
ПараметрПериод = Объект.Период;
Возврат ДлительныеОперации.ВыполнитьФункцию(
ПараметрыВыполнения,
ВыполняемыйМетод,
ПараметрДанные,
ПараметрПериод);
КонецФункции

&НаКлиенте
Процедура ОбработатьРезультат(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
КонецЕсли;
Если Результат.Статус = "Ошибка" Тогда
СтандартныеПодсистемыКлиент.ВывестиИнформациюОбОшибке(Результат.ИнформацияОбОшибке);
Возврат;
КонецЕсли;
//ВывестиРезультат(Результат.АдресРезультата);
СообщениеПользователю = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
ОбщегоНазначенияКлиент.СообщитьПользователю(СообщениеПользователю);
КонецПроцедуры
И переписываем ваш общий модуль.
Функция СозданиеРеализаций(Данные, Период) Экспорт
Если Данные.Количество() > 0 Тогда
КоличествоСозданныхДокументов = 0;
Для Каждого ДоговорКонтрагента Из Данные Цикл
НовыйДокумент = Документы._ДемоРеализацияТоваров.СоздатьДокумент();
НовыйДокумент.Дата = Период;
НовыйДокумент.МестоХранения = Справочники._ДемоМестаХранения.НайтиПоКоду("ДМ-000001");

Реквизиты = Новый Структура;
Реквизиты.Вставить("Договор","Ссылка");
Реквизиты.Вставить("Контрагент","Владелец");
Реквизиты.Вставить("ГоловнаяОрганизация","Организация");
Реквизиты.Вставить("Партнер","Партнер");
ЗначенияРеквизитовДоговора = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(ДоговорКонтрагента,Реквизиты,Истина);
ЗаполнитьЗначенияСвойств(НовыйДокумент, ЗначенияРеквизитовДоговора);

Если НЕ НовыйДокумент.ПроверитьЗаполнение() Тогда
Возврат Ложь;
КонецЕсли;
НовыйДокумент.Записать();

КоличествоСозданныхДокументов = КоличествоСозданныхДокументов + 1;
КонецЦикла;
Возврат СтрШаблон("Количество созданных документов %1", КоличествоСозданныхДокументов);
КонецЕсли;
КонецФункции
Дальше можно дорабатывать (есть что оптимизировать и улучшать).

nexting

bsn-chita, Спасибо вам большое! Перенес ваше решение, ошибок при использовании нет, но и реализации не формируются. Подебажу и если не разберусь, или наоборот разберусь - вернусь.

Теги:

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

Рейтинг@Mail.ru

Поиск