Имя: Пароль:
1C
1С v8
Сборка товаров
0 Rumpil
 
23.03.12
18:25
У меня существует три таблицы: остатки деталей, возможные товары к сборке и остаток деталей после сборки.

Для большего понимания возьмем пример. У меня есть 4 детали - Д1 в количестве 3 шт., Д2 в количестве 4 шт., Д3 в количестве 5 шт., Д4 остаток которой равен нулю.

Есть 2 товара, Т1 и Т2. Т1 состоит из Д1 в количестве 1 шт., Д2 в количестве 1 шт и Д3 в количестве 1 шт., а Т2 состоит из Д2 в количестве 1 шт. и Д4 в количестве 1 шт.

Существует кнопка "Заполнить таблицы данными". Краткое описание действия кнопки и потом код:

При нажатии кнопка таблица "остатки деталей" заполняется остатками деталей, таблица "остаток деталей после сборки" тоже заполняется такими же данными (данная таблица является динамической и каждый раз по мере потенциальной сборки товаров остатки в ней обновляются с учетом собранных потенциально товаров). Вот код:

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

        НоваяСтрока = Юните.Добавить();
        НоваяСтрока.Юните = Выборка.Номенклатура;
        НоваяСтрока.Количество = Выборка.КоличествоКонечныйОстаток;
       
        НоваяСтрока2 = Динамика.Добавить();
        НоваяСтрока2.Юните = Выборка.Номенклатура;
        НоваяСтрока2.Количество = Выборка.КоличествоКонечныйОстаток;
       
   КонецЦикла;    

Далее начинается переборка всех товаров на возможность сборки - считываются комплектующие(детали) товаров и проверяется возможность сборки по каждой детали. Код:

// считываю все товары из базы    
   ВидТовара2 = Справочники.ВидыНоменклатуры.ЮНИТЕ;

   ЗапросСписок = Новый Запрос;
   ЗапросСписок.Текст =     "ВЫБРАТЬ
                            |    Номенклатура.Ссылка
                            |ИЗ
                            |    Справочник.Номенклатура КАК Номенклатура
                            |ГДЕ
                            |    Номенклатура.ВидНоменклатуры = &ВидТовара
                            |    И Номенклатура.ЭтоГруппа = ЛОЖЬ"    ;
   ЗапросСписок.УстановитьПараметр("ВидТовара", ВидТовара2);                      
   ВыборкаСписок = ЗапросСписок.Выполнить().Выбрать();
   
   Пока ВыборкаСписок.Следующий() Цикл
   
   КоличествоПотенциал = 10000000;

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

   КонецЦикла;



Проблема в чем. Считываются данные по первому товару Т1, все ОК, программа понимает, что можно собрать 3 шт. Т1, после этого остатки в динамической таблице выглядят так:

Д2 - 1 шт.
Д3 - 2 шт.

Когда начинается проверка собираемости второго товара Т2, происходит проверку по каждой комплектующей, первая комплектующая Д2 есть в остатке - 1 шт., соответственно динамическая таблица обновляется, но вот Д4 как оказывается нет в остатке и товар собрать нельзя, но как при этом вернуть обновление динамической таблицы, которое уже было выполнено в ходе проверки по первой комплектующей Д2 ?

Сорри за размытое объяснение, может просто будут у кого идеи в какую сторону рыть ?
1 pumbaEO
 
23.03.12
18:42
Может стоит обратить внимание на симплекс метод? Оптимальное решение? Сделать модель?
2 Михаил Козлов
 
23.03.12
20:28
(1) Симплекс (алгоритм решения задачи линейного программирования - ЛП) можно применить к этой задаче, если коэфф. вхождения детали в товар = 1. Иначе может получиться дробное количество собранного товара.
Формально это задача целочисленного линейного программирования (не очень хороший термин):
Aij - сколько деталей j идет на сборку 1 товара i;
Bj - остаток детали j;
Xi - сколько собираем товара i.
Ограничения:
СУММА(Aij*Xi)<=Bj.
Xi>=0.
Функционал в (0) неопределен. Можно предположить, что это что-то типа суммарной "ценности" собранных товаров:
СУММА(Ci*Xi) => MAX.
Судя по всему, здесь может хорошо сработать неявное ветвление (схема ветвей и границ с отсечением по результату решения релаксированной задачи ЛП).
Или какой-либо вариант "жадного" алгоритма (как в задаче о ранце. Только сразу не понятно, как ранжировать товары: в ранце 1 ограничение и ранжирование по отношению "стоимости" к "весу").
В любом случае имеет смысл повозиться в этом направлении.
Если автор пришлет конкретные численные варианты, мог бы попробовать реализовать (мыло в профиле).
3 Ткачев
 
23.03.12
20:43
А где "- Запрос в цикле, фу как не хорошо..." ?
4 МихаилМ
 
24.03.12
01:07
записывайте
промежуточные вычеты в отдельную таблицу

если набрать запчастей на деталь не удалось
переписывайте обратно.
5 Rumpil
 
25.03.12
14:29
(4) вот как это обратно все переписывать то ? ) у меня на этом заскок