Комбинатор. Подбор суммы из набора чисел. Обработка для 1С версии 8.х (УФ)




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

30 Comments

  1. MSConfig

    Вот эту энергию и в мирное русло бы!

    Reply
  2. romasna

    (1)Не понял… что не так?

    Reply
  3. CheBurator

    шпарит тупым перебором? или более интеллектуальные варианты решения задачи рбкзака применяются?

    Reply
  4. starik-2005

    http://infostart.ru/public/437890/ — чтобы не перебирать все.

    Reply
  5. romasna

    (3)Скачай и посмотри, пожалуйста, если интересно. Работает быстро. Из нескольких сотен случайных чисел подбирает сумму в среднем за 5сек. Надо только умело и творчески подойти к процессу. Не веришь — проверь. Генератор случайных чисел включен… Тупой перебор не выложил бы здесь — даже не стал бы позориться. 😉 А энергию свою я употребил, когда потребовалось, на решение 3 разных задач. И в основе их — этот подбор сумм.

    Reply
  6. romasna

    (3)О, пардон… это не ты пытался мою энергию в мирное русло направить… 🙂

    Reply
  7. romasna

    (4)Лично я не против многообразия. Свои алгоритмы я программировал без шпаргалок. Что получилось — выложил. Мож кому понравятся. Денег не прошу. 🙂 Я не перебираю все.

    Reply
  8. starik-2005

    (7)

    Денег не прошу. 🙂 Я не перебираю в

    1 стартмани стоит каких-никаких денег. Было бы интересно знать суть алгоритма. Фактически все условно быстрые алгоритмы не дают 100% точности кроме рюкзака. А рюкзак требует памяти (на каждую копейку до искомой суммы * количество сумм).

    Reply
  9. romasna

    (8)Стартмани стоят для нас с тобой только некоторых усилий… что-то разработал, выложил, получил… Или не так? Была бы моя воля, я бы и даром выложил эту обработку, — не жалко.

    Что же до алгоритмов: большая часть суммы подбирается случайно (процент регулируешь ползунком), а потом — да, тупой перебор, но отбрасываются все тупиковые варианты. И если процесс длится долго, например, больше 20секунд, случайный набор чисел меняется на новый, если указано несколько попыток подбора.

    Reply
  10. romasna

    (3)Кстати, обращаю твое внимание на картинку к статье. Внизу строчка: требуемая сумма подобрана с первой попытки. На попытку не больше 20сек. было отведено. (Обычно, я и 20секунд не выставлял, а 5-10). Чисел для перебора около 140. Как ты знаешь, простой перебор за такое время результат не даст. На случайном наборе чисел все работает изумительно. Медленнее всего подбираются слишком маленькие и слишком большие (приграничные) суммы.

    Reply
  11. CheBurator

    интересует за сколько отработает алгоритм для ~100 разных подборов, на которых в каждом подборе ~15 чисел и они близки друг к другу

    Reply
  12. romasna

    (11)Полагаю, надо провести следственный эксперимент… давай набор чисел и требуемую сумму. Посмотрю.

    Reply
  13. CheBurator

    так мне без разницы — что числа выдавать что смотреть… сам посмотрю если припрет.

    а если припрет — придетяс из разработки выдирать колд, или там унутре есть функция на вход клоторой масив с данными — на выходе результат?

    Reply
  14. romasna

    (13)Вызываешь обработку модально, передав в нее список значений. Получив результат, давишь кнопку «Готово», — вываливаешься из обработки. На выходе в списке значений имеем требуемое. Задачи подобного рода я не решаю на полном автомате, — в меру своих умений вмешиваюсь в процесс получения результата. И обычно его получаю быстро, даже когда требуется полное совпадение с суммой.

    Передается именно список значений, а не массив. Это позволяет решать задачи количественно-суммовые. Например, из остатков подобрать номенклатуру на заданную сумму в количестве и ценах.

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

    Reply
  15. jaroslav.h

    Ану подскажите, есть ТЧ дока, мне нужно из этой ТЧ выбрать коство шт. товару на определенную сумму, и я знаю, что эта сумма есть в этой тч, эта обработка такое решает?

    Reply
  16. romasna

    (15)И «да», и «нет». «Нет», — потому что эта обработка позволяет только сумму подобрать из имеющихся значений. Но также и «Да», потому что она лежит в основе решения твоей задачи. Вот только прежде чем перейти к подбору суммы по номенклатуре, необходимо до вызова обработки специальным образом обработать эту самую номенклатуру. Такой простой пример: есть у тебя 6 карандашей на сумму 24 рубля. В обработку передаешь несколько элементов по этим карандашам в списке значений:

    12 — Карандаш 3шт.

    8 — Карандаш 2шт.

    4 — карандаш 1шт.

    Эти 3 элемента позволяют набрать суммы; 4, 8, 12, 16, 20, 24

    Допустим тебе нужна сумма 20. Эта обработка в списке значений вернет тебе 2 записи:

    12 — Карандаш 3шт.

    8 — Карандаш 2шт.

    Обработав их, получишь: 5 карандашей на сумму 20.

    Reply
  17. Fanil

    отлично работает, когда необходимо подделать что-то в оборотке)))

    Reply
  18. romasna

    (17) Очень рад, что она тебе помогла нести светлое людям. 🙂

    Reply
  19. dndw

    Каким то образом можно ограничить выбор только определенным количеством элементов, т.е. чтобы сумма получалась как сумма только 5 (или любого другого числа) элементов из всего набора чисел?

    Reply
  20. romasna

    (19) Здравствуйте. Этой обработкой можно получить разные комбинации чисел на определенную заданием сумму. Можно, разве что, смотреть на то, что получилось по количеству чисел и выбирать подходящую комбинацию (программно, разумеется. Это не требует изменений обработки).

    Или, найдите в коде то место, где анализируется промежуточный результат поиска и включите отказ от любого из них, которое не удовлетворяет Вашему дополнительному условию (уже много чисел!),- это может немного ускорить подбор. И это еще не все ускорение, которое можно получить… есть варианты. Но, на текущий момент такая функциональность не была предусмотрена.

    Reply
  21. dndw

    (20)

    Или, найдите в коде то место, где анализируется промежуточный результат поиска и включите отказ от любого из них

    Подскажите пожалуйста, где это происходит в коде.

    Reply
  22. romasna

    Могу я поинтересоваться, какую задачу Вы решаете? Для чего такое ограничение? Оно может весьма существенно увеличить время подбора…

    Reply
  23. romasna

    (21) Очевидно, что нужно ввести реквизит формы на количество слагаемых результата.

    Функция ВыбратьСочетания (ИзЭн, ПоЭм) — запускает последовательность сочетаний ИзЭн ПоЭм; не трогаем.

    Функция ПолучитьСочетание (Сочетание, ИзЭн, ПоЭм) — формирует следующее сочетание ИзЭн ПоЭм; не трогаем.

    Изменения нужно внести в Процедура ОбработатьСочетание (Сочетание)

    Сочетание — массив, количество элементов которого и есть количество слагаемых, которое нужно держать на контроле. Обращаю внимание, что в этой процедуре нарушается «нормальная» последовательность сочетаний, отсекаются заведомо не приводящие к нужному результату.

    И это еще не все.

    Процедура СлучайныйПодбор() — надо либо отказываться от случайного подбора, когда есть ограничение на к-во слагаемых, либо в него тоже внести поправки с учетом новых требований. И над этим нужно по-медитировать…

    Reply
  24. romasna

    (21) Меня только что осенило… надо ведь попросту рассмотреть только сочетания ИзЭн ПоЭм, когда ПоЭм равно требуемому количеству слагаемых за вычетом количества случайно подобранных. И тогда Процедура ОбработатьСочетание (Сочетание) — не трогаем. Все просто.

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

    Reply
  25. dndw

    Сохранение количества и суммы при изменении цены.

    Reply
  26. romasna

    Это совсем другого порядка задача. Предложенное мной выше решение — это совсем-совсем не то, что требуется. Я то полагал, что нужно подобрать сумму при фиксированном количестве слагаемых. В принципе, и это решение подойдет, если целочисленное количество и всю номенклатуру отдельными позициями подать в подбор, когда к-во равно 1. Да, так сработает.

    Reply
  27. dndw

    Что такое и планировал сделать развернуть все позиции до 1, и дальше составлять комбинацию.

     Сочетание = Новый Массив;
    Если ПоЭм <= ИзЭн
    Тогда
    //Если ПоЭм =7 Тогда  /Где то в этом месте нужно вводить проверку?
    Для Инд = 1 По ПоЭм Цикл
    Сочетание.Добавить(Инд);
    КонецЦикла;
    КонецЕсли;
    //КонецЕсли;
    Возврат Сочетание;
    

    Показать

    Reply
  28. romasna

    (25)

    Reply
  29. romasna

    (27) Еще раз… в подбор забрасываем всю номенклатуру: каждая строка подбора это отдельная (кво=1) позиция номенклатуры. Например, у нас 10 наименований по 5 штук каждого — итого 50 строк подбора (сумма каждой строки — это цена товара).

    Модифицируем алгоритм. Сейчас рассматриваются все сочетания строк подбора:1 из 50; 2 из 50; 3 из 50; … ; 49 из 50; 50 из 50. Цикл в цикле:

    Сочетание = ВыбратьСочетания (ИзЭн, ПоЭм) ;

    И в цикле: ПолучитьСочетание (Сочетание, ИзЭн, ПоЭм);

    ОбработатьСочетание (Сочетание)

    Например, нужно подобрать 13 позиций номенклатуры из 50 на некую заданную сумму. Что мы делаем?

    1. случайно подбираем сколько-то. Например, 8.

    2. Оставшиеся 5 получаем путем сочетаний из 42(ИзЭн) по 5(ИзЭм). Почему из 42, а не из 50? Да потому что 8 мы подобрали уже случайно. (Случайный подбор не нужно менять, — он регулируется на форме ползунком.)

    В-общем, все самое сложное я уже сделал, а Вам осталось модифицировать несколько строк программного кода. Желаю удачи. 🙂

    Reply
  30. user1202287

    Как скачать????

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *