Имя: Пароль:
1C
1С v8
Подозрение на зацикливание
,
0 madnus
 
07.04.18
22:52
Всем привет. Я только учусь программировать, поэтому строго не судите(( Есть документ Расходная накладная, в табличной части для каждого товара пользователь указывает партию, которую необходимо списать. В том случае, если товара по указанной партии не хватает, документ не проводится и выводится соответствующее сообщение о нехватке. Написал код, в случае, если товара хватает, всё проводится нормально. В случае, когда пытаюсь провести товара больше, чем есть партии, всё зависает. Не могу понять в чем ошибка, подозрение на зацикливание. Условия для прерывания цикла вроде сделал. Помогите разобраться ( Код ниже

Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |   РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура,
        |   РасходнаяНакладнаяСписокНоменклатуры.Партия КАК Партия,
        |   СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество
        |ПОМЕСТИТЬ ВТТовары
        |ИЗ
        |   Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры
        |ГДЕ
        |   РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка
        |   И РасходнаяНакладнаяСписокНоменклатуры.Номенклатура.ВидНоменклаутры = &ВидНоменклаутрыТовар
        |
        |СГРУППИРОВАТЬ ПО
        |   РасходнаяНакладнаяСписокНоменклатуры.Номенклатура,
        |   РасходнаяНакладнаяСписокНоменклатуры.Партия
        |
        |ИНДЕКСИРОВАТЬ ПО
        |   Номенклатура,
        |   Партия
        |;
        |
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |   ВТТовары.Номенклатура,
        |   ВТТовары.Партия,
        |   ВТТовары.Количество,
        |   ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
        |   ЕСТЬNULL(ОстаткиНоменклатурыОстатки.СебестоимостьОстаток, 0) КАК СебестоимостьОстаток
        |ИЗ
        |   ВТТовары КАК ВТТовары
        |       ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(
        |               &МоментВремени,
        |               (Номенклатура, Партия) В
        |                   (ВЫБРАТЬ
        |                       ВТТовары.Номенклатура,
        |                       ВТТовары.Партия
        |                   ИЗ
        |                       ВТТовары КАК ВТТовары)) КАК ОстаткиНоменклатурыОстатки
        |       ПО ВТТовары.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура
        |           И ВТТовары.Партия = ОстаткиНоменклатурыОстатки.Партия";
    
    Запрос.УстановитьПараметр("ВидНоменклаутрыТовар", Перечисления.ВидыНоменклатуры.Товар);
    Запрос.УстановитьПараметр("МоментВремени", МоментВремени());
    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        
        КолвоКСписанию = ВыборкаДетальныеЗаписи.Количество;
        
        Цена = ВыборкаДетальныеЗаписи.СебестоимостьОстаток / ВыборкаДетальныеЗаписи.КоличествоОстаток;
        
        Если КолвоКСписанию > ВыборкаДетальныеЗаписи.КоличествоОстаток Тогда
            Сообщить("Не хватает товара " + ВыборкаДетальныеЗаписи.Номенклатура +
            " в количестве " + (КолвоКСписанию - ВыборкаДетальныеЗаписи.КоличествоОстаток));
            Отказ = Истина;
            Продолжить;
        КонецЕсли;
        
            Движение = Движения.ОстаткиНоменклатуры.Добавить();
            Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
            Движение.Период = Дата;
            Движение.Номенклатура = ВыборкаДетальныеЗаписи.Номенклатура;
            Движение.Партия = ВыборкаДетальныеЗаписи.Партия;
            Движение.Количество = КолвоКСписанию;
            
            Если КолвоКСписанию < ВыборкаДетальныеЗаписи.КоличествоОстаток Тогда
                Движение.Себестоимость = Цена * КолвоКСписанию;
            Иначе
                Движение.Себестоимость = ВыборкаДетальныеЗаписи.СебестоимостьОстаток;
            КонецЕсли;
        
    КонецЦикла;
    
    
    
    // регистр ОстаткиНоменклатуры Расход
    Движения.ОстаткиНоменклатуры.Записывать = Истина;
1 DmitriyDI
 
07.04.18
23:43
(0) по коду вроде все в норме нужно отладчиком пройтись и замеры сделать посмотреть на чем зависает.
2 Веселый собака
 
08.04.18
10:28
Отказ = Истина;
Продолжить;
        

Может все же "Прервать"?
А не перебирать все?
3 madnus
 
08.04.18
11:21
(1) Отладчиком ходил. Самое интересное, что при прохождении отладчиком иногда всё отрабатывает корректно, хотя я в коде ничего не меняю. Но в 70% случае отладчик проходит и всё снова виснет. Думал ошибка в коде, но видимо у меня что то глючит.
4 madnus
 
08.04.18
11:22
(2) Пробовал и через Прервать, пробал и после цикла в процедуре Возврат. Ничего не меняется
5 madnus
 
08.04.18
12:08
Решил вопрос. Убрал из параметров РН в запросе Партию и сделал:


        |               Номенклатура В
        |                   (ВЫБРАТЬ
        |                       ВТТовары.Номенклатура
        |                   ИЗ
        |                       ВТТовары КАК ВТТовары)) КАК ОстаткиНоменклатурыОстатки

Теперь всё отрабатывает верно, но я не могу понять почему. Если кто то может, проясните, пожалуйста, почему так, чтобы в будущем я понимал и не допускал таких ошибок.
6 youalex
 
08.04.18
12:42
1.ВыборкаДетальныеЗаписи.Номенклатура - так лучше не делать, получай представление в запросе (хоть Номенклатура.Представление), и выводи пользаку его.

2. Не вижу УПОРЯДОЧИТЬ ПО в запросе. Какой метод списания по условию задачи?  

3. Прерывать цикл не нужно, по идее тебе нужно вывести пользаку все товары с отрицательным количеством, а не по одному их выуживать)) . Тут "Продолжить" - правильно.
7 youalex
 
08.04.18
12:46
(6) + понял, по п.2 - партии прямо в документе указаны.
Используй замер производительности.
8 Borteg
 
08.04.18
13:31
(0)    ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(
        |               &МоментВремени,
        |               (Номенклатура, Партия) В
        |                   (ВЫБРАТЬ
        |                       ВТТовары.Номенклатура,
        |                       ВТТовары.Партия
        |                   ИЗ
        |                       ВТТовары КАК ВТТовары)) КАК ОстаткиНоменклатурыОстатки
        |       ПО ВТТовары.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура
        |           И ВТТовары.Партия = ОстаткиНоменклатурыОстатки.Партия";

Убери условия
(Номенклатура, Партия) В
        |                   (ВЫБРАТЬ
        |                       ВТТовары.Номенклатура,
        |                       ВТТовары.Партия
        |                   ИЗ
        |                       ВТТовары КАК ВТТовары)

Ты это отберешь левым соединением.
Регистр то остатки номенклатуры большой?
9 youalex
 
08.04.18
13:47
(8) >>Убери условия ..>> Ты это отберешь левым соединением.

Минус два балла (вроде два) на экзамене.
10 madnus
 
08.04.18
16:43
(6) Метод списание в задаче не указан. В табличной части расходной накладной пользователь сам выбирает партию, с которой списывает товар, поэтому рассчитываю себестоимость по каждой партии отдельно
11 madnus
 
08.04.18
16:44
(9) я убрал из условия только Партию и у меня всё заработало нормально. Это будет считаться ошибкой на экзамене ? Оставил только номенклатуру там
12 youalex
 
08.04.18
18:10
(11) Ну, буквально, условие ошибки звучит как "Отсутствие значений параметров в виртуальной таблице или использование вместо них условия «ГДЕ»"  
То, что вы не отбираете по партии в параметрах вт - лично мое мнение, это не будет воспринято как ошибка. Но правильно будет  ее использовать.  Убедиться, что тупит именно запрос. Консоль запросов вам в помощь. Далее - убедиться, что тупит именно получение остатков (результат по остаткам есть смысл писать во временную таблицу). Смотреть на структуру регистра (нет ли измерений между Номенклатурой и Партией, например). Если есть возможность - прогнать эти тесты на серверной базе, на мс скуле. Тут вам поможет штатный профайлер скуля.
Пользователь не знает, чего он хочет, пока не увидит то, что он получил. Эдвард Йодан