From 6f22047abadb365c6fd0061442edc8a07e2451ec Mon Sep 17 00:00:00 2001 From: Aleksey Filippov Date: Wed, 4 Mar 2026 10:09:54 +0300 Subject: [PATCH] fix(TO8-48): fix readyto_1c strict comparison, add cron-based timeout check MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - Fix `checkAndSetReadyTo1c()`: cast `readyto_1c` to int before strict comparison — PostgreSQL returns string "0", so `!== 0` always skipped - Add `forceReadyTo1cByTimeout()`: batch-marks orders older than 15 min as ready for 1C export, independent of incoming FlowWow emails - Add console action `marketplace/check-ready-to-1c` for cron (*/5) - Add unit tests for both string and int readyto_1c values --- erp24/commands/MarketplaceController.php | 13 ++ erp24/services/MarketplaceService.php | 27 +++- .../unit/services/CheckReadyTo1cTest.php | 133 ++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 erp24/tests/unit/services/CheckReadyTo1cTest.php diff --git a/erp24/commands/MarketplaceController.php b/erp24/commands/MarketplaceController.php index d370164d..87ebaca9 100644 --- a/erp24/commands/MarketplaceController.php +++ b/erp24/commands/MarketplaceController.php @@ -544,4 +544,17 @@ class MarketplaceController extends Controller return ExitCode::UNSPECIFIED_ERROR; } } + + /** + * Принудительная отправка в 1С заказов, ожидающих delivery_to дольше 15 минут. + * + * Запуск: php yii marketplace/check-ready-to-1c + * Рекомендуемый крон: */5 * * * * + */ + public function actionCheckReadyTo1c(): int + { + $count = MarketplaceService::forceReadyTo1cByTimeout(15); + $this->stdout("Помечено готовыми к отправке в 1С: {$count} заказов\n"); + return ExitCode::OK; + } } diff --git a/erp24/services/MarketplaceService.php b/erp24/services/MarketplaceService.php index f91b4a03..87e94a2b 100644 --- a/erp24/services/MarketplaceService.php +++ b/erp24/services/MarketplaceService.php @@ -3489,9 +3489,34 @@ class MarketplaceService } + /** + * Принудительно помечает все заказы старше $minutes минут как готовые к отправке в 1С. + * Вызывается из крон-команды marketplace/check-ready-to-1c. + */ + public static function forceReadyTo1cByTimeout(int $minutes = 15): int + { + $orders = MarketplaceOrders::find() + ->where(['readyto_1c' => 0]) + ->andWhere(['<', 'creation_date', date('Y-m-d H:i:s', strtotime("-{$minutes} minutes"))]) + ->all(); + + $count = 0; + foreach ($orders as $order) { + $order->readyto_1c = 1; + if ($order->save()) { + $count++; + Yii::warning("Заказ ID {$order->id} автоматически помечен как готовый к отправке в 1C (таймаут {$minutes} мин)."); + } else { + Yii::error('Ошибка установки readyto_1c = 1 у заказа ID ' . $order->id . ': ' . json_encode($order->getErrors(), JSON_UNESCAPED_UNICODE)); + } + } + + return $count; + } + public static function checkAndSetReadyTo1c($order): void { - if ($order->readyto_1c !== 0) { + if ((int)$order->readyto_1c !== 0) { return; } diff --git a/erp24/tests/unit/services/CheckReadyTo1cTest.php b/erp24/tests/unit/services/CheckReadyTo1cTest.php new file mode 100644 index 00000000..20599c55 --- /dev/null +++ b/erp24/tests/unit/services/CheckReadyTo1cTest.php @@ -0,0 +1,133 @@ + $v) { + $this->$k = $v; + } + } + + public function save(): bool + { + $this->saveCallCount++; + return true; + } + + public function getErrors(): array + { + return []; + } + }; + } + + /** + * Заказ старше 15 минут с readyto_1c = "0" (строка из PostgreSQL) + * должен быть помечен как готовый. + */ + public function testCheckAndSetReadyTo1c_StringZero_OlderThan15Min_SetsReady(): void + { + $order = $this->createFakeOrder([ + 'id' => 999, + 'readyto_1c' => "0", + 'creation_date' => date('Y-m-d H:i:s', strtotime('-20 minutes')), + ]); + + MarketplaceService::checkAndSetReadyTo1c($order); + + $this->assertEquals(1, $order->readyto_1c); + $this->assertEquals(1, $order->saveCallCount, 'save() должен быть вызван один раз'); + } + + /** + * Заказ старше 15 минут с readyto_1c = 0 (int) + * должен быть помечен как готовый. + */ + public function testCheckAndSetReadyTo1c_IntZero_OlderThan15Min_SetsReady(): void + { + $order = $this->createFakeOrder([ + 'id' => 998, + 'readyto_1c' => 0, + 'creation_date' => date('Y-m-d H:i:s', strtotime('-20 minutes')), + ]); + + MarketplaceService::checkAndSetReadyTo1c($order); + + $this->assertEquals(1, $order->readyto_1c); + $this->assertEquals(1, $order->saveCallCount); + } + + /** + * Заказ моложе 15 минут — readyto_1c не должен измениться. + */ + public function testCheckAndSetReadyTo1c_YoungerThan15Min_StaysZero(): void + { + $order = $this->createFakeOrder([ + 'id' => 997, + 'readyto_1c' => "0", + 'creation_date' => date('Y-m-d H:i:s', strtotime('-5 minutes')), + ]); + + MarketplaceService::checkAndSetReadyTo1c($order); + + $this->assertEquals("0", $order->readyto_1c); + $this->assertEquals(0, $order->saveCallCount, 'save() не должен вызываться'); + } + + /** + * Заказ с readyto_1c = 1 — метод должен выйти сразу, не трогая заказ. + */ + public function testCheckAndSetReadyTo1c_AlreadyReady_Skips(): void + { + $order = $this->createFakeOrder([ + 'id' => 996, + 'readyto_1c' => 1, + 'creation_date' => date('Y-m-d H:i:s', strtotime('-60 minutes')), + ]); + + MarketplaceService::checkAndSetReadyTo1c($order); + + $this->assertEquals(1, $order->readyto_1c); + $this->assertEquals(0, $order->saveCallCount); + } + + /** + * Заказ с readyto_1c = "1" (строка) — тоже пропускается. + */ + public function testCheckAndSetReadyTo1c_StringOne_Skips(): void + { + $order = $this->createFakeOrder([ + 'id' => 995, + 'readyto_1c' => "1", + 'creation_date' => date('Y-m-d H:i:s', strtotime('-60 minutes')), + ]); + + MarketplaceService::checkAndSetReadyTo1c($order); + + $this->assertEquals("1", $order->readyto_1c); + $this->assertEquals(0, $order->saveCallCount); + } +} -- 2.39.5