Имя: Пароль:
1C
1С v8
Контроль отрицательных остатков (номенклатура с аналогами)
0 rooffy
 
19.06.18
16:04
Доброго дня.
Делаю тестовое задание, столкнулся с проблемой.
Условия примерно такие: номенклатура ведется с аналогами, при нехватке основной номенклатуры списываются аналоги начиная с самого дешевого. Партионный учет по ФИФО.

Сделал через 2 запроса, понимаю, что неоптимально, но в один не смог сделать. В первом запросе по максимуму списывается основная номенклатура по партиям, во втором аналоги, отсортированные по цене.
Так вот, если в расходной накладной например 2 номенклатуры с одним аналогом, то при попытке списать вторую остатки показывает те же, что и на начало списание первой, в результате списывается в минус.

Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    РасходнаяНакладнаяСписокНоменклатуры.Номенклатура КАК Номенклатура,
    |    СУММА(РасходнаяНакладнаяСписокНоменклатуры.Количество) КАК Количество,
    |    СУММА(РасходнаяНакладнаяСписокНоменклатуры.Сумма) КАК Сумма
    |ПОМЕСТИТЬ ВремТаб
    |ИЗ
    |    Документ.РасходнаяНакладная.СписокНоменклатуры КАК РасходнаяНакладнаяСписокНоменклатуры
    |ГДЕ
    |    РасходнаяНакладнаяСписокНоменклатуры.Ссылка = &Ссылка
    |
    |СГРУППИРОВАТЬ ПО
    |    РасходнаяНакладнаяСписокНоменклатуры.Номенклатура
    |
    |ИНДЕКСИРОВАТЬ ПО
    |    Номенклатура
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    ВремТаб.Номенклатура КАК Номенклатура,
    |    ВремТаб.Количество КАК КоличествоВДокументе,
    |    ВремТаб.Сумма КАК СуммаВДокументе,
    |    ОстаткиНоменклатурыОстатки.Партия,
    |    ЕСТЬNULL(ОстаткиНоменклатурыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
    |    ЕСТЬNULL(ОстаткиНоменклатурыОстатки.СуммаОстаток, 0) КАК СуммаОстаток
    |ИЗ
    |    ВремТаб КАК ВремТаб
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(
    |                &МоментВремени,
    |                Номенклатура В
    |                    (ВЫБРАТЬ
    |                        ВремТаб.Номенклатура
    |                    ИЗ
    |                        ВремТаб КАК ВремТаб)) КАК ОстаткиНоменклатурыОстатки
    |        ПО ВремТаб.Номенклатура = ОстаткиНоменклатурыОстатки.Номенклатура
    |
    |УПОРЯДОЧИТЬ ПО
    |    ОстаткиНоменклатурыОстатки.Партия.МоментВремени ВОЗР
    |ИТОГИ
    |    МАКСИМУМ(КоличествоВДокументе),
    |    МАКСИМУМ(СуммаВДокументе),
    |    СУММА(КоличествоОстаток),
    |    СУММА(СуммаОстаток)
    |ПО
    |    Номенклатура";
    
    Запрос.УстановитьПараметр("МоментВремени", Новый Граница(МоментВремени(),ВидГраницы.Исключая ));
    Запрос.УстановитьПараметр("Ссылка",Ссылка);    
    ВыборкаНоменклатура = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    Пока ВыборкаНоменклатура.Следующий() Цикл    
        
        ОсталосьСписать  = ВыборкаНоменклатура.КоличествоВДокументе;                        
        ВыборкаДетЗаписи = ВыборкаНоменклатура.Выбрать();             
        Пока ВыборкаДетЗаписи.Следующий() И ОсталосьСписать <> 0 Цикл
            Если ВыборкаДетЗаписи.КоличествоОстаток > 0 Тогда
                //Движения по регистрам Продажи и Остатки
                ОсталосьСписать = ОсталосьСписать - КСписанию;    
            КонецЕсли;    
            Номенклатура = ВыборкаДетЗаписи.Номенклатура;
            СуммаВДокументе = ВыборкаДетЗаписи.СуммаВДокументе;
        КонецЦикла;        
        
        Если ОсталосьСписать>0 Тогда
            Запрос = Новый Запрос;
            Запрос.Текст =
            "ВЫБРАТЬ
            |    Аналоги.Аналог КАК Номенклатура,
            |    ОстаткиНоменклатурыОстатки.Партия,
            |    ОстаткиНоменклатурыОстатки.СуммаОстаток / ОстаткиНоменклатурыОстатки.КоличествоОстаток КАК Цена,
            |    ОстаткиНоменклатурыОстатки.КоличествоОстаток,
            |    ОстаткиНоменклатурыОстатки.СуммаОстаток
            |ИЗ
            |    РегистрСведений.Аналоги КАК Аналоги
            |        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиНоменклатуры.Остатки(&МоментВремени) КАК ОстаткиНоменклатурыОстатки
            |        ПО Аналоги.Аналог = ОстаткиНоменклатурыОстатки.Номенклатура
            |ГДЕ
            |    Аналоги.Номенклатура = &Номенклатура
            |    И ОстаткиНоменклатурыОстатки.Склад = &Склад
            |
            |УПОРЯДОЧИТЬ ПО
            |    Цена";                          
            Запрос.УстановитьПараметр("Склад",Склад);
            Запрос.УстановитьПараметр("Номенклатура",Номенклатура);
            Запрос.УстановитьПараметр("МоментВремени",Новый Граница(МоментВремени(),ВидГраницы.Исключая));                      
            ВыборкаАналоги = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
            ВыборкаАналогиТаб = Запрос.Выполнить().Выгрузить();
            Пока ВыборкаАналоги.Следующий() И ОсталосьСписать <> 0 Цикл    
                Если ВыборкаАналоги.КоличествоОстаток > 0 Тогда
                    //Движения по регистрам Продажи и Остатки
                    ОсталосьСписать = ОсталосьСписать - КСписанию;    
                КонецЕсли;
            КонецЦикла;
            Если ОсталосьСписать>0 Тогда            
                Отказ = Истина;            
            КонецЕсли;
1 DrShad
 
19.06.18
16:14
запрос в цикле это мощно
погугли ФИФО в запросе
2 FIXXXL
 
19.06.18
16:16
запрос в цикле, да еще и количество неправильно...
сделай хотя бы пакетный из основного состава плюс остатки аналогов
остатки аналогов выгрузи в ТЗ, добавь поле ТекущийОстаток, в который пиши остаток после "проходов", ну и юзай эту ТЗ, а не запрос в цикле, всё нагрузка меньше

ну или почитай про новый подход, когда движения пишутся, а потом читаются расхождения
вот эти расхождения вторым запросом прогоняй таким же образом через аналоги
3 FIXXXL
 
19.06.18
16:22