From: fomichev Date: Tue, 12 Nov 2024 07:59:01 +0000 (+0300) Subject: Merge branch 'refs/heads/develop' into feature_fomichev_erp_149_flowwow_feed X-Git-Tag: 1.6~13^2~10 X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=e3b86c61a4952f5ad7d71f80c09badbf6ff5be04;p=erp24_rep%2Fyii-erp24%2F.git Merge branch 'refs/heads/develop' into feature_fomichev_erp_149_flowwow_feed # Conflicts: # erp24/services/MarketplaceService.php --- e3b86c61a4952f5ad7d71f80c09badbf6ff5be04 diff --cc erp24/services/MarketplaceService.php index 45ddbf5f,ad2b1bee..cf075d6c --- a/erp24/services/MarketplaceService.php +++ b/erp24/services/MarketplaceService.php @@@ -19,97 -14,46 +19,100 @@@ use yii_app\records\ProductsClass class MarketplaceService { + + private const CATEGORIES_WITH_SUBCATEGORIES = [ + "Цветы" => [ + "Монобукеты", + "Авторские букеты", + "Цветы в коробке", + "Цветы в корзине", + "Букеты невесты", + "Композиции из цветов", + "Мягкие игрушки", + "Подарочные наборы", + "Мишки из роз", + "Открытки", + "Стабилизированные цветы", + "Букеты из сухоцветов", + "Искусственные цветы", + "Цветы в ящиках", + "Другое", + "Цветы поштучно", + "Траурные цветы", + "Букеты из мыла", + "Цветы для интерьера", + ], + "Живые растения" => [ + "Цветы в горшках", + "Флорариумы", + "Суккуленты, кактусы", + "Бонсаи", + "Пальмы и деревья", + "Левитирующие растения", + "Саженцы и рассада", + "Фитокартины", + "Семена", + "Другое", + "Кашпо и горшки для цветов", + "Наборы для выращивания", + "Грунты и удобрения", + "Аксессуары для комнатных растений", + "Спатифиллумы", + "Замиокулькасы", + "Антуриумы" + ] + ]; + - public static function infoForMarketplace(int $marketId, bool $is_yandex) { + public static function infoForMarketplace(int $marketId) { - if (!array_key_exists($marketId, MarketplaceStore::getWarehouseId())) - return; + if (!array_key_exists($marketId, MarketplaceStore::getWarehouseId())) { + return null; + } - - $marketplacesCount = count(MarketplaceStore::getWarehouseId()); + $is_yandex = $marketId == 2; // 1. Получение гуидов букетов $productsGroup = ProductsClass::find() - ->orWhere(['ilike', 'tip', ProductsClass::MARKETPLACE]) - ->orWhere(['ilike', 'tip', ProductsClass::MARKETPLACE_ADDITIONAL]) + ->where(['tip' => [ProductsClass::MARKETPLACE, ProductsClass::MARKETPLACE_ADDITIONAL]]) ->select('category_id') - ->asArray(); + ->asArray() + ->column(); $productsGuids = Products1c::find() - ->andWhere(['in', 'parent_id', $productsGroup]) - ->andWhere(['<>', 'components', '']) - ->select('id') - ->column(); + ->where(['parent_id' => $productsGroup]) + ->andWhere(['!=', 'components', '']) + ->select(['id', 'components']) + ->asArray() + ->all(); // 2. Получение цен на букеты - // $prices = ArrayHelper::map(Prices::findAll(['product_id' => $productsGuids]), 'product_id', 'price'); - $prices = ArrayHelper::map(Prices::findAll(['product_id' => ArrayHelper::getColumn($productsGuids, 'id')]), 'product_id', 'price'); ++ // $prices = ArrayHelper::map(Prices::findAll(['product_id' => ArrayHelper::getColumn($productsGuids, 'id')]), 'product_id', 'price'); + $allPrices = Prices::findAll(['product_id' => $productsGuids]); + $prices = ArrayHelper::map($allPrices, 'product_id', 'price'); + + + foreach ($productsGuids as $productId) { + if (!array_key_exists($productId, $prices)) { + $prices[$productId] = 0; + } + } - // 3. Получение состава букетов $bouquetComposition = []; - foreach ($productsGuids as $guid) { - $components = Products1c::find() - ->andWhere(['id' => $guid]) - ->select('components') - ->column(); + $componentsGuids = []; + foreach ($productsGuids as $ind => $dataComponents) { + $guid = $dataComponents['id']; + $components = $dataComponents['components']; // Проверяем, что массив не пустой и строка валидна - if (!empty($components) && !in_array('', $components, true)) { - $bouquetComposition[$guid] = json_decode($components[0]); // Сохраняем компоненты + if (!empty($components)) { + $componentsJson = json_decode($components); + $bouquetComposition[$guid] = $componentsJson; + foreach ($componentsJson as $compJsonGuid => $compJsonCnt) { + $componentsGuids[] = $compJsonGuid; + } } } + $componentsGuids = array_unique($componentsGuids); // 4. Проверка остатков @@@ -139,13 -93,11 +152,13 @@@ $temp = intval($values['count'] / $products->$productGuid); $bouquetCount = !empty($bouquetCount) ? min($bouquetCount, $temp) : $temp; $store = $values['marketplace_guid']; - } + - if (isset($bouquetCount) && $bouquetCount > 0) { + if (!empty($stockRecords) && isset($store) && $bouquetCount > 0) { $stocks[$guid] = ['count' => $bouquetCount, 'store' => $store]; } + } + } // 5. Получение приоритетов @@@ -225,343 -179,6 +240,343 @@@ } } - return Json::encode($availableGuids); + return Json::encode($distribution); } + + /** + * Статический метод для получения всей информации по продуктам, которая необходима для создания фида. + * + * @return array + */ + public static function getAllProductsInfo($id) + { + $parents = ProductsClass::find() + ->select('category_id') + ->orWhere(['ilike', 'tip', ProductsClass::MARKETPLACE]) + ->orWhere(['ilike', 'tip', ProductsClass::MARKETPLACE_ADDITIONAL]) + ->column(); + + $products = Products1c::find() + ->where(['tip' => 'products']) + ->andWhere(['not', ['components' => '']]) + ->andWhere(['parent_id' => $parents]) + + ->all(); + + $count = (int)$id; + $selectedProducts = array_slice($products, 0, $count); + + $result = []; + + foreach ($selectedProducts as $product) { + + $properties = MarketplaceService::getProductPropertiesByGuid($product->id); + if (!$properties) { + $message = "Товар с GUID {$product->id} не имеет свойств в MatrixErpProperty и был исключен из фида."; + Yii::error($message, __METHOD__); + + + InfoLogService::setInfoLog( + __FILE__, + __LINE__, + $message, + 'Missing properties error' + ); + continue; + } + + $price = MarketplaceService::getProductPrice($product->id); + + + /* if ($price == 0) { + $message = "У товара {$product->id} отсутствует цена и он будет исключен из фида."; + Yii::error($message, __METHOD__); + + + InfoLogService::setInfoLog( + __FILE__, + __LINE__, + $message, + 'Zero price error' + ); + continue; + }*/ + + $components = json_decode($product->components, true); + $composition = []; + + foreach ($components as $componentId => $quantity) { + $component = Products1c::findOne(['id' => $componentId]); + if ($component && $quantity > 0) { + $composition[] = [ + 'name' => $component->name, + 'quantity' => $quantity, + 'unit' => 'шт' + ]; + } + } + + $properties = MarketplaceService::getProductPropertiesByGuid($product->id); + + $result[] = [ + 'id' => $product->id, + 'name' => $properties['displayName'], + 'pictures' => [$properties['imageUrl']], + 'price' => $price, + 'oldprice' => MarketplaceService::getProductOldPrice($product->id), + 'description' => MarketplaceService::getProductDescription($product->id), + 'qty' => MarketplaceService::getProductQty($product->id), + 'amount' => MarketplaceService::getProductQty($product->id), + 'weight' => MarketplaceService::getProductWeight($product->id), + 'minorder' => MarketplaceService::getProductMinOrder($product->id), + 'composition' => $composition, + 'available' => MarketplaceService::getProductAvailability($product->id), + 'category_id' => MarketplaceService::getProductCategory($product->id), + 'category_name' => $properties['flowwowSubcategory'], + 'params' => MarketplaceService::getProductParams($product->id), + 'productLink' => MarketplaceService::getProductLinkByGuid($product->id), + ]; + } + + return $result; + } + + + /** + * Статический метод для создания XML-фида на основе информации о продуктах. + * + * @param array $productsInfo + * @return string + */ + public static function createXMLFeed($productsInfo) + { + $xml = new \SimpleXMLElement(''); + $xml->addAttribute('date', date('Y-m-d H:i')); + + $shop = $xml->addChild('shop'); + $shop->addChild('name', 'Интернет магазин База Цветов 24'); + $shop->addChild('company', 'Интернет магазин База Цветов 24'); + $shop->addChild('url', 'https://bazacvetov24.ru'); + $shop->addChild('platform', 'BSM/Yandex/Market'); + + // Добавление валюты + $currencies = $shop->addChild('currencies'); + $currency = $currencies->addChild('currency'); + $currency->addAttribute('id', 'RUB'); + $currency->addAttribute('rate', '1'); + + // Добавление категорий (пример добавления нескольких категорий) + $uniqueCategories = []; + foreach ($productsInfo as $product) { + $categoryId = $product['category_id']; + $categoryName = $product['category_name']; + + + if (!isset($uniqueCategories[$categoryId])) { + $uniqueCategories[$categoryId] = $categoryName; + } + } + + + $categories = $shop->addChild('categories'); + foreach ($uniqueCategories as $id => $name) { + $category = $categories->addChild('category', $name); + $category->addAttribute('id', $id); + } + + // Добавление офферов (продуктов) + $offers = $shop->addChild('offers'); + foreach ($productsInfo as $product) { + $offer = $offers->addChild('offer'); + $offer->addAttribute('id', $product['id']); + $offer->addAttribute('available', $product['available'] ? 'true' : 'false'); + + // Добавление URL продукта + $offer->addChild('url', $product['productLink']); + + // Добавление цены и валюты + $offer->addChild('price', $product['price']); + $offer->addChild('oldPrice', $product['oldprice']); + $offer->addChild('currencyId', 'RUB'); + $offer->addChild('categoryId', $product['category_id']); + + // Добавление доступности доставки + $offer->addChild('delivery', 'true'); + + // Описание продукта + if (!empty($product['description'])) { + $offer->addChild('description', $product['description']); + } + + // Добавление веса и количества + $offer->addChild('weight', $product['weight']); + // $offer->addChild('qty', $product['qty']); + // $offer->addChild('amount', $product['amount']); + // $offer->addChild('cost', $product['amount']); + + foreach ($product['composition'] as $component) { + $consist = $offer->addChild('consist', $component['quantity']); + $consist->addAttribute('name', $component['name']); + $consist->addAttribute('unit', $component['unit']); + // $consist->addAttribute('cost', 12); + } + + // Добавление параметров + if (!empty($product['params'])) { + foreach ($product['params'] as $paramName => $paramValue) { + $param = $offer->addChild('param', $paramValue); + $param->addAttribute('name', $paramName); + } + } + + // Название продукта + $offer->addChild('name', $product['name']); + + // Добавление изображений продукта + if (!empty($product['pictures'])) { + foreach ($product['pictures'] as $picture) { + $offer->addChild('picture', $picture); + } + } + } + + return $xml->asXML(); + } + + + private static function getProductPropertiesByGuid($guid) { + $product = MatrixErpProperty::find() + ->where(['guid' => $guid]) + ->one(); + + if (!$product) { + return null; + } + + return [ + 'id' => $product->id, + 'description' => $product->description, + 'imageUrl' => self::getProductImageUrl($product->image_id), + 'date' => $product->date, + 'displayName' => $product->display_name, + 'externalImageUrl' => $product->external_image_url, + 'productUrl' => $product->product_url, + 'flowwowCategory' => $product->flowwow_category, + 'flowwowSubcategory' => $product->flowwow_subcategory, + ]; + } + + private static function getProductImageUrl($imageId) { + $image = Images::findOne($imageId); + $fileName = ''; + if ($image && File::src($image->filename, 'images') != null) { + $fileName = File::src($image->filename, 'images'); + return 'https://media.dev.erp-flowers.ru/media/view-url?url=' . $fileName; + } + + + return null; + } + private static function getProductLinkByGuid($guid) { + return 'https://media.dev.erp-flowers.ru/media/view-card?guid=' . urlencode($guid); + } + + private static function getProductPrice($productId) { + $price = Prices::find() + ->where(['product_id' => $productId]) + ->one(); + return $price['price'] ?? 0; + } + private static function getProductOldPrice($productId) { return 300; } + private static function getProductDescription($productId) { + + $product = MatrixErpProperty::find() + ->where(['guid' => $productId]) + ->one(); + + if (!$product) { + return null; // Вернуть null, если продукт не найден + } + + return $product->description; + } + private static function getProductQty($productId) { return 9; } + private static function getProductWeight($productId) { + return 0.5; + } + private static function getProductCategory($productId) { + + $product = MatrixErpProperty::find() + ->where(['guid' => $productId]) + ->one(); + + if (!$product) { + return null; + } + + return self::getCategorySubcategoryId($product->flowwow_category, $product->flowwow_subcategory); + } + + public static function getCategorySubcategoryId($category, $subcategory) + { + $categories = self::CATEGORIES_WITH_SUBCATEGORIES; + + if (!array_key_exists($category, $categories)) { + return null; + } + + $categoryIndex = array_search($category, array_keys($categories)) + 1; + $subcategoryIndex = array_search($subcategory, $categories[$category]) + 1; + + if ($subcategoryIndex === false) { + return null; + } + + + return (string)$categoryIndex . (string)$subcategoryIndex; + } + + private static function getProductMinOrder($productId) { + return 1; + } + private static function getProductAvailability($productId) { + return true; + } + + private static function getProductMaterial($productId) + { + // Здесь можно реализовать логику получения материала продукта + return 'Цветы'; // Пример значения + } + + private static function getProductWidth($productId) + { + // Здесь можно реализовать логику получения ширины продукта + return 18; // Пример значения + } + + private static function getProductHeight($productId) + { + // Здесь можно реализовать логику получения высоты продукта + return 20; // Пример значения + } + + private static function getProductLength($productId) + { + // Здесь можно реализовать логику получения длины продукта + return 9; // Пример значения + } + + private static function getProductParams($productId) + { + return [ + + 'Ширина, См' => self::getProductWidth($productId), + 'Высота, См' => self::getProductHeight($productId), + + ]; + } + + + }