From: Vladimir Fomichev Date: Tue, 2 Sep 2025 09:53:10 +0000 (+0300) Subject: Правки по загрузке X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=37dc0c86a11a6428f00923d9de8bf55e6071566a;p=erp24_rep%2Fyii-erp24%2F.git Правки по загрузке --- diff --git a/erp24/actions/marketplace/ReportAction.php b/erp24/actions/marketplace/ReportAction.php index 5c86dec8..5bd262d9 100644 --- a/erp24/actions/marketplace/ReportAction.php +++ b/erp24/actions/marketplace/ReportAction.php @@ -33,10 +33,10 @@ class ReportAction extends Action 'flowwow_category' => 'string', 'flowwow_subcategory' => 'string', 'yandex_category' => 'string', - 'length' => 'numeric', + //'length' => 'numeric', 'width' => 'numeric', 'height' => 'numeric', - 'weight' => 'numeric', + //'weight' => 'numeric', ]; $conditions = []; diff --git a/erp24/controllers/MatrixErpController.php b/erp24/controllers/MatrixErpController.php index a093b2f3..c0742714 100644 --- a/erp24/controllers/MatrixErpController.php +++ b/erp24/controllers/MatrixErpController.php @@ -292,7 +292,7 @@ class MatrixErpController extends Controller if ($model->validate()) { foreach ($model->files as $file) { - $results[] = $this->processFile($file, $model->category); + $results[] = $this->processFile($file, $model->category, $model->subcategory); } Yii::$app->session->setFlash('importResults', $results); @@ -309,7 +309,7 @@ class MatrixErpController extends Controller /** * Обработка одного файла: парсинг → поиск MatrixErp по артикулу → upsert MatrixErpProperty по GUID. */ - protected function processFile(UploadedFile $file, string $category): array + protected function processFile(UploadedFile $file, string $category, string $subcategory): array { $res = [ 'file' => $file->name, @@ -325,16 +325,15 @@ class MatrixErpController extends Controller $service = new ProductParserService(); $parsed = $service->parseProductHtml($html); - $products = $this->normalizeParsed($parsed); - var_dump($products);die(); + if (empty($products)) { throw new \RuntimeException('Парсер вернул пустой результат.'); } foreach ($products as $p) { $art = $this->extractArticule($p['name'] ?? ''); - $res['articule'] = $res['articule'] ?? $art; + $res['articule'] = $art ?? $res['articule']; if (!$art) { $res['status'] = 'error'; @@ -351,7 +350,7 @@ class MatrixErpController extends Controller $res['guid'] = $matrix->guid; - if (!$this->upsertProperty($matrix, $p, $category)) { + if (!$this->upsertProperty($matrix, $p, $category, $subcategory)) { $res['status'] = 'error'; $res['errors'][] = "Не удалось сохранить свойства для GUID {$matrix->guid}."; } @@ -383,14 +382,16 @@ class MatrixErpController extends Controller } /** - * Артикул из названия: ищем (FW0125) или просто FW0125, либо "Артикул: FW0125". + * Артикул из названия: ищем (FW0125) */ protected function extractArticule(string $name): ?string { - $pattern = `/\\((?[A-Z]{2,4}\\d{3,6})\\)/u`; - if (preg_match($pattern, $name, $m)) { - return strtoupper($m['art']); - } + + if ($name) { + $nameStringArray = explode('(', $name); + $articule = trim(explode(')', $nameStringArray[1])[0]); + return $articule; + } return null; } @@ -400,74 +401,68 @@ class MatrixErpController extends Controller */ protected function upsertProperty(MatrixErp $matrix, array $matrixProduct, string $category, string $subcategory): bool { - $prop = MatrixErpProperty::find()->where(['guid' => $matrix->guid])->one(); - $nowDt = date('Y-m-d H:i:s'); - $nowD = date('Y-m-d'); - - if (!$prop) { - $prop = new MatrixErpProperty(); - $prop->guid = $matrix->guid; - $prop->matrix_erp_id = $matrix->guid; - $prop->date = $nowD; - $prop->created_admin_id = Yii::$app->user->id ?? null; - $prop->created_at = $nowDt; + $matrixProductProperty = MatrixErpProperty::find()->where(['guid' => $matrix->guid])->one(); + $date = date('Y-m-d H:i:s'); + + if (!$matrixProductProperty) { + $matrixProductProperty = new MatrixErpProperty(); + $matrixProductProperty->guid = $matrix->guid; + $matrixProductProperty->date = $date; + $matrixProductProperty->created_admin_id = Yii::$app->user->id ?? null; + $matrixProductProperty->created_at = $date; } else { - $prop->updated_admin_id = Yii::$app->user->id ?? null; - $prop->updated_at = $nowDt; + $matrixProductProperty->updated_admin_id = Yii::$app->user->id ?? null; + $matrixProductProperty->updated_at = $date; } - try { - $uploadImage = FileService::downloadAsUploadedFile($externalUrl, maxBytes: 8_000_000); - } catch (\Throwable $e) { - Yii::error("Ошибка загрузки изображения по ссылке: " . $e->getMessage()); - - \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - return ['error' => 'Не удалось скачать файл по ссылке']; - } + try { + $uploadImage = FileService::downloadAsUploadedFile($matrixProduct['image_url']); + } catch (\Throwable $e) { + Yii::error("Ошибка загрузки изображения по ссылке: " . $e->getMessage()); + } if ($uploadImage) { if (Images::isImageFile($uploadImage, ['png', 'jpg', 'jpeg', 'webp', 'gif'])) { $image = new Images(); - $imageId = $image->loadImage($uploadImage); // ваш существующий метод (как при обычной загрузке) + $imageId = $image->loadImage($uploadImage); if (!empty($imageId)) { - $prop->image_id = $imageId; - $prop->external_image_url = MarketplaceService::getProductImageUrl($imageId); + $matrixProductProperty->image_id = $imageId; + $matrixProductProperty->external_image_url = MarketplaceService::getProductImageUrl($imageId); if (!empty($oldFile)) { $oldFile->delete(); } - if (!$prop->save()) { - Yii::error("Ошибка сохранения ссылок на картинки " . json_encode($modelEdit->getErrors(), JSON_UNESCAPED_UNICODE)); + if (!$matrixProductProperty->save()) { + Yii::error("Ошибка сохранения ссылок на картинки " . json_encode($matrixProductProperty->getErrors(), JSON_UNESCAPED_UNICODE)); } } } else { - \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - return ['error' => 'Файл не является изображением либо запрещённое расширение']; + Yii::error(json_encode(['error' => 'Файл не является изображением либо запрещённое расширение'], JSON_UNESCAPED_UNICODE)); + return false; } } else { - \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; - return ['error' => 'Не передан файл и не указана ссылка']; + Yii::error(json_encode(['error' => 'Не передан файл и не указана ссылка'], JSON_UNESCAPED_UNICODE)); + return false; } - $prop->display_name = $matrixProduct['name'] ?? $prop->display_name; - $prop->description = $matrixProduct['description'] ?? $prop->description; - $prop->external_image_url = $matrixProduct['image_url'] ?? $prop->external_image_url; - $prop->product_url = $matrixProduct['product_url'] ?? $prop->product_url; + $matrixProductProperty->display_name = $matrixProduct['name']; + $matrixProductProperty->description = $matrixProduct['description']; + + $matrixProductProperty->product_url = MarketplaceService::getProductLinkByGuid($matrixProductProperty->guid); // Категории - $prop->flowwow_category = $category; - $prop->flowwow_subcategory = $category; - $prop->flowwow_subcategory = $matrixProduct['properties']['subcategory'] ?? $prop->flowwow_subcategory; - $prop->yandex_category = $matrixProduct['properties']['yandex_category'] ?? $prop->yandex_category; + $matrixProductProperty->flowwow_category = $category; + $matrixProductProperty->flowwow_subcategory = $subcategory; + $matrixProductProperty->yandex_category = "Цветы, букеты, композиции"; + + + if (isset($matrixProduct['properties']['Размер']['ширина'])) $matrixProductProperty->width = (float)$matrixProduct['properties']['Размер']['ширина']; + if (isset($matrixProduct['properties']['Размер']['высота'])) $matrixProductProperty->height = (float)$matrixProduct['properties']['Размер']['высота']; - if (isset($matrixProduct['properties']['length'])) $prop->length = (float)$matrixProduct['properties']['length']; - if (isset($matrixProduct['properties']['width'])) $prop->width = (float)$matrixProduct['properties']['width']; - if (isset($matrixProduct['properties']['height'])) $prop->height = (float)$matrixProduct['properties']['height']; - if (isset($matrixProduct['properties']['weight'])) $prop->weight = (float)$matrixProduct['properties']['weight']; - return $prop->save(); + return $matrixProductProperty->save(); } } \ No newline at end of file diff --git a/erp24/records/Images.php b/erp24/records/Images.php index 67210757..01460daa 100644 --- a/erp24/records/Images.php +++ b/erp24/records/Images.php @@ -94,7 +94,7 @@ class Images extends \yii\db\ActiveRecord mkdir($imageDirPath); } - if ($file_obj->saveAs($imageDirPath . '/' . $file_name)) { + if ($file_obj->saveAs($imageDirPath . '/' . $file_name, false)) { $this->original_name = $file_obj->baseName; $this->filename = $file_name; $this->size = $file_obj->size; diff --git a/erp24/records/MatrixErpProperty.php b/erp24/records/MatrixErpProperty.php index b65840ca..83a8e4e0 100644 --- a/erp24/records/MatrixErpProperty.php +++ b/erp24/records/MatrixErpProperty.php @@ -8,7 +8,6 @@ use Yii; * This is the model class for table "matrix_erp_property". * * @property int $id ID - * @property string $matrix_erp_id * @property string $guid * @property string|null $description Описание * @property int|null $image_id Изображение diff --git a/erp24/services/ProductParserService.php b/erp24/services/ProductParserService.php index 7f7e6b93..d05f2fa0 100644 --- a/erp24/services/ProductParserService.php +++ b/erp24/services/ProductParserService.php @@ -17,55 +17,23 @@ class ProductParserService { return [ 'name' => $this->extractName($xpath), - 'price' => $this->extractPrice($xpath), - 'old_price' => $this->extractOldPrice($xpath), - 'rating' => $this->extractRating($xpath), - 'reviews_count' => $this->extractReviewsCount($xpath), 'image_url' => $this->extractImageUrl($xpath), 'description' => $this->extractDescription($xpath), 'properties' => $this->extractProperties($xpath), - ]; } - private - function extractName(DOMXPath $xpath): string + private function extractName(DOMXPath $xpath): string { $node = $xpath->query("//h1")->item(0); return $node ? trim($node->nodeValue) : ''; } - private - function extractPrice(DOMXPath $xpath): string - { - $node = $xpath->query("//span[@class='footer-price']")->item(0); - return $node ? trim($node->nodeValue) : ''; - } - - private - function extractOldPrice(DOMXPath $xpath): string - { - $node = $xpath->query("//div[@class='footer-old-price']")->item(0); - return $node ? trim($node->nodeValue) : ''; - } - private - function extractRating(DOMXPath $xpath): string - { - $node = $xpath->query("//div[@class='rating']//div[contains(@class, 'el-rate')]")->item(0); - return $node ? $node->getAttribute('data-score') : ''; - } - private - function extractReviewsCount(DOMXPath $xpath): string - { - $node = $xpath->query("//div[@class='review-count']")->item(0); - return $node ? trim($node->nodeValue) : ''; - } - private - function extractImageUrl(DOMXPath $xpath): string + private function extractImageUrl(DOMXPath $xpath): string { $q1 = "//div[@id='js-detect-events']" . "//div[contains(concat(' ', normalize-space(@class), ' '), ' swiper-slide-active ')]" . @@ -92,14 +60,18 @@ class ProductParserService { return $src; } - private - function extractDescription(DOMXPath $xpath): string + private function extractDescription(DOMXPath $xpath): string { - $node = $xpath->query("//div[@class='product-properties-general']" . "//div[@class='property-item']" . "//p[@class='pre-line']" . "//span")->item(0); + $expression = + "//*[contains(concat(' ', normalize-space(@class), ' '), ' product-properties-general ')]" . + "//*[contains(concat(' ', normalize-space(@class), ' '), ' property-item ')]" . + "//*[contains(concat(' ', normalize-space(@class), ' '), ' pre-line ')]//span"; + + $node = $xpath->query($expression)->item(0); return $node ? trim($node->nodeValue) : ''; } - function extractProperties(DOMXPath $xpath): array + private function extractProperties(DOMXPath $xpath): array { $properties = []; @@ -133,40 +105,10 @@ class ProductParserService { if ($sizes) { $properties['Размер'] = $sizes; - if (isset($sizes['Ширина'])) $properties['width'] = $sizes['Ширина']; - if (isset($sizes['Высота'])) $properties['height'] = $sizes['Высота']; } - continue; - } - - - $valueNode = $xpath->query( - ".//*[contains(concat(' ', normalize-space(@class), ' '), ' property-text ') " . - " or contains(concat(' ', normalize-space(@class), ' '), ' pre-line ')]", - $node - )->item(0); - - if ($valueNode) { - $properties[$propName] = trim(preg_replace('/\s+/u', ' ', $valueNode->textContent)); } - } - - if (!isset($properties['width']) || !isset($properties['height'])) { - $tagSpans = $xpath->query("//ul[contains(@class,'size-tag')]//li//span[not(contains(@class,'size-tag-icon'))]"); - $seen = []; - foreach ($tagSpans as $span) { - $text = trim($span->textContent); - if (preg_match('/(\d+(?:[.,]\d+)?)\s*см/ui', $text, $m)) { - $val = (float) str_replace(',', '.', $m[1]); - $seen[] = $val; - } - } - if (!empty($seen)) { - if (!isset($properties['width']) && isset($seen[0])) $properties['width'] = $seen[0]; - if (!isset($properties['height']) && isset($seen[1])) $properties['height'] = $seen[1]; - } } return $properties;