namespace Uplab\Tilda;
use Bitrix\Main\Application;
class Replace
{
/** Куда писать логи */
private const LOG_DIR = '/local/dev/tilda';
/** Ключевые поля не раздуваем: усечём большие строки */
private const LOG_SNIPPET = 1500;
/** Удобный корреляционный ID на один запрос */
private static function rid(): string {
static $rid = null;
if ($rid === null) {
try {
$rid = bin2hex(random_bytes(6));
} catch (\Throwable $e) {
$rid = substr(uniqid('', true), -12);
}
}
return $rid;
}
private static function utf8ok(string $s): bool {
return (preg_match('//u', $s) === 1);
}
private static function pregErrName(int $code): string {
// PHP 8.x
switch ($code) {
case \PREG_NO_ERROR: return 'PREG_NO_ERROR';
case \PREG_INTERNAL_ERROR: return 'PREG_INTERNAL_ERROR';
case \PREG_BACKTRACK_LIMIT_ERROR: return 'PREG_BACKTRACK_LIMIT_ERROR';
case \PREG_RECURSION_LIMIT_ERROR: return 'PREG_RECURSION_LIMIT_ERROR';
case \PREG_BAD_UTF8_ERROR: return 'PREG_BAD_UTF8_ERROR';
case \PREG_BAD_UTF8_OFFSET_ERROR: return 'PREG_BAD_UTF8_OFFSET_ERROR';
case \PREG_JIT_STACKLIMIT_ERROR: return 'PREG_JIT_STACKLIMIT_ERROR';
default: return 'PREG_UNKNOWN_'.$code;
}
}
private static function brief(?string $s, int $limit = self::LOG_SNIPPET): string {
if ($s === null) return '';
$len = strlen($s);
if ($len <= $limit) return $s;
return substr($s, 0, $limit) . "... [+" . ($len - $limit) . " bytes]";
}
private static function log(string $stage, array $data = []): void {
$rq = $_SERVER['REQUEST_URI'] ?? 'unknown';
$file = $_SERVER['DOCUMENT_ROOT'] . self::LOG_DIR . '/' .
date('Y-m-d_H-i-s') . '_' . self::rid() . '_' .
str_replace(['/', '?', '&', '='], '_', $rq) . '.jsonl';
// Безопасно, коротко, структурировано
$payload = [
'time' => date('c'),
'rid' => self::rid(),
'stage' => $stage,
] + $data;
// не падаем из-за логов
@file_put_contents($file, json_encode($payload, JSON_UNESCAPED_UNICODE) . PHP_EOL, FILE_APPEND | LOCK_EX);
}
public static function tagReplace(&$content) {
$request = Application::getInstance()->getContext()->getRequest();
if ($request->isAdminSection()) return false;
$requestUri = $request->getRequestUri() ?? ($_SERVER['REQUEST_URI'] ?? 'unknown');
$original = (string)$content;
$work = $original;
self::log('enter', [
'url' => $requestUri,
'content_len' => strlen($original),
'content_sha1' => sha1($original),
'utf8_ok' => self::utf8ok($original),
'has_marker' => (strpos($original, 'UPLABTILDA') !== false),
]);
try {
// Ищем маркеры в РАБОЧЕЙ копии
$matches = null;
$ok = @preg_match_all('/\[(UPLABTILDA [^\]]+)\]/u', $work, $matches);
$pregErr = preg_last_error();
self::log('preg_match_all_done', [
'ok' => $ok,
'preg_error' => self::pregErrName($pregErr),
'match_cnt' => is_array($matches) && isset($matches[0]) ? count($matches[0]) : 0,
]);
if ($ok === false || $pregErr !== \PREG_NO_ERROR) {
self::log('fail_regex', [
'reason' => 'preg_match_all error',
'preg_err' => self::pregErrName($pregErr),
]);
return false;
}
if ($ok > 0 && is_array($matches[1])) {
foreach ($matches[1] as $k => $match) {
$needle = $matches[0][$k] ?? '';
self::log('before_replace', [
'k' => $k,
'match' => $match,
'needle' => self::brief($needle, 300),
'len_work' => strlen($work),
]);
$beforeLen = strlen($work);
$work = self::replaceContent($work, $match, $needle);
self::log('after_replace', [
'k' => $k,
'len_delta' => strlen($work) - $beforeLen,
'utf8_ok' => self::utf8ok($work),
'content_sha1'=> sha1($work),
]);
}
}
// jquery 3: .load → .on('load')
$before = $work;
$work = str_replace("$(window).load(function()", "$(window).on('load', function ()", $work);
self::log('after_jq_fix', [
'changed' => ($before !== $work),
]);
// Удаляем закомментированное
$beforeLen = strlen($work);
Helper::removeCommentedCode($work);
self::log('after_remove_comments', [
'len_delta' => strlen($work) - $beforeLen,
]);
// Коммит: пустые строки не публикуем
if ($work === '') {
self::log('fail_commit', [
'reason' => 'empty_work',
]);
return false;
}
$content = $work;
self::log('success', [
'final_len' => strlen($content),
'final_sha1' => sha1($content),
'utf8_ok' => self::utf8ok($content),
]);
return true;
} catch (\Throwable $e) {
self::log('exception', [
'class' => get_class($e),
'code' => $e->getCode(),
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
// чтобы не раздувать лог: первые 1500 байт проблемного контента
'content_snippet' => self::brief($work),
]);
return false;
}
}
public static function replaceContent($content, $match, $str) {
// Парсим параметры безопасно
$params = [];
$explodedParams = preg_split("~(\s| )+~u", $match, -1, PREG_SPLIT_NO_EMPTY);
foreach ($explodedParams as $value) {
$kv = explode('=', $value, 2);
if (count($kv) === 2) {
$kv[0] = str_replace("amp;", "", $kv[0]);
$params[$kv[0]] = $kv[1];
}
}
// Для диагностики — лог ключевых параметров
self::log('replace_params', [
'page' => isset($params['PAGE']) ? (int)$params['PAGE'] : null,
'hide' => $params['HIDEPAGETEMPLATE'] ?? null,
'keys' => array_keys($params),
]);
if (!empty($params['HIDEPAGETEMPLATE']) && $params['HIDEPAGETEMPLATE'] === "Y") {
$pageId = (int)($params['PAGE'] ?? 0);
$content = Common::getPageFullContent($pageId);
} else {
$pageId = (int)($params['PAGE'] ?? 0);
$html = Common::getPageContent($pageId, $params);
$content = str_replace($str, $html, $content);
}
return $content;
}
public static function removeFromIndex($arFields) {
if ($arFields["MODULE_ID"] === "iblock" ) {
$arFields["TITLE"] = preg_replace('/\[(UPLABTILDA [^\]]+)\]/u', '', $arFields["TITLE"]);
$arFields["BODY"] = preg_replace('/\[(UPLABTILDA [^\]]+)\]/u', '', $arFields["BODY"]);
}
return $arFields;
}
}
Разместить товар на адресном складе по выгруженному из товароучетной системы заданию— подробная информация об особенностях работы ПО и оборудования в разделе База знаний на сайте компании «Клеверенс»
Разместить товар на адресном складе по выгруженному из товароучетной системы заданию Последние изменения: 2024-03-26
Выберите уточнение:
Операция «Размещение» производится в соответствии со следующим бизнес-процессом:
После того как была проведена приемка товара на склад (по готовому заданию или по факту), необходимо разместить принятый товар. Рассмотрим, как это происходит на адресном складе по выгруженному из товароучетной системы заданию:
На ТСД из товароучетной программы выгружается документ «Отбор (размещение) товаров» («Приобретение товаров и услуг», «Приходного ордера на товары»), содержащий данные по ячейкам и товарам для размещения в эти ячейки. Как документ выгружается из товароучетных программ, было описано на странице .
Кладовщик сканирует ячейку и видит на экране ТСД данные по товару, который должен быть помещен в эту ячейку. Затем он начинает сканирование этих товаров.
Результатом данной операции становится документ «Отбор (размещение) товаров».
Размещение товара в ячейки
В главном меню «Склада 15» выберите операцию «Размещение» и откройте нужный документ.
Откроется окно сканирования товара, в котором будет отображаться список всех заданных ячеек и товара, который должен быть в них размещен.
После сканирования ячейки на экране появится список товаров, которые должны быть в нее помещены в соответствии с заданием. Приступайте к сканированию заданного товара. Результаты сканирования будут заноситься в колонку «Факт», зеленым будет указываться совпадение количества товара, красным — расхождение.
После размещения товара в одну ячейку, приступайте к размещению во вторую. Для этого отсканируйте штрихкод следующей ячейки, а дальше продолжайте работу в соответствии с действиями, описанными выше.
После окончания операции завершите документ. Это необходимо для того, чтобы можно было отправить его на сервер Mobile SMARTS (либо оставить на ТСД в случае прямого обмена документами). Незавершенный документ отправить нельзя.
После отправки на сервер документ необходимо загрузить в товароучетную программу для дальнейшей работы. Как это делается в 1С, Вы можете прочитать в статье «Загрузка документов в 1С », а как в Excel — в статье «Интеграция «Магазина 15» через CSV и Excel».