]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
fix(ERP-252): add delivery parsing tests and fix surprise-delivery pattern
authorAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Mon, 2 Mar 2026 20:30:48 +0000 (23:30 +0300)
committerAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Mon, 2 Mar 2026 20:30:48 +0000 (23:30 +0300)
12 unit tests for parseAddressFromDeliveryText() covering:
- Full address (city/street/house)
- "Уточните адрес у получателя" pattern
- Surprise SMS delivery ("Отправим смс получателю...")
- Empty strings, prefix-only, unknown cities
- GPS coordinates for known cities
- Pickup delivery, two-word cities
- Result structure validation (all keys, no nulls)

Fixed parser: added filters for surprise-delivery phrases
that were incorrectly parsed as street names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
erp24/services/MarketplaceService.php
erp24/tests/unit/services/MarketplaceServiceDeliveryParsingTest.php [new file with mode: 0644]

index 89d9ef1ce2d1b87912520dee47f339a3c75fda7e..c364217d43b2c01438585862fac6f3ae2e78568b 100644 (file)
@@ -3367,6 +3367,10 @@ class MarketplaceService
 
         // Убираем служебные фразы, которые не являются адресом
         $cleaned = preg_replace('/Уточните\s+адрес\s+доставки\s+у\s+получателя/ui', '', $cleaned);
+        $cleaned = preg_replace('/Отправим\s+смс\s+получателю.*$/ui', '', $cleaned);
+        $cleaned = preg_replace('/Пожалуйста.*сохранить\s+сюрприз/ui', '', $cleaned);
+        $cleaned = preg_replace('/чтобы\s+узнать\s+данные\s+для\s+доставки/ui', '', $cleaned);
+        $cleaned = preg_replace('/не\s+звоните\s+раньше/ui', '', $cleaned);
 
         // Чистим оставшиеся запятые и пробелы
         $cleaned = preg_replace('/,\s*,/', ',', $cleaned);
diff --git a/erp24/tests/unit/services/MarketplaceServiceDeliveryParsingTest.php b/erp24/tests/unit/services/MarketplaceServiceDeliveryParsingTest.php
new file mode 100644 (file)
index 0000000..c587faa
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+
+namespace tests\unit\services;
+
+use Codeception\Test\Unit;
+use yii_app\services\MarketplaceService;
+
+/**
+ * Тесты парсинга адреса доставки из текстовой строки FlowWow/YM.
+ *
+ * Покрывает:
+ * - MarketplaceService::parseAddressFromDeliveryText()
+ * - Различные форматы delivery-строк из прода
+ * - Edge cases: пустые строки, отсутствие адреса, сюрприз-доставка
+ *
+ * @group marketplace
+ * @group delivery
+ */
+class MarketplaceServiceDeliveryParsingTest extends Unit
+{
+    /**
+     * Полный адрес: город, улица, дом
+     * Пример из прода: заказ #4409
+     */
+    public function testParseFullAddress_CityStreetHouse(): void
+    {
+        $text = 'Доставка: 8 марта 2026 в 10:30—12:30, Нижний Новгород, улица Героев Советского Союза Костьева, 19, Кв 41 этаж 1 подъезд 3';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertNotEquals('Уточняется', $result['city'], 'Город должен быть распознан');
+        $this->assertNotEquals('Уточняется', $result['street'], 'Улица должна быть распознана');
+        $this->assertNotEquals('Уточняется', $result['house'], 'Дом должен быть распознан');
+    }
+
+    /**
+     * Адрес без улицы: "Уточните адрес доставки у получателя"
+     * Пример из прода: заказ #4408
+     */
+    public function testParseNoAddress_AskRecipient(): void
+    {
+        $text = 'Доставка: сегодня, 27 февраля 2026 в 17:30—18:00, Уточните адрес доставки у получателя';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertEquals('Уточняется', $result['city']);
+        $this->assertEquals('Уточняется', $result['street']);
+        $this->assertEquals('Уточняется', $result['house']);
+    }
+
+    /**
+     * Сюрприз-доставка: адрес будет позже через SMS
+     * Пример из прода: заказы #4459, #4460, #4461, #4464
+     */
+    public function testParseSurpriseDelivery_SmsLater(): void
+    {
+        $text = 'Доставка: Отправим смс получателю 8 марта в 07:30, чтобы узнать данные для доставки Пожалуйста, не звоните раньше, чтобы сохранить сюрприз';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        // Адреса нет — всё "Уточняется"
+        $this->assertEquals('Уточняется', $result['street']);
+        $this->assertEquals('Уточняется', $result['house']);
+    }
+
+    /**
+     * Пустая строка
+     */
+    public function testParseEmptyString(): void
+    {
+        $result = MarketplaceService::parseAddressFromDeliveryText('');
+
+        $this->assertEquals('Уточняется', $result['city']);
+        $this->assertEquals('Уточняется', $result['street']);
+        $this->assertEquals('Уточняется', $result['house']);
+        $this->assertEquals(0.0, $result['latitude']);
+        $this->assertEquals(0.0, $result['longitude']);
+    }
+
+    /**
+     * Только "Доставка:" без адреса
+     */
+    public function testParseDeliveryPrefixOnly(): void
+    {
+        $result = MarketplaceService::parseAddressFromDeliveryText('Доставка:');
+
+        $this->assertEquals('Уточняется', $result['street']);
+    }
+
+    /**
+     * GPS-координаты для Нижнего Новгорода
+     */
+    public function testParseNizhnyNovgorod_HasGps(): void
+    {
+        $text = 'Доставка: 5 марта 2026 в 12:00—14:00, Нижний Новгород, ул. Ленина, 10';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertGreaterThan(0, $result['latitude'], 'Широта должна быть заполнена для НН');
+        $this->assertGreaterThan(0, $result['longitude'], 'Долгота должна быть заполнена для НН');
+    }
+
+    /**
+     * GPS-координаты для Москвы
+     */
+    public function testParseMoscow_HasGps(): void
+    {
+        $text = 'Доставка: 5 марта 2026 в 12:00—14:00, Москва, Тверская, 1';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertGreaterThan(0, $result['latitude'], 'Широта должна быть заполнена для Москвы');
+        $this->assertGreaterThan(0, $result['longitude'], 'Долгота должна быть заполнена для Москвы');
+    }
+
+    /**
+     * Неизвестный город — GPS = 0
+     */
+    public function testParseUnknownCity_ZeroGps(): void
+    {
+        $text = 'Доставка: 5 марта 2026 в 12:00—14:00, Саратов, ул. Мира, 5';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertEquals(0.0, $result['latitude']);
+        $this->assertEquals(0.0, $result['longitude']);
+    }
+
+    /**
+     * Самовывоз
+     */
+    public function testParsePickup(): void
+    {
+        $text = 'Самовывоз: 5 марта 2026 в 12:00—14:00, Нижний Новгород, ул. Речная, 22';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        $this->assertNotEquals('Уточняется', $result['street'], 'Улица должна быть распознана для самовывоза');
+    }
+
+    /**
+     * Результат всегда содержит все 5 ключей
+     */
+    public function testParseResult_AlwaysHasAllKeys(): void
+    {
+        $result = MarketplaceService::parseAddressFromDeliveryText('любой текст');
+
+        $this->assertArrayHasKey('city', $result);
+        $this->assertArrayHasKey('street', $result);
+        $this->assertArrayHasKey('house', $result);
+        $this->assertArrayHasKey('latitude', $result);
+        $this->assertArrayHasKey('longitude', $result);
+    }
+
+    /**
+     * Все значения — строки или float, никогда не null
+     */
+    public function testParseResult_NeverReturnsNull(): void
+    {
+        $inputs = [
+            '',
+            'Доставка:',
+            'Доставка: сегодня',
+            'random text',
+            'Доставка: Отправим смс получателю',
+        ];
+
+        foreach ($inputs as $input) {
+            $result = MarketplaceService::parseAddressFromDeliveryText($input);
+
+            $this->assertNotNull($result['city'], "city не должен быть null для: '$input'");
+            $this->assertNotNull($result['street'], "street не должен быть null для: '$input'");
+            $this->assertNotNull($result['house'], "house не должен быть null для: '$input'");
+            $this->assertNotNull($result['latitude'], "latitude не должен быть null для: '$input'");
+            $this->assertNotNull($result['longitude'], "longitude не должен быть null для: '$input'");
+        }
+    }
+
+    /**
+     * Город с двумя словами парсится корректно
+     */
+    public function testParseTwoWordCity(): void
+    {
+        $text = 'Доставка: 5 марта 2026 в 10:00—12:00, Нижний Новгород, Большая Покровская, 1';
+
+        $result = MarketplaceService::parseAddressFromDeliveryText($text);
+
+        // Должен распознать хотя бы что-то кроме "Уточняется"
+        $this->assertNotEquals('Уточняется', $result['street']);
+    }
+}