Версия для печати темы (https://pro1c.org.ua/index.php?s=53163baeea6a57f4aec8bcf9a809d05e&showtopic=64784)

Нажмите сюда для просмотра этой темы в обычном формате

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7 _ Тематическое общение _ Автоматизация подбора тары(упаковки) для товара

Автор: kapitoshka_user 19.02.21, 10:59

Всем здравствуйте!

платформа 1С:Предприятие 8.3 (8.3.16.1148)
конфигурация "Управление торговым предприятием для Украины" (1.2.33.2), обычные формы.

Есть очень интересная задаче по автоматическому подбору упаковки товара в тару. Размеры товара и тары могут быть разные - есть список номенклатуры в заказе и перечень доступной тары, габариты (ширина/высота/длина/объем/вес) указаны.
Нужна обработка по оптимальному заполнению товара в упаковку, коробок для упаковки может быть как одна, так и несколько, если не весь товар поместился в одну тару.

Главное условие - это то, что в одной коробке могут быть как тяжелые товары, так и легкие. И упаковывать товар необходимо по уменьшению веса(плотности) товара - снизу идет наиболее тяжелый и объемный товар, а сверху - наиболее легкий.

Подобрать тару и упаковать товар одной весовой категории я могу. Способ не совсем оптимальный, но имеет право на жизнь - по мере упаковки товара всю тару разбиваю на свободные области рядом с уложенным товаром и стараюсь найти подходящий товар по размерам области. Если свободная область, в которую хочу положить товар, больше товара по габаритам - разбиваю исходную область на несколько других областей. Область с товаром отмечаю как заполненную, и получаю несколько свободных областей сверху, сбоку и спереди от товара. Минус - то что свободные области по размерам ограничены габаритами положенного товара и такая раскладка не всегда оптимальна.

А главная задача - это разместить несколько товаров с различной весовой категорией в одну тару наиболее оптимально....
Я не могу найти способы, как можно учитывать свободное пространство в коробке, как запоминать свободные/занятые области. Кто сталкивался с подобной задачей, учет расположения тел в пространстве, трехмерный тетрис в 1ске?

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

Автор: 29a 19.02.21, 12:16

kapitoshka_user @ Сегодня, 10:59 * ,
Реализация на Python https://pro1c.org.ua/redirect.php?https://github.com/hudora/pyShipping
Реализация на PHP https://pro1c.org.ua/redirect.php?https://github.com/yetzt/boxing

Реализация на PHP https://pro1c.org.ua/redirect.php?https://github.com/dvdoug/BoxPacker
Реализация на С++ https://pro1c.org.ua/redirect.php?https://github.com/juj/RectangleBinPack

Автор: 29a 19.02.21, 14:07

в Pythone есть бесплатная библиотека py3dbp в которую передаешь список упаковок (размеры, мах вес), список товаров (размеры, вес), в результате библиотека возвращает варианты размещения.
Применительно к 1С, можно установить интерпретатор Python, из 1С передать в скрипт параметры (коробки, товары), обратно получить варианты размещения.
Пример:

::::::::::: small-envelope(11.500x6.125x0.250, max_weight:10.000) vol(17.609)
FITTED ITEMS:
UNFITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************
::::::::::: small-box(8.625x5.375x1.625, max_weight:70.000) vol(75.334)
FITTED ITEMS:
UNFITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************
::::::::::: large-envelope(15.000x12.000x0.750, max_weight:15.000) vol(135.000)
FITTED ITEMS:
UNFITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************
::::::::::: medium-box(11.000x8.500x5.500, max_weight:70.000) vol(514.250)
FITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
UNFITTED ITEMS:
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************
::::::::::: medium-2-box(13.625x11.875x3.375, max_weight:70.000) vol(546.064)
FITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
UNFITTED ITEMS:
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************
::::::::::: large-box(12.000x12.000x5.500, max_weight:70.000) vol(792.000)
FITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
UNFITTED ITEMS:
***************************************************
***************************************************
::::::::::: large-2-box(23.688x11.750x3.000, max_weight:70.000) vol(835.002)
FITTED ITEMS:
====>  50g [powder 1](3.937x1.968x1.968, weight: 1.000) pos([0, 0, 0]) rt(0) vol(15.248)
====>  50g [powder 2](3.937x1.968x1.968, weight: 2.000) pos([Decimal('3.937'), 0, 0]) rt(0) vol(15.248)
====>  50g [powder 3](3.937x1.968x1.968, weight: 3.000) pos([Decimal('7.874'), 0, 0]) rt(0) vol(15.248)
====>  250g [powder 4](7.874x3.937x1.968, weight: 4.000) pos([Decimal('11.811'), 0, 0]) rt(0) vol(61.008)
====>  250g [powder 5](7.874x3.937x1.968, weight: 5.000) pos([Decimal('19.685'), 0, 0]) rt(1) vol(61.008)
====>  250g [powder 6](7.874x3.937x1.968, weight: 6.000) pos([0, Decimal('1.968'), 0]) rt(0) vol(61.008)
====>  250g [powder 7](7.874x3.937x1.968, weight: 7.000) pos([Decimal('11.811'), Decimal('3.937'), 0]) rt(0) vol(61.008)
====>  250g [powder 8](7.874x3.937x1.968, weight: 8.000) pos([0, Decimal('5.905'), 0]) rt(0) vol(61.008)
UNFITTED ITEMS:
====>  250g [powder 9](7.874x3.937x1.968, weight: 9.000) pos([Decimal('7.874'), 0, Decimal('1.968')]) rt(5) vol(61.008)
***************************************************
***************************************************

Автор: Vofka 19.02.21, 14:22

29a, как 1С получит результат выполнения этого скрипта? Оно же просто в консоль результат показывает?

Автор: kapitoshka_user 19.02.21, 14:25

29a @ Сегодня, 12:16 * ,
Да, я видела алгоритмы. С алгоритмом пока вопросов нет. Но я не понимаю, как могу фиксировать товар в упаковке, как мне запоминать свободную область, т.к. в упаковке может быть несколько уровней с выложенным товаром.
Сейчас я заполняю слой за слоем, после заполнения нижнего слоя - я его закрываю и больше не возвращаюсь к нему, но это же не оптимально - т.к. если на первом уровне есть пустое место, куда ни один товар не поместится, и на втором уровне будет над ним пустое место, в которое ни один товар не поместиться. Но если объединить эти две области - мы сможем упаковать какую-то лампочку, например. Я не знаю, как отслеживать эти области средствами 1с, у меня в этом проблема...

29a @ Сегодня, 14:07 * ,
ух Вы никогда с таким не сталкивалась, покопаю в этом направлении, спасибо

Автор: 29a 19.02.21, 14:31

Цитата(Vofka @ 19.02.21, 14:22) *
29a, как 1С получит результат выполнения этого скрипта? Оно же просто в консоль результат показывает?

В консоли для примера..., вместо вывода как вариант сохранить результат в xml, csv, потом прочитать его средствами 1С

Автор: kapitoshka_user 19.02.21, 14:41

29a @ Сегодня, 14:31 * ,
Спасибо за совет, для себя обязательно посмотрю и попробую реализовать. Но все-таки предпочтение остается выполнять все силами 1ски, т.к. руководство против дополнительных сервисов, и эта операция будет выполняться в базе на рабочих мобильных устройствах.
Поэтому вопрос для меня остается актуален

Автор: 29a 19.02.21, 14:45

kapitoshka_user @ Сегодня, 14:41 * ,
https://pro1c.org.ua/redirect.php?http://xn--80aakg3ded.xn--p1ai/ispolzovanie-python-v-1s/
по ссылке есть пример выполнения кода python из 1С

Автор: Vofka 19.02.21, 15:24

Цитата(29a @ 19.02.21, 14:31) *
вместо вывода как вариант сохранить результат в xml, csv

Я ж правильно понимаю, что возможность сохранения в каком-то формате должна поддерживаться конкретным python скриптом?

Автор: 29a 19.02.21, 15:33

Цитата(Vofka @ 19.02.21, 15:24) *
Я ж правильно понимаю, что возможность сохранения в каком-то формате должна поддерживаться конкретным python скриптом?

Да, вместо вывода в консоль print(), записываем данные в файл, в нужном формате
Например:
f = open(file_name, 'w')
f.write('data_to_write + '\n')
f.close()

Автор: Vofka 19.02.21, 16:24

29a, понял, спасибо!

Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua