Заказы на доработку 1С (сервис удаленной работы)

Хранилище

База знаний
Неназначенных незавершенных заказов: 1
Бесплатные отчеты, обработки, конфигурации, внешние компоненты для 1С Статьи, описание работы, методики по работе с 1С

Здравствуйте, гость ( Вход | Зарегистрироваться )



> Ошибка в цикле          
salton Подменю пользователя
сообщение 30.04.15, 16:59
Сообщение #1

Говорящий
***
Группа: Пользователи
Сообщений: 92
Из: Полтава
Спасибо сказали: 24 раз
Рейтинг: 0

Никак не могу достичь цели.
Вкратце нужно из ТЗ в табличную часть нового документа или уже существующего загрузить информацию. При этом не исключена повторная загрузка с исключением ранее загруженной информации.
В ТЗ грубо говоря есть строки, 1 колонка - Менеджер, 2 - Идентификатор. 3 - число.
В колонке Менеджер данные могут быть разные, в колонке Идентифкатор - данные разные.
Нужно Взять Менеджера, проверить есть ли документ для него, если нет - создать и дальше заполнить табличную часть идентифкатором из второй колонки и числом из третьей.
И так для каждой строки ТЗ.

Есть код:

    
таб.ВыбратьСтроки(); // таб - заполенная ТЗ с информацией
Пока таб.ПолучитьСтроку() = 1 Цикл
    локОтчет= "";
    тмпОтчет = СоздатьОбъект("Документ.Отчет");
    тмпОтчет.ВыбратьДокументы(ДатаСоздания,ДатаСоздания);
    Пока тмпОтчет.ПолучитьДокумент() = 1 Цикл
        Если тмпОтчет.Менеджер = таб.Менеджер Тогда
            локОтчет= тмпОтчет;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    Если локОтчет= "" Тогда //если не существует документа - создаем новый
        локОтчет= СоздатьОбъект("Документ.Отчет");
        локОтчет.Новый();
        локОтчет.НоваяСтрока();

        //дальше заполняем первую строку документа информацией
    Иначе
        //документ уже существует
        локОтчет.ВыбратьСтроки();
        Пока локОтчет.ПолучитьСтроку()=1 Цикл
                        Если Число(локОтчет.Идентификатор)=СокрЛП(таб.Идентификатор) Тогда
                //проверяем нет ли в существующем документе строки с информацией которую загрузили ранее
                Продолжить; //если есть возвращаемся в начало цикла и смотрим на следующую строку
            КонецЕсли;
            локОтчет.НоваяСтрока();
            //дальше заполняем строку документа информацией        
        КонецЦикла;
    КонецЕсли;
КонецЦикла


в итоге при первичной загрузке информации из ТЗ документы создаются изаполняются, а при повторной загрузке - вся информация задваивается.
Как избежать задвоения?
Заранее благодарен!

Sharzem Подменю пользователя
сообщение 30.04.15, 19:11
Сообщение #2

Оратор
Иконка группы
Группа: Местный
Сообщений: 298
Спасибо сказали: 98 раз
Рейтинг: 99.1

Можно так:
ТаблЗначДоков = СоздатьОбъект("ТаблицаЗначений");
ТаблЗначДоков.НоваяКолонка("ДокОтчет","Документ.Отчет");
ТаблЗначДоков.НоваяКолонка("Менеджер","Справочник");

тмпОтчет = СоздатьОбъект("Документ.Отчет");
тмпОтчет.ВыбратьДокументы(ДатаСоздания,ДатаСоздания);

Пока тмпОтчет.ПолучитьДокумент() = 1 Цикл
    ТаблЗначДоков.НоваяСтрока();
    ТаблЗначДоков.ДокОтчет = тмпОтчет.ТекущийДокумент();
    ТаблЗначДоков.Менеджер = тмпОтчет.Менеджер;
КонецЦикла;

НачатьТранзакцию();
таб.ВыбратьСтроки(); // таб - заполенная ТЗ с информацией
Пока таб.ПолучитьСтроку() = 1 Цикл
    МенеджерВтаб = таб.Менеджер;
    номСтрДока = "";
    Если ТаблЗначДоков.НайтиЗначение(МенеджерВтаб,номСтрДока,"Менеджер") = 1 Тогда
        ТаблЗначДоков.ПолучитьСтрокуПоНомеру(номСтрДока);
        тмпОтчет.НайтиДокумент(ТаблЗначДоков.ДокОтчет);
        Модифиц = 1; //Признак необходимости модификации (По умолчанию - 1)
        тмпОтчет.ВыбратьСтроки();
        Пока тмпОтчет.ПолучитьСтроку() = 1 Цикл
            //Только сначала определи что здесь число или строка, типы должны быть одинаковы
            Если Число(тмпОтчет.Идентификатор) = Число(таб.Идентификатор) Тогда
                Модифиц = 0;
            КонецЕсли;
        КонецЦикла;
        Если Модифиц = 1 Тогда
            тмпОтчет.НоваяСтрока();
            //заполняй следующую строку документа информацией
            тмпОтчет.Записать();
        КонецЕсли;
    Иначе
        тмпОтчет.Новый();
        тмпОтчет.Менеджер = МенеджерВтаб;
        тмпОтчет.НоваяСтрока();
        //заполняй первую строку документа информацией
        тмпОтчет.Записать();
    КонецЕсли;
КонецЦикла;
ЗафиксироватьТранзакцию();


Signature
То, что для одного человека константа, для другого - переменная. (Алан.Дж.Перлис)

Домовик Подменю пользователя
сообщение 30.04.15, 19:21
Сообщение #3

Ветеран
Иконка группы
Группа: Местный
Сообщений: 975
Из: Киев
Спасибо сказали: 168 раз
Рейтинг: 0

    
    тмпОтчет = СоздатьОбъект("Документ.Отчет");
    локОтчет= СоздатьОбъект("Документ.Отчет");
таб.ВыбратьСтроки(); // таб - заполенная ТЗ с информацией
Пока таб.ПолучитьСтроку() = 1 Цикл
    локОтчет="";  //или локОтчет =ПолучитьПустоеЗначение("Документ.Отчет");
    тмпОтчет.ВыбратьДокументы(ДатаСоздания,ДатаСоздания);
    Пока тмпОтчет.ПолучитьДокумент() = 1 Цикл
        Если тмпОтчет.Менеджер = таб.Менеджер Тогда
            локОтчет.НайтиДокумент(тмпОтчет.ТекущийДОкумент());
            Прервать;
        КонецЕсли;
    КонецЦикла;
    Если локОтчет="" Тогда //если не существует документа - создаем новый  // или сравнить с пустым значением - функция ПустоеЗначение()
        локОтчет.Новый();
        локОтчет.НоваяСтрока();

        //дальше заполняем первую строку документа информацией
    Иначе
        //документ уже существует
        локОтчет.ВыбратьСтроки();
        Пока локОтчет.ПолучитьСтроку()=1 Цикл
                        Если Число(локОтчет.Идентификатор)=СокрЛП(таб.Идентификатор) Тогда
                //проверяем нет ли в существующем документе строки с информацией которую загрузили ранее
                Продолжить; //если есть возвращаемся в начало цикла и смотрим на следующую строку
            КонецЕсли;
            локОтчет.НоваяСтрока();
            //дальше заполняем строку документа информацией        
        КонецЦикла;
    КонецЕсли;
КонецЦикла


ой, первого ответа не видно было. )

Sharzem Подменю пользователя
сообщение 30.04.15, 19:35
Сообщение #4

Оратор
Иконка группы
Группа: Местный
Сообщений: 298
Спасибо сказали: 98 раз
Рейтинг: 99.1

Цитата(Домовик @ 30.04.15, 20:21) *
    

локОтчет=СоздатьОбъект("Документ.Отчет")
локОтчет="";
локОтчет.Новый()

Если Число(локОтчет.Идентификатор)=СокрЛП(таб.Идентификатор) Тогда


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

Хотя если сравнить его вариант с предложенными, то 1 С он наверное такими кодами вовсе убьет.


Signature
То, что для одного человека константа, для другого - переменная. (Алан.Дж.Перлис)

salton Подменю пользователя
сообщение 30.04.15, 19:43
Сообщение #5

Говорящий
***
Группа: Пользователи
Сообщений: 92
Из: Полтава
Спасибо сказали: 24 раз
Рейтинг: 0

спасибо, сейчас проверю предложенный Вами варианты.

зы. Менеджер в Таб может повторяться несколько раз...

Домовик Подменю пользователя
сообщение 30.04.15, 19:56
Сообщение #6

Ветеран
Иконка группы
Группа: Местный
Сообщений: 975
Из: Киев
Спасибо сказали: 168 раз
Рейтинг: 0

Sharzem, вы имеете в виду скобки присваиваются? и типа тип значения теряется? да? точно? потеряется или обнулится?


Sharzem Подменю пользователя
сообщение 30.04.15, 20:16
Сообщение #7

Оратор
Иконка группы
Группа: Местный
Сообщений: 298
Спасибо сказали: 98 раз
Рейтинг: 99.1

Цитата(salton @ 30.04.15, 20:43) *
спасибо, сейчас проверю предложенный Вами варианты.

зы. Менеджер в Таб может повторяться несколько раз...


Теперь представьте вариант что "Менеджер" у Вас порядка 100 000 и информации по ним еще + по 10 шт. на каждого, итого 1 млн. строк в таб.

Смотрите глобальней, сделайте что-б в таб не попадала информация которая уже разнесена по документам.

Ваш подход и варриант реализации не совсем правильные, уж очень это все долго ! И еще, луше не перебирать сначала строки Таб, а потом документа, а сделать наоборот, перебрать Документы, потом строки Таб и только после этого произвести Запись или Проведение Документа, таким образом выиграете доп. время + еще нужно проверить существующие Документы на блокировку. (см. Блокировка(вклВыкл)). Впрочем удачи )

Цитата(Домовик @ 30.04.15, 20:56) *
Sharzem, вы имеете в виду скобки присваиваются? и типа тип значения теряется? да? точно? потеряется или обнулится?


Из синтаксис помощника:
Синтаксис:
НайтиДокумент(<Документ>)
Назначение:
Найти документ по значению.
Возвращает: 1 - если действие выполнено (документ найден);
0 - если действие не выполнено.
Параметры:
<Документ> - выражение со значением типа 'Документ'.
Замечание:
Метод можно использовать только для объектов, созданных функцией СоздатьОбъект.

Вот еще:

Новый()
Назначение:
Начать ввод нового документа.
Замечание:
Метод можно использовать только для объектов, созданных функцией СоздатьОбъект.

А вы что сделали ?
локОтчет=СоздатьОбъект("Документ.Отчет")
локОтчет="";

и далее применили
локОтчет.Новый()

и
локОтчет.НайтиДокумент(тмпОтчет.ТекущийДОкумент());


Извините, я не хотел Вас оскорбить, не вкоем случае.


Signature
То, что для одного человека константа, для другого - переменная. (Алан.Дж.Перлис)

Спасибо сказали: Домовик,

Домовик Подменю пользователя
сообщение 30.04.15, 20:33
Сообщение #8

Ветеран
Иконка группы
Группа: Местный
Сообщений: 975
Из: Киев
Спасибо сказали: 168 раз
Рейтинг: 0

Sharzem, та что вы? действительно много чего забываю. я только не пойму о чем вы. но давайте сейчас уже не спорить. вы же помогли по вопросу.
я еще чуть позже на выспанную голову посмотрю ).

Спасибо сказали: Sharzem,

Sharzem Подменю пользователя
сообщение 30.04.15, 22:16
Сообщение #9

Оратор
Иконка группы
Группа: Местный
Сообщений: 298
Спасибо сказали: 98 раз
Рейтинг: 99.1

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

//======================================================================
Процедура ЗаполнимДокументыИзТаб(прТаб,прНачДата, прКонДата)//прТаб - это Ваша таб, прНачДата, прКонДата - даты выборки документов
    Если ТипЗначенияСтр(прТаб) <> "ТаблицаЗначений" Тогда
        Предупреждение("Это не таблица значений!",5);
        Возврат;
    ИначеЕсли прТаб.КоличествоСтрок() = 0 Тогда
        Предупреждение("Пустая таблица значений!",5);
        Возврат;
    КонецЕсли;
    
    лпНоваяТаб = СоздатьОбъект("ТаблицаЗначений");//Копия Таб
    прТаб.Выгрузить(лпНоваяТаб)
    
    //лпТаблЗначДоков (Таблица значений) - для документов которые есть в периоде, для того что-б не делать выбоку в цикле
    лпТаблЗначДоков = СоздатьОбъект("ТаблицаЗначений");
    лпТаблЗначДоков.НоваяКолонка("ДокОтчет","Документ.Отчет");
    лпТаблЗначДоков.НоваяКолонка("Менеджер","Справочник");
    //Выборка документов и заполнение лпТаблЗначДоков, где лпДокОтчет - агрегатный Объект для применения команд
    лпДокОтчет = СоздатьОбъект("Документ.Отчет");
    
    //лпТаблЧастьДока (Таблица значений) - для выгрузки табличной части, для того чтоб не бегать в цикле по строкам
    лпТаблЧастьДока = СоздатьОбъект("ТаблицаЗначений");
    
    лпДокОтчет.ВыбратьДокументы(прНачДата, прКонДата);
    Пока лпДокОтчет.ПолучитьДокумент() = 1 Цикл
        лпТаблЗначДоков.НоваяСтрока();
        лпТаблЗначДоков.ДокОтчет = лпДокОтчет.ТекущийДокумент();
        лпТаблЗначДоков.Менеджер = лпДокОтчет.Менеджер;
    КонецЦикла;
    //лпТаблОтбор (Таблица значений) - для отбора по менеджерам, для того что-б не перезаписывать (перепроводить) документы в цикле
    лпТаблОтбор = СоздатьОбъект("ТаблицаЗначений");
    лпНоваяТаб.Выгрузить(лпТаблОтбор);
    лпТаблОтбор.НоваяКолонка("Отбор","Число");
    лпТаблОтбор.Заполнить(1,,,"Отбор");
    лпТаблОтбор.Свернуть("Менеджер","Отбор");
    //Теперь выберем Менеджер и конкретно по нему заполним или создадим документы
    лпТаблОтбор.ВыбратьСтроки();
    НачатьТранзакцию();
    Пока лпТаблОтбор.ПолучитьСтроку() = 1 Цикл
        лпМенеджер = лпТаблОтбор.Менеджер;
        лпКолОтбора = лпТаблОтбор.Отбор;
        лпСтрТаблЗначДок = "";
        Если лпТаблЗначДоков.НайтиЗначение(лпМенеджер,лпСтрТаблЗначДок,"Менеджер") = 1 Тогда//Всегда на 1-го Менеджера только 1 документ
            лпТаблЗначДоков.ПолучитьСтрокуПоНомеру(лпСтрТаблЗначДок);
            лпДокОтчет.НайтиДокумент(лпТаблЗначДоков.ДокОтчет);
        Иначе//Документ не найден
            лпДокОтчет.Новый();
            лпДокОтчет.Менеджер = лпМенеджер;
            //Еще какие там необходимые реквизиты
            
            лпДокОтчет.УстановитьНовыйНомер();
            лпДокОтчет.АвтоВремяТекущее();//или еще какое-то
        КонецЕсли;
        лпДокОтчет.ВыгрузитьТабличнуюЧасть(лпТаблЧастьДока);
        ОбработаемТабличнуюЧасть(лпТаблЧастьДока,лпНоваяТаб,лпКолОтбора,лпМенеджер);
        лпКолСтрокДока = лпДокОтчет.КоличествоСтрок();
        лпКолСтрокТаблЧасть = лпТаблЧастьДока.КоличествоСтрок();
        Если лпКолСтрокДока < лпКолСтрокТаблЧасть Тогда//Добавлены новые строки
            лпДокОтчет.ЗагрузитьТабличнуюЧасть(лпТаблЧастьДока);
            Если (лпДокОтчет.Блокировка(1)=1) Тогда//Проверим не блокирован ли документ
                лпДокОтчет.Блокировка(0);
                лпДокОтчет.Провести();//Или Записать() не знаю
            Иначе
                Сообщить("Заблокирован "+лпДокОтчет.Представлениевида()+" № "+лпДокОтчет.НомерДок+" от "+лпДокОтчет.ДатаДок,"!");
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    ЗафиксироватьТранзакцию();
КонецПроцедуры //ЗаполнимДокументыИзТаб


Signature
То, что для одного человека константа, для другого - переменная. (Алан.Дж.Перлис)

Спасибо сказали: salton, Домовик,

Домовик Подменю пользователя
сообщение 01.05.15, 8:30
Сообщение #10

Ветеран
Иконка группы
Группа: Местный
Сообщений: 975
Из: Киев
Спасибо сказали: 168 раз
Рейтинг: 0

Цитата(Sharzem @ 30.04.15, 17:16) *
А вы что сделали ?
локОтчет=СоздатьОбъект("Документ.Отчет")
локОтчет="";

и далее применили
локОтчет.Новый()
и
локОтчет.НайтиДокумент(тмпОтчет.ТекущийДОкумент());


а как "обнулить" переменную типа Документ. , не слетая с типа? и не используя в цикле СоздатьОбъект ?
у меня в комментариях кода указано еще ПолучитьПустоеЗначение(). оказывается "обнуляет", но потом перепозиционировать не дает...




разве что признак нахождения существующего документа писать в другую, числову, переменную.

Sharzem Подменю пользователя
сообщение 01.05.15, 9:14
Сообщение #11

Оратор
Иконка группы
Группа: Местный
Сообщений: 298
Спасибо сказали: 98 раз
Рейтинг: 99.1

Цитата(Домовик @ 01.05.15, 9:30) *
а как "обнулить" переменную типа Документ. , не слетая с типа? и не используя в цикле СоздатьОбъект ?
у меня в комментариях кода указано еще ПолучитьПустоеЗначение(). оказывается "обнуляет", но потом перепозиционировать не дает...

разве что признак нахождения существующего документа писать в другую, числову, переменную.


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

А в принцыпе, поднятый salton вопрос, не особо заслуживает внимания, скорее больше критики. "На коленке" написали, пусть нам он простит, ответы дали по существу, а дальше пускай выбирает варриант и работает над исправлением синтаксических ошибок.

ЗЫ, Автор, если будете читать еще тему, то в Процедуре ЗаполнимДокументыИзТаб после строки:
лпДокОтчет.АвтоВремяТекущее();

нужно еще одну добавить:
лпДокОтчет.Записать();


Signature
То, что для одного человека константа, для другого - переменная. (Алан.Дж.Перлис)

Спасибо сказали: Домовик,

Не нашли ответа на свой вопрос?
Зарегистрируйтесь и задайте новый вопрос.


Ответить Новая тема
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

RSS Текстовая версия Сейчас: 28.04.24, 2:39
1С Предприятие 8.3, 1С Предприятие 8.2, 1С Предприятие 8.1, 1С Предприятие 8.0, 1С Предприятие 7.7, Литература 1С, Общие вопросы по администрированию 1С, Методическая поддержка 1С - всё в одном месте: на Украинском 1С форуме!