<?php // Полная загрузка сервисных книжек, создан 2025-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='\
Симпатично. А по умолчанию что производителем WMS предлагается интересно…
Упрощенно
1. Не надо делать СЛОЖНЫХ экранов с кучей альтернатив и списков. люди работают со вполне конкретными физическими объектами.
поэтому — например — показ товарного состава приемки (последний слайд) — не несет никакой полезной информации для приемщика — он и так на приемке видит КУЧУ ТОВАРА и эту же КУЧУ ТОВАРА он видит в форме списка на экране — ни с чем конкретно — глядя на эти две кучи — приемщик не работает, поэтому вопрос — зачем ему этот список?
Приемщик — целый день куртится на приемке. К середине рабочего дня его уже клинит от обилия товаров, wabh/ — не надо нагружать лишним. нужно облегчать работу. Представим: приемщик находится (из приложенных слайдов) на сладйе со списком двух товаров. Его в это время отвлекли/сдернули на 3 мин. Он возвращается в приемку и к этому экрану. В зоне приемки — несколько поставок — из них штук пять с белым и розовым товаром. Дальнешие действия приемщика….?????
На любом экране (упрощенно) д.б.
— кто я? (я=приемка №5, z=отгрузка№10)
— где я? (я на «идентификация товара»)
— что я должен сделать? («выбери товар для начала пересчета»)
всё!
ни один экран не удовлетворяет этим минимальным требованиям.
посмотрим тупо на экран где нарисованы два возможных действия 1. обозначить поддон 2. обозначить ячейку.
Cорри? у меня вопрос — а нафига ДВА ДЕЙСТВИЯ горят одновременно, если выполнить в данном конкретном случае можно сейчас только одно..? второй действие — чтобы приемщик посмотрел и испугался? чтобы он в голове делал первое, но готовился внутренне ко второму и поэтому косячит на первом…?
Меньше альтернатив! быстрые короткие задачи, которые не требуют размышлений. На приемке важны а) скорость и б) качество приемки. Не надо усложнять жизнь приемщику.
(ты сам же писал в своих статьях все правильно)
Вариант зачтен как проба пера.
(1) genayo, В том то и беда что ничего не предлагает со сканером штрих кода. Только радиотерминалы.
(2) CheBurator,
Начнем. У приемщика есть терминал (ноутбук со сканером, планшет со сканером, терминал без радиосвязи с WinCE)
Он открывает это рабочее место и видит список приемок. Выбирает приемку и видит пустой экран. Начинает приемку — либо скандируя товар сканером или вводя в ручном режиме. Выбирает партию и указывает количество (или несколько раз сканирует товар)
Если товар еще не принимался или контейнер приемки заполнен и закрыт то после сканирования товара то оператор должен выбрать ячейку и контейнер из свободных (сканированием или в ручном режиме). Дальше при сканировании, добавлении этого же товара он сам будет добавляться в количество в этой же ячейке.
Так же оператор может закрыть контейнер (допустим паллет заполнен, и нужно поставить новый паллет)
Как только паллет заполнен он становится доступным к распределению в системе.
Итого работа оператора:
1. Выбрать приемку из тех которые ему назначены по номеру ворот.
2. Сканировать / вводить в ручном режиме товар принимаемый
3. В начале приемки указать куда будет ставиться какой товар в зоне приемки
4. По заполнению транспортного контейнера фиксировать данный факт.
(4) Вообщем да, все верно.
В частностях — могут потребоваться существенные кардинальные переделки/уточнения процесса — зависит от частностей поставщика, особенностей груза и т.д. Вплоть до того, что на каждого поставщика — своя процедура (в т.ч. и на NСД) приемки и вплоть до того что для каждой вида товаров/товара — своя процедура приемки.
а так — по процессу «Итого работа оператора» — все те же ответы на те же простые вопросы, а то у тебя пунктом 3 стоит то, что должно стоять первым 😉
Типа с самого начала (примерно/упрощенно)
а)
1. Кто я? = моя роль «Приемщик»
2. Где я? = сканируй Ворота!
3. Что я должен сделать? = идентифицируй приемку!
б) (зависит от частностей, как вариант)
1. Кто я? = Приемка №45
2. Где я? = сканируй контейнер/ТЕ!
3. Что я должен сделать? = идентифицируй товар
в) Кто я? = Товар АААА
2. Где я? = введи количество!
3. Что я должен сделать? = идентифицируй партию
…
Описано выше примерно, может быть по всякому.
где-то приходит большими партиями — удобнее один раз идентфицировать партию, потом только количества попаллетно принимать.. Где-то по другому/наоборот.
ну и т.д.
имхо
просто хочу заострит внимание что «..то оператор должен выбрать ячейку и контейнер из свободных» — такой подход не катит. надо мыслить WMSно 😉
Не «выбрать ячейку И контейнер», а
или
1. выбрать ячейку, ПОТОМ 2. выбрать контейнер
или
1. выбрать контейнер, ПОТОМ 2. выбрать ячейку
то есть никаких «И»…
может показаться что я зря «паранойю» — но здесь надо отказываться от всяких «и», учета «воздуха» и прочих привычных расхляюанностей для 1Сников. не взлетит с таким подходом, или очень тяжело будет. Конвеер, чистый конвеер. И чем меньше решений принимает «персонал» — тем все получается быстрее, устойчивее, плановее и предсказуемее…
Посмотрел у себя по одной из последних приемок, чистого времени на приемку паллеты уходит ~15-20сек — ввод количества, считать данные по сроку годности и ввести его, налепить и отсканировать ТЕ, количество вводить могут просто числом (360) или «умножением» по раскладке (12пробел30 или 4пробел3пробел30), срок годности вводят как удобнее — как считали с паллеты — так и вводят, где-то год впереди, где-то год в конце — прога сама жует. И партии — не выбирают. Партии либо автоматом генерятся, либо автоматом подхватываются существующие по совпадению ключевых реквизитов. Поставка из 30 паллет (несколько артикулов, разные сроки на один артикул, сроки на паллетах не смешаны) — грязное время приемки составляет 15-20 мин.
(6) CheBurator, Ага: именно так и сделано Сначала контейнер потом ячейку или сначала ячейку а потом контейнер. Причем можно выбрать без сканирования и то и другое но в базе будет отображено что выбор был ручной что бы потом можно было разобраться.
(5) CheBurator,
Ага: тут момент я убрал понятие «сканируй ворота» потому как ш/к каждой ячейки уникально, и грубо говоря не примет система ячейку с 5ых ворот в 1ых воротах. Но мысль уловил. Вообще обработка в будущем будет переведена в мобильное приложение под android для реализации «ручной» и «шк» приемки.
(8) Возможно мы немного о разном.
«Сканируй ворота» или «сканируй ячейку/зону приемки» — используется, например:
1. для приемки/разгрузки товара кучей в ячейку «Ворота10» (далее собственно приемка с раскладкой по паллетам и прочее)
2. для фильтрации списка приемок. спозиционировался на ворота — система выдает только те приемки, которые назначены на данные ворота. Чтобы не приняли (по недомыслию) фуру с овощами на воротах зоны молочки.
Если в системе всего одни ворота (одна ячейка приемки) — то нормальная система не будет грузить тупыми выборами — пипл заходит в режим/раздел «Приемка» — если ворота в сисеме одни — то и нефиг на них позиционироваться (в тихом режиме система сама уже спозиционировалась).
ну и куча всего разного.
Учесть все тонкости и частности достаточно трудно/накладно, поэтому есть универсальная процедура приемки, например, которая подходит всем. и разрабю очень неохотно идут на изменение таких универсальных вещей. А пипл — пусть мается жутким раздражением и неудобством.
например. есть на паллете с товаром дата изготовления. и длительность хранения. у кого-то в днях, а у кого-то В МЕСЯЦАХ. — охренеешь работать в одной универсальной форме ввода сроков. к 28 февраля — прибавить 2 месяца — это скольо в днях будет? и это будет 30 апреля или 28 апреля? а если дата изготовления = 12 мая и срок 4 месяца — как приемщику вводить..? По уму — надо на каждый видж товаров писать свой «плугин» приемки
.. поэтому чуть не понял, что имеется в виду в «тут момент я убрал понятие «сканируй ворота» потому как ш/к каждой ячейки уникально, и грубо говоря не примет система ячейку с 5ых ворот в 1ых воротах. «
(9) CheBurator, Ха, а интересное решение. Я как бы рассчитывал на адекватность старшего приемки, но на самом деле спасибо за идею — поправлю.
А я имел ввиду что при приемке и выставлении контейнера в ячейку указывать ворота не обязательно ) Что касается приемки «в навалку» — тут все немного проще и сложнее — в моем понимании приемка это как раз формирование контейнеров для дальнейшего хранения. Но по сути то же понятная идея. Так же спасибо
(3) на сколько я понял, вы работаете с Axelot WMS 4?
У них ведь есть штатное рабочее место для приемки товара… Под стационарный компьютер, с большими кнопками…
А можно выложить на github или в какой-нибудь файлообменник?
(3) можно подключать любое оборудование. ТСД нужно для нестационарных.
(14)
Подтверждаю сканер подключен и работает, более того в Axelot WMS4
реализованы рабочие места по операциям, поэтому не совсем понятно зачем изобретать велосипед
смотрите скрины там и список существующих рабочих мест
скрин рабочего места оператора приемки
скрин подключенного сканера
Контейнеры для меня пока — загадочная штука… Это что-то физически реальное? или некая условная сущность?
(16) это условное понятие, классический вариант — паллета, может быть короб, ящик, тележка для отбора. Но может быть и любой другой объект, который вмещает в себя номенклатуру.
(17) спасибо.
я понял так что контейнер это эквивалент того. что в других системах называется «ТЕ» — транспортная единица..?
(18) Да.
Очевидно, что в рамках склада нет транспорта, как такового, поэтому принято называть его контейнером поскольку он может быть размером с коробочку для обеда и контейнером в общественном понимании. В то же время груз, как раз является объектом транспортировки.
(19) Понял, спсб.
так и думал
Товарищи, помогите разобраться с ТСД. Открываю список задач(к примеру отборы), кликаю по ссылке, но задача на ТСД не открывается, пишет, что задачи не найдены. В списке задач пишет, что есть 4 задачи.
(21) Думаю вы уже разобрались, но отвечу для тех кто будет гуглить:
А) Задачи не попадают на ТСД, например, потому, что рабочий поток по задаче не указан в складской роли
1) Складской Работник состоит в группе
2) Группе назначена роль
3) В роли указан список доступных рабочих потоков
Б) Задачи отсеиваются отбором, который настраивается в рабочем потоке (или в алгоритме)