|   |   | 
| 
 | Как бы половчее избежать запроса в цикле? | ☑ | ||
|---|---|---|---|---|
| 0
    
        pessok 17.12.14✎ 10:58 | 
        Коллеги, приветствую
 УТ 10.3, несколько допиленная под нужды. В данном случае говорим о розничной продаже в разрезе заказов. Дополнительно сделан РН ТоварыНаБорту, соответственно кладовщик при отгрузке "отправляет" в машину товары, и уже именно из этих товаров формируются документы продажи. Есть обработочка, которая по списку заказов формирует ЧекиККМ, а потом закрытие заказов, чтобы подчистить хвосты. Ранее списание происходило с того склада, который был указан кладовщиком при отправке на борт. Теперь нужно реализовать нечто типа метода списания ФИФО в разрезе организаций, чтобы ЧекККМ создавался на ту организацию, где сейчас есть остатки (т.е. на один заказ может быть N чеков от разных организаций, не спрашивайте зачем, это "узбекский учет" (: ) Притом надо учесть, что созданные ранее чеки тоже виртуально списывают партии (хотя на самом деле спишет уже только ОРП). Чеки создаются группой в одной транзакции, соответственно для каждого конкретного заказа нужно проверить остатки с учетом уже созданных ранее в этой транзакции чеков. Я представляю себе только запрос в цикле (при обходе заказов формируем запрос остатков), а как сделать красивее? | |||
| 1
    
        gerthog 17.12.14✎ 11:06 | 
        (0) Блин, два раза прочитал и ничего не понял(     | |||
| 2
    
        spiller26 17.12.14✎ 11:07 | 
        (1) та же ботва.
 Кусок кода дайте. | |||
| 3
    
        pessok 17.12.14✎ 11:10 | 
        щас, момент     | |||
| 4
    
        H A D G E H O G s 17.12.14✎ 11:14 | 
        (0) Бред какой-то. Почему не РТУ + ПКО?     | |||
| 5
    
        H A D G E H O G s 17.12.14✎ 11:15 | 
        (0) Заказ - это заказ покупателя?
 Как один заказ покупателя может быть на несколько организаций? | |||
| 6
    
        pessok 17.12.14✎ 11:17 | 
        (4) потому что хотят чеки. см. "узбекский учет". Продажа обезличена, но все равно ведется в разрезе заказов
 (5) заказ один, а чеков по нему может быть несколько, на несколько разных организаций. Код, пока не дописан, т.к. я не уверен, что ход мыслей правильный. Пока писал все эти TODO уже, кажись, придумал относительно нормальное решение Процедура СформироватьЧеки(МассивЗаказов) Экспорт Запрос = Новый Запрос( "ВЫБРАТЬ | Заказы.Заказ КАК Заказ, | Заказы.ДатаОтгрузки, | Заказы.КассаПродажи, | Заказы.Номенклатура, | СУММА(Заказы.Количество) КАК Количество, | Заказы.ЕдиницаИзмерения, | Заказы.Цена КАК Цена, | СУММА(Заказы.Сумма) КАК Сумма, | СУММА(Заказы.СуммаНДС) КАК СуммаНДС, | Заказы.Водитель |ПОМЕСТИТЬ Заказы |ИЗ | (ВЫБРАТЬ | ЗаказыПокупателей.ЗаказПокупателя.АдресТочки.КассаПродажи КАК КассаПродажи, | ЗаказыПокупателей.ЗаказПокупателя КАК Заказ, | ЗаказыПокупателей.ЗаказПокупателя.ДатаОтгрузки КАК ДатаОтгрузки, | ТоварыНаБортуОстатки.Водитель КАК Водитель, | ЗаказыПокупателей.Номенклатура КАК Номенклатура, | ЗаказыПокупателей.ЕдиницаИзмерения КАК ЕдиницаИзмерения, | ЗаказыПокупателей.Цена КАК Цена, | ТоварыНаБортуОстатки.КоличествоОстаток КАК Количество, | ТоварыНаБортуОстатки.КоличествоОстаток * ЗаказыПокупателей.Цена КАК Сумма, | (ТоварыНаБортуОстатки.КоличествоОстаток * ЗаказыПокупателей.Цена / 1.18 - ТоварыНаБортуОстатки.КоличествоОстаток * ЗаказыПокупателей.Цена) * -1 КАК СуммаНДС | ИЗ | РегистрНакопления.ЗаказыПокупателей.Обороты( | , | , | , | ЗаказПокупателя В (&Заказы) | И ДоговорКонтрагента.Владелец = ЗНАЧЕНИЕ(Справочник.Контрагенты.ФизЛицо)) КАК ЗаказыПокупателей | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаБорту.Остатки(, ЗаказПокупателя В (&Заказы)) КАК ТоварыНаБортуОстатки | ПО ЗаказыПокупателей.ЗаказПокупателя = ТоварыНаБортуОстатки.ЗаказПокупателя | И ЗаказыПокупателей.Номенклатура = ТоварыНаБортуОстатки.Номенклатура | ГДЕ | ТоварыНаБортуОстатки.КоличествоОстаток > 0) КАК Заказы | |СГРУППИРОВАТЬ ПО | Заказы.Номенклатура, | Заказы.ЕдиницаИзмерения, | Заказы.Заказ, | Заказы.Цена, | Заказы.Водитель, | Заказы.КассаПродажи, | Заказы.ДатаОтгрузки |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ЧекККМ.Ссылка КАК ЧекККМ, | ЧекККМ.ЗаказПокупателя, | ЧекККМ.Организация |ПОМЕСТИТЬ ЧекиККМ |ИЗ | Документ.ЧекККМ КАК ЧекККМ |ГДЕ | НЕ ЧекККМ.ПометкаУдаления | |СГРУППИРОВАТЬ ПО | ЧекККМ.Ссылка, | ЧекККМ.ЗаказПокупателя, | ЧекККМ.Организация | |ОБЪЕДИНИТЬ ВСЕ | |ВЫБРАТЬ | ОтчетОРозничныхПродажахТовары.Ссылка, | ОтчетОРозничныхПродажахТовары.ЗаказПокупателя, | ОтчетОРозничныхПродажахТовары.Ссылка.Организация |ИЗ | Документ.ОтчетОРозничныхПродажах.Товары КАК ОтчетОРозничныхПродажахТовары |ГДЕ | НЕ ОтчетОРозничныхПродажахТовары.Ссылка.ПометкаУдаления | |СГРУППИРОВАТЬ ПО | ОтчетОРозничныхПродажахТовары.Ссылка, | ОтчетОРозничныхПродажахТовары.ЗаказПокупателя, | ОтчетОРозничныхПродажахТовары.Ссылка.Организация |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | Заказы.Заказ КАК ЗаказПокупателя, | Заказы.ДатаОтгрузки КАК Дата, | Заказы.Водитель КАК Водитель, | ЧекиККМ.ЧекККМ КАК ЧекККМ, | Заказы.КассаПродажи, | Заказы.Номенклатура, | Заказы.Количество КАК Количество, | Заказы.ЕдиницаИзмерения, | Заказы.Цена, | Заказы.Сумма КАК Сумма, | Заказы.СуммаНДС КАК СуммаНДС |ИЗ | Заказы КАК Заказы | ЛЕВОЕ СОЕДИНЕНИЕ ЧекиККМ КАК ЧекиККМ | ПО Заказы.Заказ = ЧекиККМ.ЗаказПокупателя |ИТОГИ | СУММА(Количество), | СУММА(Сумма), | СУММА(СуммаНДС) |ПО | ЗаказПокупателя"); Запрос.УстановитьПараметр("Заказы", МассивЗаказов); ВыборкаЗаказ = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам); Пока ВыборкаЗаказ.Следующий() Цикл МассивЗаказов = Новый Массив(); МассивЗаказов.Добавить(ВыборкаЗаказ.Заказ); ТаблицаОстатков = СформироватьТаблицуОстатковПартийПоЗаказам(МассивЗаказов); // получение остатков для заказа с учетом чеков //TODO сделать обход остатков по товарам, сформировать таблицу организаций, складов, товаров под спиание //пройтись циклом по полученной таблице и создать документы Документ = Документы.ЧекККМ.СоздатьДокумент(); ЗаполнениеДокументов.ЗаполнитьШапкуДокумента(Документ, ПараметрыСеанса.ТекущийПользователь); ЗаполнитьЗначенияСвойств(Документ, ВыборкаЗаказ); Документ.Организация = Справочники.Организации.НайтиПоКоду("Р00000002"); //TODO заполнение должно идти по таблице, сформированной для остатков Документ.Комментарий = "Создан на основании "+ВыборкаЗаказ.ЗаказПокупателя+" по складу "; //TODO заполнение должно идти по таблице, сформированной для остатков ВыборкаДетали = ВыборкаЧекККМ.Выбрать(); Пока ВыборкаДетали.Следующий() Цикл //TODO список товаров и количество уже должно заполняться по таблице остатков Товар = Документ.Товары.Добавить(); ЗаполнитьЗначенияСвойств(Товар, ВыборкаДетали); Товар.Коэффициент = Товар.ЕдиницаИзмерения.Коэффициент; КонецЦикла; Документ.СуммаДокумента = Документ.Товары.Итог("Сумма"); НСтр = Документ.Оплата.Добавить(); НСтр.ВидОплаты = Справочники.ВидыОплатЧекаККМ.Наличные; НСтр.Сумма = Документ.СуммаДокумента; Попытка Документ.Записать(РежимЗаписиДокумента.Проведение); Сообщить("Записан "+Документ.Ссылка); Исключение Сообщить("Ошибка "+ОписаниеОшибки()); КонецПопытки; КонецЦикла; КонецПроцедуры Функция СформироватьТаблицуОстатковПартийПоЗаказам(МассивЗаказов) Экспорт //формируем массив номенклатуры и дат ТаблицаНоменклатураЗаказ = Новый ТаблицаЗначений; ТаблицаНоменклатураЗаказ.Колонки.Добавить("ЗаказПокупателя", Новый ОписаниеТипов("ДокументСсылка.ЗаказПокупателя")); ТаблицаНоменклатураЗаказ.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура")); ТаблицаНоменклатураЗаказ.Колонки.Добавить("ДатаОтгрузки", Новый ОписаниеТипов("Дата")); ТаблицаНоменклатураЗаказ.Колонки.Добавить("АдресТочки", Новый ОписаниеТипов("СправочникСсылка.ТорговыеТочки")); СписокДат = Новый ТаблицаЗначений; СписокДат.Колонки.Добавить("ДатаОтгрузки", Новый ОписаниеТипов("Дата")); Для Каждого ЗаказПокупателя Из МассивЗаказов Цикл ЗаполнитьЗначенияСвойств(СписокДат.Добавить(), ЗаказПокупателя); Для Каждого ТекСтр Из ЗаказПокупателя.Товары Цикл НовСтр = ТаблицаНоменклатураЗаказ.Добавить(); НовСтр.ЗаказПокупателя = ЗаказПокупателя; НовСтр.Номенклатура = ТекСтр.Номенклатура; ЗаполнитьЗначенияСвойств(НовСтр, ЗаказПокупателя); КонецЦикла; КонецЦикла; СписокНоменклатуры = ОбщегоНазначения.УдалитьПовторяющиесяЭлементыМассива(ТаблицаНоменклатураЗаказ.ВыгрузитьКолонку("Номенклатура")); СписокДат.Свернуть("ДатаОтгрузки"); СписокДат.Сортировать("ДатаОтгрузки Возр"); //получаем остатки Запрос = Новый Запрос(); Запрос.Текст = "ВЫБРАТЬ | ДатыОтгрузки.ДатаОтгрузки КАК Период |ПОМЕСТИТЬ ВТДатыОтгрузки |ИЗ | &ДатыОтгрузки КАК ДатыОтгрузки |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ЗаказыНоменклатура.ЗаказПокупателя, | ЗаказыНоменклатура.ДатаОтгрузки, | ЗаказыНоменклатура.Номенклатура, | ЗаказыНоменклатура.АдресТочки |ПОМЕСТИТЬ ВТЗаказыНоменклатура |ИЗ | &ЗаказыНоменклатура КАК ЗаказыНоменклатура |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ РАЗЛИЧНЫЕ | ТорговыеТочкиДоступныеСклады.Склад |ПОМЕСТИТЬ ВТДоступныеСклады |ИЗ | Справочник.ТорговыеТочки.ДоступныеСклады КАК ТорговыеТочкиДоступныеСклады |ГДЕ | ТорговыеТочкиДоступныеСклады.Ссылка В | (ВЫБРАТЬ | ВТЗаказыНоменклатура.АдресТочки | ИЗ | ВТЗаказыНоменклатура) |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ВложенныйЗапросОстатков.Период, | ВложенныйЗапросОстатков.Организация, | ВложенныйЗапросОстатков.Склад, | ВложенныйЗапросОстатков.Номенклатура, | ВложенныйЗапросОстатков.КоличествоКонечныйОстаток |ИЗ | (ВЫБРАТЬ | ВТДатыОтгрузки.Период КАК Период, | ОстаткиПартий.Организация КАК Организация, | ОстаткиПартий.Склад КАК Склад, | ОстаткиПартий.Номенклатура КАК Номенклатура, | ОстаткиПартий.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток | ИЗ | ВТДатыОтгрузки КАК ВТДатыОтгрузки | ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | Оборот1.Дата КАК ДатаС, | МИНИМУМ(ВЫБОР | КОГДА Оборот2.Дата ЕСТЬ NULL | ТОГДА КОНЕЦПЕРИОДА(&КонецПериода, ДЕНЬ) | ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(Оборот2.Дата, ДЕНЬ, -1), ДЕНЬ) | КОНЕЦ) КАК ДатаПо, | Оборот1.Организация КАК Организация, | Оборот1.Склад КАК Склад, | Оборот1.Номенклатура КАК Номенклатура, | Оборот1.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток | ИЗ | (ВЫБРАТЬ | ПартииТоваровНаСкладахОстаткиИОбороты.Период КАК Дата, | ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор.Организация КАК Организация, | ПартииТоваровНаСкладахОстаткиИОбороты.Склад КАК Склад, | ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура, | ПартииТоваровНаСкладахОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток | ИЗ | РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты( | &НачалоПериода, | &КонецПериода, | Запись, | , | Номенклатура В (&СписокНоменклатуры) | И Склад В | (ВЫБРАТЬ | ВТДоступныеСклады.Склад | ИЗ | ВТДоступныеСклады)) КАК ПартииТоваровНаСкладахОстаткиИОбороты) КАК Оборот1 | ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | ПартииТоваровНаСкладахОстаткиИОбороты.Период КАК Дата, | ПартииТоваровНаСкладахОстаткиИОбороты.Регистратор.Организация КАК Организация, | ПартииТоваровНаСкладахОстаткиИОбороты.Склад КАК Склад, | ПартииТоваровНаСкладахОстаткиИОбороты.Номенклатура КАК Номенклатура | ИЗ | РегистрНакопления.ПартииТоваровНаСкладах.ОстаткиИОбороты( | &НачалоПериода, | &КонецПериода, | Запись, | , | Номенклатура В (&СписокНоменклатуры) | И Склад В | (ВЫБРАТЬ | ВТДоступныеСклады.Склад | ИЗ | ВТДоступныеСклады)) КАК ПартииТоваровНаСкладахОстаткиИОбороты) КАК Оборот2 | ПО Оборот1.Дата < Оборот2.Дата | И Оборот1.Номенклатура = Оборот2.Номенклатура | И Оборот1.Склад = Оборот2.Склад | И Оборот1.Организация = Оборот2.Организация | | СГРУППИРОВАТЬ ПО | Оборот1.Дата, | Оборот1.Номенклатура, | Оборот1.КоличествоКонечныйОстаток, | Оборот1.Склад, | Оборот1.Организация) КАК ОстаткиПартий | ПО (ВТДатыОтгрузки.Период МЕЖДУ НАЧАЛОПЕРИОДА(ОстаткиПартий.ДатаС, ДЕНЬ) И КОНЕЦПЕРИОДА(ОстаткиПартий.ДатаПо, ДЕНЬ))) КАК ВложенныйЗапросОстатков | ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | ТоварыНаСкладахОбороты.Регистратор.Организация КАК Организация, | ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура, | СУММА(ТоварыНаСкладахОбороты.КоличествоРасход) КАК КоличествоСписанийПоЧекам | ИЗ | РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, Запись, ) КАК ТоварыНаСкладахОбороты | ГДЕ | ТоварыНаСкладахОбороты.Регистратор ССЫЛКА Документ.ЧекККМ | | СГРУППИРОВАТЬ ПО | ТоварыНаСкладахОбороты.Номенклатура, | ТоварыНаСкладахОбороты.Регистратор.Организация) КАК СписанныеЧекамиТовары | ПО ВложенныйЗапросОстатков.Организация = СписанныеЧекамиТовары.Организация | И ВложенныйЗапросОстатков.Номенклатура = СписанныеЧекамиТовары.Номенклатура |АВТОУПОРЯДОЧИВАНИЕ"; Запрос.УстановитьПараметр("ДатыОтгрузки", СписокДат); Запрос.УстановитьПараметр("СписокНоменклатуры", СписокНоменклатуры); Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(СписокДат[0].ДатаОтгрузки)); Запрос.УстановитьПараметр("КонецПериода", КонецДня(СписокДат[СписокДат.Количество()-1].ДатаОтгрузки)); Запрос.УстановитьПараметр("ЗаказыНоменклатура", ТаблицаНоменклатураЗаказ); Возврат Запрос.Выполнить().Выгрузить(); КонецФункции | |||
| 7
    
        batman69 17.12.14✎ 11:21 | 
        (6) мля..     | |||
| 8
    
        pessok 17.12.14✎ 11:21 | 
        +(6) более верное, на мой взгляд, решение появилось:
 сначала сформировать полную таблицу остатков, а потом уже непосредственно в ней при создании чеков уменьшать количество остатка по организации. И для этой таблице при обходе искать соответствия | |||
| 9
    
        H A D G E H O G s 17.12.14✎ 11:21 | 
        (6) Удачи вам, мистер Горски.     | |||
| 10
    
        pessok 17.12.14✎ 11:21 | 
        (7) конкретнее, пожалуйста ;)     | |||
| 11
    
        pessok 17.12.14✎ 11:22 | 
        (9) да кто спорит, что это жутота, но делать надо     | |||
| 12
    
        spiller26 17.12.14✎ 11:24 | 
        (6) ВыборкаЗаказ = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам) 
 Зачем группировка??? Зачем в запросе Итоги? | |||
| 13
    
        Garykom гуру 17.12.14✎ 11:24 | 
        Ух ты "рюкзачки"     | |||
| 14
    
        pessok 17.12.14✎ 11:26 | 
        (12) это еще старый вариант просто, когда для одного заказа четко создавался один чек по организации заказа. Заполнять чеки удобнее по группировкам. Итоги не нужны, согласен     | |||
| 15
    
        Garykom гуру 17.12.14✎ 11:26 | 
        Кстати запросы считают что то (когда + и -) медленно, они тока выборку быстро делают данных (по индексам)
 Так что самое быстрое и без запросов в цикле, это запросом строим таблицу(ы) и дальше по ней(ним) работаем | |||
| 16
    
        pessok 17.12.14✎ 11:28 | 
        (15) ну вот я так и подумал. в (8) описал     | |||
| 17
    
        spiller26 17.12.14✎ 11:32 | 
        Можно сделать все в одном запросе, но долго
 "МассивЗаказов" загнать в ВТ_МассивЗаказов Функцию СформироватьТаблицуОстатковПартийПоЗаказам(МассивЗаказов) переработать в запрос | |||
| 18
    
        pessok 17.12.14✎ 11:35 | 
        (17) не можно, к сожалению. мне нужно проверять чеки, которые уже созданы в этой транзакции. Т.е:
 В массиве заказов два заказа. в каждом "Номенклатура А" - 1 шт У нас есть по одной партии этого товара на каждой из двух организаций. Соответственно после того, как создался первый чек остатки уже изменились, второй чек должен создаваться с учетом этого | |||
| 19
    
        pessok 17.12.14✎ 11:36 | 
        (18) посему оптимальное, на мой взгляд, сразу создать таблицу остатков и уже при создании чеков убирать из нее "списанную" чеком номенклатуру     | |||
| 20
    
        Михаил Козлов 17.12.14✎ 11:48 | 
        (19)+. Как модуле партионного учета.     | |||
| 21
    
        mdocs 17.12.14✎ 11:56 | 
        (0) набор умных слов. Сначала надо написать работающий код, потом думать об оптимизации. Если можете сразу все продумать оптимально, то это отлично. Если нет - то пишите хоть как нибудь но чтоб на выходе были верные данные.     | |||
| 22
    
        pessok 17.12.14✎ 12:02 | 
        (21) вот это как раз таки плохой подход. надо сразу писать нормально. потому что в противной случае этот копрокод так и останется навсегда     | 
 
 | Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |