if (!CModule::IncludeModule('o2k.betapro')) { die('Модуль не установлен!'); } $stack = new O2k\Betapro\Services\Stack(); $manager = new O2k\Betapro\Manager(); $result = $stack->getStackList(); echo '

В очереди на отправку: ' . count($result) . ' заказ(ов)

'; echo '
'; print_r($result); echo '
'; echo "

Обработка очереди завершена

"; ……………………………………………………………………………………………………………………………………………………………………………………………………………………………………….. //////////////////////////////////////////////////////////////////////////////////////// getStackList(); // вернёт массив, где ключ – ID записи, значения см. в доке :contentReference[oaicite:0]{index=0}​:contentReference[oaicite:1]{index=1} echo '

В очереди найдено: '.count($stackList).' записей

'; echo ''; echo ''; $problemCount = 0; foreach ($stackList as $stackId => $row) { $problem = []; // 1. BX_ORDER_ID отсутствует или null if (empty($row['BX_ORDER_ID'])) { $problem[] = 'BX_ORDER_ID пуст'; } // 2. BX_ORDER_ID не число if (!empty($row['BX_ORDER_ID']) && !ctype_digit((string)$row['BX_ORDER_ID'])) { $problem[] = 'BX_ORDER_ID не число'; } // 3. заказ физически не существует в sale if (!empty($row['BX_ORDER_ID']) && Sale\Order::load($row['BX_ORDER_ID']) === null) { $problem[] = 'Заказ с таким ID не найден в sale'; } // 4. отсутствие ACCOUNT_NUMBER (тоже вызывает падение cancelSendedOrder / checkSendedOrder) if (empty($row['BX_ACCOUNT_NUMBER'])) { $problem[] = 'BX_ACCOUNT_NUMBER пуст'; } // 5. можно проверить, что STATUS=ADDED и одновременно BX_ORDER_ID пуст if ($row['STATUS'] == Stack::STATUS_ADDED && empty($row['BX_ORDER_ID'])) { $problem[] = 'STATUS_ADDED, но BX_ORDER_ID пуст — 100% падает в sendAddedOrder()'; } // вывод строки echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; if ($problem) { $problemCount++; } } echo '
# Stack ORDER_ID
(во внутренней таблице модуля)
BX_ORDER_ID
(ID заказа в Sale)
BX_ACCOUNT_NUMBER STATUS Проблема
'.$stackId.''.$row['ORDER_ID'].''.($row['BX_ORDER_ID'] ?: 'NULL').''.($row['BX_ACCOUNT_NUMBER'] ?: 'NULL').''.$row['STATUS'].''.($problem ? implode('; ', $problem) : ' ').'
'; echo '

Найдено проблемных записей: '.$problemCount.'

'; if ($problemCount && isset($_GET['debug'])) { echo '
';
    echo "Ниже пример, как можно вручную вызвать sendAddedOrder() в try/catch\n\n";
    foreach ($stackList as $id => $row) {
        if ($row['STATUS'] == Stack::STATUS_ADDED) {
            try {
                $manager->sendAddedOrder((int)$row['BX_ORDER_ID']); // может упасть
                echo "OK: stack #$id, order ".$row['BX_ORDER_ID']."\n";
            } catch (Throwable $e) {
                echo "FAIL: stack #$id, order ".$row['BX_ORDER_ID']." — ".$e->getMessage()."\n";
            }
        }
    }
    echo '
'; } require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php'); require($_SERVER['DOCUMENT_ROOT'] . '/bitrix/footer.php'); ?> ……………………………….//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// ['ID','ORDER_ID','STATUS'], 'filter' => ['SEND'=>'N', 'STATUS'=>Stack::STATUS_ADDED], 'order' => ['ID'=>'DESC'], 'limit' => 15, ])->fetchAll(); /** шаг 2. отмечаем, что мы хотим их обработать (ничего не меняем – просто вывод) */ echo "
Готовим к отправке ".count($rows)." записей\n";
foreach ($rows as $r){
    echo "#{$r['ID']} (ORDER_ID={$r['ORDER_ID']})\n";
}
echo "
"; /** шаг 3. пускаем штатный механизм менеджера */ $manager = new Manager(); $manager->checkQueue(); // здесь вызовется protected sendAddedOrder() echo "
Готово, обновите страницу для проверки."; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Удаление всех товаров из очереди truncateTable(StackRequestTable::getTableName()); /** * 2. (опционально) сбрасываем признак «уже добавлен в очередь», * чтобы нужные заказы могли попасть в неё повторно на следующем запуске exchange. * * Закомментируй, если нужно просто опустошить очередь «навсегда». */ //$conn->query("UPDATE o2k_betapro_order SET ADDED_TO_STACK = 'N' WHERE ADDED_TO_STACK = 'Y'"); echo "✓ Очередь Betapro очищена\n"; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// итоговый код add('-' . Config::getQueueLookbackDays() . ' days'); $rsOrders = OrderTable::getList([ 'select' => [ 'ID', 'ORDER_ID', 'DATE_INSERT' => 'BX_ORDER.DATE_INSERT', ], 'runtime' => [ 'BX_ORDER' => [ 'data_type' => Order::class, 'reference' => ['=this.ORDER_ID' => 'ref.ID'], 'join_type' => 'LEFT', ], ], 'filter' => [ '>=BX_ORDER.DATE_INSERT' => $fromDate, 'ADDED_TO_STACK' => 'N', 'BX_ORDER.CANCELED' => 'N', ], 'order' => ['ID' => 'ASC'], ]); while ($order = $rsOrders->fetch()) { $internalId = (int)$order['ID']; $bxOrderId = (int)$order['ORDER_ID']; // --- Фильтрация тестовых заказов по свойству NAME --- $saleOrder = Order::load($bxOrderId); if ($saleOrder) { $props = $saleOrder->getPropertyCollection(); $nameProp = $props->getItemByOrderPropertyCode('NAME'); $custName = $nameProp ? mb_strtolower($nameProp->getValue()) : ''; if (mb_stripos($custName, mb_strtolower(Config::getTestNameMask())) !== false) { // если в имени встречается «test» — пропускаем continue; } } /* чистим старые хвосты */ $rs = StackRequestTable::getList([ 'select' => ['ID'], 'filter' => ['=ORDER_ID' => $internalId], ]); while ($row = $rs->fetch()) { StackRequestTable::delete($row['ID']); } /* добавляем в очередь */ $stack->addToStack($internalId, Stack::STATUS_ADDED, 'N'); /* и помечаем в o2k_betapro_order */ $stack->markSendedOrder($bxOrderId); echo "Добавлен: внутренний={$internalId}, BX={$bxOrderId}\n"; } /* 2. Собираем, что реально уйдёт */ $stackList = $stack->getStackList(); $willSend = []; foreach ($stackList as $stackId => $row) { if ($row['STATUS'] != Stack::STATUS_ADDED) { continue; } $order = Order::load($row['BX_ORDER_ID']); $created = $order ? $order->getDateInsert() : null; if ($created instanceof DateTime && $now->getTimestamp() - $created->getTimestamp() < $delaySec) { continue; // ещё рано } $willSend[$stackId] = $row; } if (php_sapi_name() !== 'cli') { echo '

Будут отправлены в BetaPro: ' . count($willSend) . '

'; if ($willSend) { echo ''; foreach ($willSend as $sid => $row) { $order = Order::load($row['BX_ORDER_ID']); $date = $order ? $order->getDateInsert()->toString() : '—'; echo ''; } echo '
#StackORDER_IDBX_ORDER_ID ACCOUNT_NUMBERДата создания
' . htmlspecialchars($sid) . ' ' . htmlspecialchars($row['ORDER_ID']) . ' ' . htmlspecialchars($row['BX_ORDER_ID']) . ' ' . htmlspecialchars($row['BX_ACCOUNT_NUMBER']) . ' ' . htmlspecialchars($date) . '

'; } } /* 3. Отправляем и удаляем */ foreach ($willSend as $stackId => $row) { $bxId = (int)$row['BX_ORDER_ID']; try { if ($manager->sendAddedOrder($bxId)) { StackRequestTable::delete($stackId); echo "Отправлен и удалён: stack={$stackId}, BX={$bxId}\n"; } else { echo "sendAddedOrder вернул false: stack={$stackId}\n"; } } catch (\Throwable $e) { echo "Ошибка: stack={$stackId} — " . $e->getMessage() . "\n"; } } echo "=== DONE ===\n"; require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php'; ?> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// query(" DELETE FROM ". StackRequestTable::getTableName() ." WHERE SEND = 'Y' "); // ======================================================================= // 1) Добавляем свежие заказы в очередь (как обычно) // ======================================================================= $stack = new Stack(); $now = new DateTime(); // Берём заказы за последние 3 дня и которые ещё не добавлялись $fromDate = (clone $now)->add('-3 days'); $rsNew = OrderTable::getList([ 'select' => ['ID','ORDER_ID'], 'runtime' => [ 'BX_ORDER' => [ 'data_type' => Order::class, 'reference' => ['=this.ORDER_ID'=>'ref.ID'], 'join_type' => 'LEFT', ], ], 'filter' => [ '>=BX_ORDER.DATE_INSERT' => $fromDate, 'ADDED_TO_STACK' => 'N', 'BX_ORDER.CANCELED' => 'N', ], 'order' => ['ID'=>'ASC'], ]); echo "Добавляем в очередь новых заказов:\n"; while ($row = $rsNew->fetch()) { $intId = (int)$row['ID']; $bxId = (int)$row['ORDER_ID']; // на всякий случай удаляем старые хвосты очереди $rsOld = StackRequestTable::getList([ 'select'=>['ID'], 'filter'=>['=ORDER_ID'=>$intId], ]); while ($old = $rsOld->fetch()) { StackRequestTable::delete($old['ID']); } $stack->addToStack($intId, Stack::STATUS_ADDED, 'N'); $stack->markSendedOrder($bxId); echo " → internal={$intId}, bx={$bxId}\n"; } // ======================================================================= // 2) Запускаем штатный менеджер, который отправит всё, что осталось // в o2k_betapro_stack_request (STATUS_ADDED & SEND=N) и удалит записи // ======================================================================= echo "\nЗапускаем отправку — Manager::checkQueue()\n"; $manager = new Manager(); $manager->checkQueue(); // ==== новый блок очистки очереди ==== echo "\nУдаляем все остатки из o2k_betapro_stack_request…\n"; $conn = Application::getConnection(); $conn->query(" DELETE FROM ". StackRequestTable::getTableName() ." WHERE SEND = 'Y' OR STATUS != ".Stack::STATUS_ADDED." "); echo "Готово — очередь пуста.\n"; echo "=== DONE ===\n"; require $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/main/include/epilog_after.php';