27 private ?
SkuTree $skuTree =
null;
33 $this->skuTree =
new SkuTree($iblockInfo);
43 $result->addError(
new Error(sprintf(
44 'New product "%s" must be saved.', $sku->
getName()
49 if (!$brandProperty || $brandProperty->getPropertyValueCollection()->isEmpty())
51 $result->addError(
new Error(
52 sprintf(
'Product "%s"(%s) has no brands.', $sku->
getParent()->getName(), $sku->
getParent()->getId() ??
'new'),
55 'productId' => $sku->
getParent()->getId(),
63 $result->addError(
new Error(
64 sprintf(
'Product "%s"(%s) has no images.', $sku->
getName(), $sku->
getId() ??
'new'),
67 'productId' => $sku->
getId(),
75 $result->addError(
new Error(
76 sprintf(
'Product "%s"(%s) has no prices.', $sku->
getName(), $sku->
getId() ??
'new'),
79 'productId' => $sku->
getId(),
94 $result->setData($this->prepareSimpleProduct($sku));
98 $result->setData($this->prepareVariation($sku));
104 private function prepareSimpleProduct(
BaseSku $sku): array
106 $fields = $this->getBaseFields($sku);
108 return [$sku->
getId() => $fields];
111 private function prepareVariation(
BaseSku $sku): array
113 $fields = $this->getBaseFields($sku);
116 if ($this->skuTree && $skuParent)
118 $skuTree = $this->skuTree->
load([$skuParent->getId()])[$skuParent->getId()];
119 $skuFields = $this->getSkuFields($sku, $skuTree);
120 if (!empty($skuFields))
122 $fields[
'data'] += $skuFields;
126 return [$sku->
getId() => $fields];
131 return self::RETAILER_ID_PREFIX . $id;
136 return str_replace(self::RETAILER_ID_PREFIX,
'', $retailerId);
149 private function getBaseFields(
BaseSku $variation): array
152 'method' =>
'UPDATE',
153 'retailer_id' => self::RETAILER_ID_PREFIX . $variation->
getId(),
155 'name' => $this->getProductName($variation),
156 'description' => $this->getProductDescription($variation),
157 'retailer_product_group_id' => $this->getProductRetailerId($variation),
158 'url' => $this->getProductUrl($variation),
159 'image_url' => $this->getProductImageUrl($variation),
162 'brand' => $this->getProductBrand($variation),
163 'condition' =>
'new',
164 'availability' =>
'in stock',
165 'price' => $this->getProductPrice($variation),
166 'currency' => $this->getProductCurrency($variation),
171 private function getSkuFields(
BaseSku $variation, array $skuTree): array
173 $offerTree = $this->getOfferTree($variation->
getId(), $skuTree);
174 if (empty($offerTree) || empty($offerTree[
'DISPLAY_PROPERTIES']))
181 [$color, $size, $custom] = $this->extractVariants($offerTree);
185 $fields[
'color'] = $color;
190 $fields[
'size'] = $size;
195 $fields[
'additional_variant_attributes'] = $custom;
201 private function getOfferTree(
int $variationId, array $skuTree): ?array
203 foreach ($skuTree[
'OFFERS'] as $offer)
205 if ((
int)$offer[
'ID'] === $variationId)
214 private function extractVariants(array $offerTree): array
220 foreach ($offerTree[
'DISPLAY_PROPERTIES'] as $code => $property)
222 if ($color ===
null && $code ===
'COLOR_REF')
224 $color = $property[
'DISPLAY_VALUE'];
226 elseif ($size ===
null && ($code ===
'SIZES_CLOTHES' || $code ===
'SIZES_SHOES'))
228 $size = $property[
'DISPLAY_VALUE'];
232 $custom[$property[
'NAME']] = $property[
'DISPLAY_VALUE'];
236 return [$color, $size, $custom];
239 private function getProductName(BaseSku $variation): string
241 return $this->truncateSentence($variation->getName(), 100);
244 private function getProductDescription(BaseSku $variation): string
246 $description = $variation->getField(
'DETAIL_TEXT');
249 if ($variation->getField(
'DETAIL_TEXT_TYPE') ===
'html')
251 $description = HTMLToTxt($description);
254 return $this->truncateSentence($description, 5000);
257 $description = $variation->getField(
'PREVIEW_TEXT');
260 if ($variation->getField(
'PREVIEW_TEXT_TYPE') ===
'html')
262 $description = HTMLToTxt($description);
265 return $this->truncateSentence($description, 5000);
268 return $variation->getName();
271 private function getProductImageUrl(BaseSku $product): string
274 $image = $product->getFrontImageCollection()->getFirst();
275 if ($image && $image->getSource())
277 return $this->getCurrentUri($image->getSource());
283 private function getCurrentUri(
string $path): string
285 if (strpos($path,
'http') === 0)
293 $uri = $request->isHttps() ?
'https://' :
'http://';
294 $uri .= $server->getServerName();
296 (int)$server->getServerPort() === 80
297 || ($server->get(
'HTTPS') && (int)$server->getServerPort() === 443)
300 :
':' . $server->getServerPort();
303 return (
new Uri($uri))->getUri();
306 private function getProductPrice(BaseSku $entity): string
308 $basePrice = $entity->getPriceCollection()->findBasePrice();
311 return $basePrice->getPrice() * 100;
317 private function getProductCurrency(BaseSku $entity): string
319 $basePrice = $entity->getPriceCollection()->findBasePrice();
322 return $basePrice->getCurrency();
325 return \CCrmCurrency::GetDefaultCurrencyID();
328 private function truncateSentence(
string $sentence,
int $limit): string
335 if (mb_strlen($sentence) <= $limit)
340 return mb_substr($sentence, 0, mb_strrpos(mb_substr($sentence, 0, $limit + 1),
' '));
343 private function getProductUrl(BaseSku $variation): string
346 !Loader::includeModule(
'salescenter')
347 || !Loader::includeModule(
'landing'))
352 $product = $variation->getParent();
355 $siteUrlInfo = LandingManager::getInstance()->getCollectionPublicUrlInfo();
356 $siteUrl = $siteUrlInfo[
'url'] ??
null;
357 $productDetailUrl = \Bitrix\Landing\PublicAction\Utils::getIblockURL($product->getId(),
'detail');
359 if ($siteUrl && $productDetailUrl)
361 return str_replace(
'#system_catalog', $siteUrl, $productDetailUrl);
368 private function getProductBrand(BaseSku $variation): string
371 $product = $variation->getParent();
377 $names = $this->getBrandNames($brandProperty);
379 return implode(
', ', $names);
386 private function getBrandNames(Property $property): array
388 if (!Loader::includeModule(
'highloadblock'))
393 $userTypeSettings = $property->getSetting(
'USER_TYPE_SETTINGS');
394 $tableName = $userTypeSettings[
'TABLE_NAME'] ??
'';
396 if (empty($tableName))
401 $brandValues = $property->getPropertyValueCollection()->toArray();
402 if (empty($brandValues))
407 $brandValues = array_column($brandValues,
null,
'VALUE');
409 return array_intersect_key($this->loadBrandNamesMap($tableName), $brandValues);
412 private function loadBrandNamesMap(
string $tableName): array
414 static $nameMap = [];
416 if (!isset($nameMap[$tableName]))
420 $highLoadBlock = HighloadBlockTable::getList([
421 'filter' => [
'=TABLE_NAME' => $tableName],
425 if (!empty($highLoadBlock))
427 $entity = HighloadBlockTable::compileEntity($highLoadBlock);
428 $entityDataClass = $entity->getDataClass();
429 $directoryData = $entityDataClass::getList();
430 while ($element = $directoryData->fetch())
432 $tableMap[$element[
'UF_XML_ID']] = $element[
'UF_NAME'];
436 $nameMap[$tableName] = $tableMap;
439 return $nameMap[$tableName];