Рабочая среда оператора приемки для WMS 4.0 от AXELOT [beta]




Принцип обмена данными из 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='\

22 Comments

  1. genayo

    Симпатично. А по умолчанию что производителем WMS предлагается интересно…

    Reply
  2. CheBurator

    Упрощенно

    1. Не надо делать СЛОЖНЫХ экранов с кучей альтернатив и списков. люди работают со вполне конкретными физическими объектами.

    поэтому — например — показ товарного состава приемки (последний слайд) — не несет никакой полезной информации для приемщика — он и так на приемке видит КУЧУ ТОВАРА и эту же КУЧУ ТОВАРА он видит в форме списка на экране — ни с чем конкретно — глядя на эти две кучи — приемщик не работает, поэтому вопрос — зачем ему этот список?

    Приемщик — целый день куртится на приемке. К середине рабочего дня его уже клинит от обилия товаров, wabh/ — не надо нагружать лишним. нужно облегчать работу. Представим: приемщик находится (из приложенных слайдов) на сладйе со списком двух товаров. Его в это время отвлекли/сдернули на 3 мин. Он возвращается в приемку и к этому экрану. В зоне приемки — несколько поставок — из них штук пять с белым и розовым товаром. Дальнешие действия приемщика….?????

    На любом экране (упрощенно) д.б.

    — кто я? (я=приемка №5, z=отгрузка№10)

    — где я? (я на «идентификация товара»)

    — что я должен сделать? («выбери товар для начала пересчета»)

    всё!

    ни один экран не удовлетворяет этим минимальным требованиям.

    посмотрим тупо на экран где нарисованы два возможных действия 1. обозначить поддон 2. обозначить ячейку.

    Cорри? у меня вопрос — а нафига ДВА ДЕЙСТВИЯ горят одновременно, если выполнить в данном конкретном случае можно сейчас только одно..? второй действие — чтобы приемщик посмотрел и испугался? чтобы он в голове делал первое, но готовился внутренне ко второму и поэтому косячит на первом…?

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

    (ты сам же писал в своих статьях все правильно)

    Вариант зачтен как проба пера.

    Reply
  3. izidavld

    (1) genayo, В том то и беда что ничего не предлагает со сканером штрих кода. Только радиотерминалы.

    Reply
  4. izidavld

    (2) CheBurator,

    Начнем. У приемщика есть терминал (ноутбук со сканером, планшет со сканером, терминал без радиосвязи с WinCE)

    Он открывает это рабочее место и видит список приемок. Выбирает приемку и видит пустой экран. Начинает приемку — либо скандируя товар сканером или вводя в ручном режиме. Выбирает партию и указывает количество (или несколько раз сканирует товар)

    Если товар еще не принимался или контейнер приемки заполнен и закрыт то после сканирования товара то оператор должен выбрать ячейку и контейнер из свободных (сканированием или в ручном режиме). Дальше при сканировании, добавлении этого же товара он сам будет добавляться в количество в этой же ячейке.

    Так же оператор может закрыть контейнер (допустим паллет заполнен, и нужно поставить новый паллет)

    Как только паллет заполнен он становится доступным к распределению в системе.

    Итого работа оператора:

    1. Выбрать приемку из тех которые ему назначены по номеру ворот.

    2. Сканировать / вводить в ручном режиме товар принимаемый

    3. В начале приемки указать куда будет ставиться какой товар в зоне приемки

    4. По заполнению транспортного контейнера фиксировать данный факт.

    Reply
  5. CheBurator

    (4) Вообщем да, все верно.

    В частностях — могут потребоваться существенные кардинальные переделки/уточнения процесса — зависит от частностей поставщика, особенностей груза и т.д. Вплоть до того, что на каждого поставщика — своя процедура (в т.ч. и на NСД) приемки и вплоть до того что для каждой вида товаров/товара — своя процедура приемки.

    а так — по процессу «Итого работа оператора» — все те же ответы на те же простые вопросы, а то у тебя пунктом 3 стоит то, что должно стоять первым 😉

    Типа с самого начала (примерно/упрощенно)

    а)

    1. Кто я? = моя роль «Приемщик»

    2. Где я? = сканируй Ворота!

    3. Что я должен сделать? = идентифицируй приемку!

    б) (зависит от частностей, как вариант)

    1. Кто я? = Приемка №45

    2. Где я? = сканируй контейнер/ТЕ!

    3. Что я должен сделать? = идентифицируй товар

    в) Кто я? = Товар АААА

    2. Где я? = введи количество!

    3. Что я должен сделать? = идентифицируй партию



    Описано выше примерно, может быть по всякому.

    где-то приходит большими партиями — удобнее один раз идентфицировать партию, потом только количества попаллетно принимать.. Где-то по другому/наоборот.

    ну и т.д.

    Reply
  6. CheBurator

    имхо

    просто хочу заострит внимание что «..то оператор должен выбрать ячейку и контейнер из свободных» — такой подход не катит. надо мыслить WMSно 😉

    Не «выбрать ячейку И контейнер», а

    или

    1. выбрать ячейку, ПОТОМ 2. выбрать контейнер

    или

    1. выбрать контейнер, ПОТОМ 2. выбрать ячейку

    то есть никаких «И»…

    может показаться что я зря «паранойю» — но здесь надо отказываться от всяких «и», учета «воздуха» и прочих привычных расхляюанностей для 1Сников. не взлетит с таким подходом, или очень тяжело будет. Конвеер, чистый конвеер. И чем меньше решений принимает «персонал» — тем все получается быстрее, устойчивее, плановее и предсказуемее…

    Посмотрел у себя по одной из последних приемок, чистого времени на приемку паллеты уходит ~15-20сек — ввод количества, считать данные по сроку годности и ввести его, налепить и отсканировать ТЕ, количество вводить могут просто числом (360) или «умножением» по раскладке (12пробел30 или 4пробел3пробел30), срок годности вводят как удобнее — как считали с паллеты — так и вводят, где-то год впереди, где-то год в конце — прога сама жует. И партии — не выбирают. Партии либо автоматом генерятся, либо автоматом подхватываются существующие по совпадению ключевых реквизитов. Поставка из 30 паллет (несколько артикулов, разные сроки на один артикул, сроки на паллетах не смешаны) — грязное время приемки составляет 15-20 мин.

    Reply
  7. izidavld

    (6) CheBurator, Ага: именно так и сделано Сначала контейнер потом ячейку или сначала ячейку а потом контейнер. Причем можно выбрать без сканирования и то и другое но в базе будет отображено что выбор был ручной что бы потом можно было разобраться.

    Reply
  8. izidavld

    (5) CheBurator,

    Ага: тут момент я убрал понятие «сканируй ворота» потому как ш/к каждой ячейки уникально, и грубо говоря не примет система ячейку с 5ых ворот в 1ых воротах. Но мысль уловил. Вообще обработка в будущем будет переведена в мобильное приложение под android для реализации «ручной» и «шк» приемки.

    Reply
  9. CheBurator

    (8) Возможно мы немного о разном.

    «Сканируй ворота» или «сканируй ячейку/зону приемки» — используется, например:

    1. для приемки/разгрузки товара кучей в ячейку «Ворота10» (далее собственно приемка с раскладкой по паллетам и прочее)

    2. для фильтрации списка приемок. спозиционировался на ворота — система выдает только те приемки, которые назначены на данные ворота. Чтобы не приняли (по недомыслию) фуру с овощами на воротах зоны молочки.

    Если в системе всего одни ворота (одна ячейка приемки) — то нормальная система не будет грузить тупыми выборами — пипл заходит в режим/раздел «Приемка» — если ворота в сисеме одни — то и нефиг на них позиционироваться (в тихом режиме система сама уже спозиционировалась).

    ну и куча всего разного.

    Учесть все тонкости и частности достаточно трудно/накладно, поэтому есть универсальная процедура приемки, например, которая подходит всем. и разрабю очень неохотно идут на изменение таких универсальных вещей. А пипл — пусть мается жутким раздражением и неудобством.

    например. есть на паллете с товаром дата изготовления. и длительность хранения. у кого-то в днях, а у кого-то В МЕСЯЦАХ. — охренеешь работать в одной универсальной форме ввода сроков. к 28 февраля — прибавить 2 месяца — это скольо в днях будет? и это будет 30 апреля или 28 апреля? а если дата изготовления = 12 мая и срок 4 месяца — как приемщику вводить..? По уму — надо на каждый видж товаров писать свой «плугин» приемки

    Reply
  10. CheBurator

    .. поэтому чуть не понял, что имеется в виду в «тут момент я убрал понятие «сканируй ворота» потому как ш/к каждой ячейки уникально, и грубо говоря не примет система ячейку с 5ых ворот в 1ых воротах. «

    Reply
  11. izidavld

    (9) CheBurator, Ха, а интересное решение. Я как бы рассчитывал на адекватность старшего приемки, но на самом деле спасибо за идею — поправлю.

    А я имел ввиду что при приемке и выставлении контейнера в ячейку указывать ворота не обязательно ) Что касается приемки «в навалку» — тут все немного проще и сложнее — в моем понимании приемка это как раз формирование контейнеров для дальнейшего хранения. Но по сути то же понятная идея. Так же спасибо

    Reply
  12. hotey

    (3) на сколько я понял, вы работаете с Axelot WMS 4?

    У них ведь есть штатное рабочее место для приемки товара… Под стационарный компьютер, с большими кнопками…

    Reply
  13. user675080_alexkmbk

    А можно выложить на github или в какой-нибудь файлообменник?

    Reply
  14. Aleskey_K

    (3) можно подключать любое оборудование. ТСД нужно для нестационарных.

    Reply
  15. AlexeyK1

    (14)

    Подтверждаю сканер подключен и работает, более того в Axelot WMS4

    реализованы рабочие места по операциям, поэтому не совсем понятно зачем изобретать велосипед

    смотрите скрины там и список существующих рабочих мест

    скрин рабочего места оператора приемки

    скрин подключенного сканера

    Reply
  16. CheBurator

    Контейнеры для меня пока — загадочная штука… Это что-то физически реальное? или некая условная сущность?

    Reply
  17. Aleskey_K

    (16) это условное понятие, классический вариант — паллета, может быть короб, ящик, тележка для отбора. Но может быть и любой другой объект, который вмещает в себя номенклатуру.

    Reply
  18. CheBurator

    (17) спасибо.

    я понял так что контейнер это эквивалент того. что в других системах называется «ТЕ» — транспортная единица..?

    Reply
  19. Aleskey_K

    (18) Да.

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

    Reply
  20. CheBurator

    (19) Понял, спсб.

    так и думал

    Reply
  21. dtrex

    Товарищи, помогите разобраться с ТСД. Открываю список задач(к примеру отборы), кликаю по ссылке, но задача на ТСД не открывается, пишет, что задачи не найдены. В списке задач пишет, что есть 4 задачи.

    Reply
  22. Power_0N

    (21) Думаю вы уже разобрались, но отвечу для тех кто будет гуглить:

    А) Задачи не попадают на ТСД, например, потому, что рабочий поток по задаче не указан в складской роли

    1) Складской Работник состоит в группе

    2) Группе назначена роль

    3) В роли указан список доступных рабочих потоков

    Б) Задачи отсеиваются отбором, который настраивается в рабочем потоке (или в алгоритме)

    Reply

Leave a Comment

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