• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

    На последнюю неделю приходится экзамен, где нужно будет показать свои навыки, взломав ряд уязвимых учебных сайтов, и добыть флаги. Успешно сдавшие экзамен получат сертификат.

    Запись на курс до 25 апреля. Получить промодоступ ...

Списание по партиям

  • Автор темы NocturnalMortum
  • Дата начала
N

NocturnalMortum

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

Заранее благодарен.
 
N

NocturnalMortum

Он все так же не берет 1-ю накладную в цикл. Еще не получается условие отбора в запросе построить, он выбирает всю информацию из регистра. Может поменять таблицу регистра? И как сделать условие?
 
U

unknown181538

Таблицу остатков надо брать!
 
N

NocturnalMortum

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

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

unknown181538

Пока Выборка.Следующий() цикл
СписатьКол=Выборка.КоличествоНакл;
КоличествоПартии=Выборка.КоличествоОстаток;
Сообщить (Строка(СписатьКол)+" "+Строка(КоличествоПартии));
Пока СписатьКол<>0 и Выборка.Следующий() цикл
Это неправильно. Функция Следующий() делает перемещение по выборке.
 
N

NocturnalMortum

не могли бы подсказать как будет вернее?
 
U

unknown181538

Надо еще сделать выборку из выборки вложенную и обойти партии.
 
P

puh14

В такой структуре очень геморно получится - лучше сделать так - первый запрос, выборка номенклатуры и количества в накладной. Во время обхода его выборки запоминается количество к списанию и запускается второй запрос к партиям по номенклатуре текущей выборки - его результат выгружается в ТЗ, сортируется (если надо fifo lifo), а дальше списывается пока количество к списанию не станет равным нулю. Важен еще один момент - если партия списывается целиком, то и себестоимость списывается целиком, без всяких пропорциональных расчетов, иначе могут вылезти копеечные остатки при нулевом количестве.
 
N

NocturnalMortum

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


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

тока он все равно не работает =)
 
P

puh14

1)А записать движения? хотя если это проведение - должно и так сработать


2)собственно выше писал про пропорциональное списание. пример - себестоимость 300,01 колво на списание 30000, остаток 30000. Из-за округлений ресурсов регистра у вас зависнет 1 копейка при нулевом количестве.

А в отладчике что видно? по второй выборке он идет? и кстати как идет? не спишет ли он партию от другой номенклатуры?
 
U

unknown181538

В такой структуре очень геморно получится - лучше сделать так - первый запрос, выборка номенклатуры и количества в накладной. Во время обхода его выборки запоминается количество к списанию и запускается второй запрос к партиям по номенклатуре текущей выборки - его результат выгружается в ТЗ, сортируется (если надо fifo lifo), а дальше списывается пока количество к списанию не станет равным нулю. Важен еще один момент - если партия списывается целиком, то и себестоимость списывается целиком, без всяких пропорциональных расчетов, иначе могут вылезти копеечные остатки при нулевом количестве.
Запрос в цикле? Еще и в ТЗ?... А вдруг кто увидит?) Простейшее списание надо учиться делать, а то потом что-нибудь посложнее попадется...
собственно выше писал про пропорциональное списание. пример - себестоимость 300,01 колво на списание 30000, остаток 30000.
Движение.Себестоимость=?(Выборка.КоличествоОстаток=0, 0, Выборка.СебестоимостьОстаток*КолСпис/Выборка.КоличествоОстаток);
300.01*30000/30000 = 300.01. Неужели нет? Это не тот случай.

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

NocturnalMortum

блин один фиг делает одно движение и списывает одной массой...
 
U

unknown181538

А запрос правильный результат возвращает?
 
N

NocturnalMortum

Там еще проблема была в том что я в приходной, не указал параметр ссылки при движении. В общем мне посоветовали все делать не через вложенный запрос, а через временные таблицы. И вот что получилось:
Код:
Запрос=Новый Запрос;
Запрос.Текст ="ВЫБРАТЬ
|	РасходнаяНакладнаяМатериалы.Номенклатура,
|	СУММА(РасходнаяНакладнаяМатериалы.Количество) КАК Количество
|ПОМЕСТИТЬ ДокТЧ
|ИЗ
|	Документ.РасходнаяНакладная.Материалы КАК РасходнаяНакладнаяМатериалы
|ГДЕ
|	РасходнаяНакладнаяМатериалы.Ссылка = &Ссылка
|
|СГРУППИРОВАТЬ ПО
|	РасходнаяНакладнаяМатериалы.Номенклатура
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|	ДокТабл.Номенклатура КАК Номенклатура,
|	ДокТабл.Количество КАК КоличествоНакл,
|	ПартииТовараОстатки.Партия,
|	ЕСТЬNULL(ПартииТовараОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
|	ЕСТЬNULL(ПартииТовараОстатки.СебестоимостьОстаток, 0) КАК СебестоимостьОстаток
|ИЗ
|	ДокТЧ КАК ДокТабл
|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ПартииТовара.Остатки(
|				&МоментВремени,
|				Номенклатура В
|					(ВЫБРАТЬ РАЗЛИЧНЫЕ
|						ДокТЧ.Номенклатура
|					ИЗ
|						ДокТЧ КАК ДокТЧ)) КАК ПартииТовараОстатки
|		ПО ДокТабл.Номенклатура = ПартииТовараОстатки.Номенклатура
|
|УПОРЯДОЧИТЬ ПО
|	ПартииТовараОстатки.Партия.Дата
|ИТОГИ
|	МИНИМУМ(КоличествоНакл),
|	СУММА(КоличествоОстаток)
|ПО
|	Номенклатура";


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

Если ВыборкаИтоги.КоличествоНакл>ВыборкаИтоги.КОличествоОстаток Тогда
Сообщить("Не хватает товара: " + ВыборкаИтоги.Номенклатура+ " из необходимых "+
+ ВыборкаИтоги.КоличествоНакл + " есть только "+ ВыборкаИтоги.КОличествоОстаток);
Отказ=Истина;
КонецЕсли;

Если Отказ Тогда
Продолжить;
КонецЕсли;

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


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


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

все работает, спасибо за помощь.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!