Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SW-613-exported-main-variant-config #233

Merged
merged 17 commits into from
Jan 17, 2022
Merged
7 changes: 6 additions & 1 deletion src/Controller/ExportController.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,13 @@ protected function initialize(Request $request, ?SalesChannelContext $context):
$this->salesChannelContext = $this->salesChannelService ? $this->salesChannelService
->getSalesChannelContext($context, $this->exportConfig->getShopkey()) : null;

$this->productService = ProductService::getInstance($this->container, $this->salesChannelContext);
$this->container->set('fin_search.sales_channel_context', $this->salesChannelContext);
$this->pluginConfig = $this->getPluginConfig();
$this->productService = ProductService::getInstance(
$this->container,
$this->salesChannelContext,
$this->pluginConfig
);

$this->export = Export::getInstance(
$this->exportConfig->getProductId() ? Export::TYPE_PRODUCT_ID : Export::TYPE_XML,
Expand All @@ -130,6 +134,7 @@ protected function validate(): ?Response
if (count($messages) > 0) {
$errorHandler = new ProductErrorHandler();
$errorHandler->getExportErrors()->addGeneralErrors($messages);

return $this->export->buildErrorResponse($errorHandler, $this->headerHandler->getHeaders());
}

Expand Down
114 changes: 109 additions & 5 deletions src/Export/ProductService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace FINDOLOGIC\FinSearch\Export;

use FINDOLOGIC\FinSearch\Findologic\MainVariant;
use FINDOLOGIC\FinSearch\Struct\Config;
use FINDOLOGIC\FinSearch\Utils\Utils;
use InvalidArgumentException;
use Psr\Container\ContainerInterface;
use Shopware\Core\Content\Product\Aggregate\ProductVisibility\ProductVisibilityDefinition;
use Shopware\Core\Content\Product\ProductCollection;
Expand All @@ -26,26 +29,34 @@ class ProductService
{
public const CONTAINER_ID = 'fin_search.product_service';

/** @var Config */
private $config;
zaifastafa marked this conversation as resolved.
Show resolved Hide resolved

/** @var ContainerInterface */
private $container;

/** @var SalesChannelContext|null */
private $salesChannelContext;

public function __construct(ContainerInterface $container, ?SalesChannelContext $salesChannelContext = null)
{
public function __construct(
ContainerInterface $container,
?SalesChannelContext $salesChannelContext = null,
?Config $config = null
zaifastafa marked this conversation as resolved.
Show resolved Hide resolved
) {
$this->container = $container;
$this->salesChannelContext = $salesChannelContext;
$this->config = $config ?? $container->get(Config::class);
}

public static function getInstance(
ContainerInterface $container,
?SalesChannelContext $salesChannelContext
?SalesChannelContext $salesChannelContext,
?Config $config = null
): ProductService {
if ($container->has(self::CONTAINER_ID)) {
$productService = $container->get(self::CONTAINER_ID);
} else {
$productService = new ProductService($container, $salesChannelContext);
$productService = new ProductService($container, $salesChannelContext, $config);
$container->set(self::CONTAINER_ID, $productService);
}

Expand All @@ -61,11 +72,21 @@ public function setSalesChannelContext(SalesChannelContext $salesChannelContext)
$this->salesChannelContext = $salesChannelContext;
}

public function setConfig(Config $config): void
{
$this->config = $config;
}

public function getSalesChannelContext(): ?SalesChannelContext
{
return $this->salesChannelContext;
}

public function getConfig(): ?Config
{
return $this->config;
}

public function getTotalProductCount(): int
{
$criteria = $this->buildProductCriteria();
Expand Down Expand Up @@ -275,7 +296,34 @@ protected function buildProductsWithVariantInformation(EntitySearchResult $resul
$products->add($product);
}

return $products;
if ($this->config->getMainVariant() === MainVariant::SHOPWARE_DEFAULT) {
return $products;
}

return $this->getProductsByMainVariantBasedOnConfig($products);
}

protected function getProductsByMainVariantBasedOnConfig(ProductCollection $products): ProductCollection
{
$mainVariantConfig = $this->config->getMainVariant();
$variantProducts = new ProductCollection();

foreach ($products as $product) {
switch ($mainVariantConfig) {
case MainVariant::MAIN_PARENT:
$parent = $this->getParentByMainProduct($product);
break;
case MainVariant::CHEAPEST:
$parent = $this->getParentByCheapestVariant($product);
break;
default:
zaifastafa marked this conversation as resolved.
Show resolved Hide resolved
throw new InvalidArgumentException($mainVariantConfig);
}

$variantProducts->add($parent);
}

return $variantProducts;
}

protected function getRealMainProductWithVariants(string $realMainProductId): ?ProductEntity
Expand All @@ -288,4 +336,60 @@ protected function assignChildrenOrSiblings(ProductEntity $product): void
$children = $this->getChildrenOrSiblings($product);
$product->setChildren($children);
}

protected function getParentByMainProduct(ProductEntity $product): ProductEntity
{
$children = new ProductCollection();
foreach ($product->getChildren() as $child) {
if ($child->getId() !== $product->getId()) {
$children->add($child);
}
}

$product->setChildren($children);

return $product;
}

protected function getParentByCheapestVariant(ProductEntity $product): ProductEntity
{
$currencyId = $this->salesChannelContext->getSalesChannel()->getCurrencyId();
$children = $product->getChildren();
// Add the current product in the children collection, so we can include it when
// checking for the cheapest price logic in the loop below.
$children->add($product);
// Get the real parent of the product. If no product is found, it means we
// already have the real parent.
$parent = $children->filter(static function (ProductEntity $childEntity) {
return $childEntity->getParentId() === null;
})->first();

if (!$parent) {
$parent = $product;
}

// Consider the current product to have the cheapest price by default, and look for
// a cheaper product in its children.
$cheapestPrice = $parent->getCurrencyPrice($currencyId);
foreach ($children as $child) {
$price = $child->getCurrencyPrice($currencyId);
if (!$price) {
continue;
}

if ($price->getGross() < $cheapestPrice->getGross()) {
$cheapestPrice->setGross($price->getGross());
$parent = $child;
}
}

$configuredChildren = $children->filter(static function (ProductEntity $child) use ($parent) {
return $child->getId() !== $parent->getId();
});

$parent->setParentId(null);
$parent->setChildren($configuredChildren);

return $parent;
}
}
12 changes: 12 additions & 0 deletions src/Findologic/MainVariant.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace FINDOLOGIC\FinSearch\Findologic;

final class MainVariant
TheKeymaster marked this conversation as resolved.
Show resolved Hide resolved
{
public const SHOPWARE_DEFAULT = 'default';
public const MAIN_PARENT = 'parent';
public const CHEAPEST = 'cheapest';
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,6 @@
{{ $tc('findologic.settingForm.testButton') }}
</sw-button>
<span class="divider"></span>
<sw-multi-select
v-model="actualConfigData['FinSearch.config.crossSellingCategories']"
:options="categories"
:label="$tc('findologic.settingForm.config.crossSellingCategories.label')"
:helpText="$tc('findologic.settingForm.config.crossSellingCategories.tooltipText')"
:placeholder="$tc('findologic.settingForm.config.crossSellingCategories.placeholder')"
>
<template #selection-label-property="{ item }">
{{ item.name }}
</template>

</sw-multi-select>
<sw-text-field
v-model="actualConfigData['FinSearch.config.integrationType']"
ref="integrationType"
Expand All @@ -58,9 +46,37 @@
{% endblock %}
{% endblock %}
</sw-container>
</sw-card>


<sw-card class="sw-card--grid"
:title="$tc('findologic.settingForm.config.export.title')">
<sw-container>
<div class="findologic-settings-credentials-fields">
<sw-single-select
v-model="actualConfigData['FinSearch.config.mainVariant']"
:options="mainVariantOptions"
:label="$tc('findologic.settingForm.config.mainVariant.label')"
:placeholder="$tc('findologic.settingForm.config.mainVariant.default.label')"
:helpText="$tc('findologic.settingForm.config.mainVariant.tooltipText')">
</sw-single-select>

<sw-multi-select
v-model="actualConfigData['FinSearch.config.crossSellingCategories']"
:options="categories"
:label="$tc('findologic.settingForm.config.crossSellingCategories.label')"
:helpText="$tc('findologic.settingForm.config.crossSellingCategories.tooltipText')"
:placeholder="$tc('findologic.settingForm.config.crossSellingCategories.placeholder')"
>
<template #selection-label-property="{ item }">
{{ item.name }}
</template>
</sw-multi-select>
</div>
</sw-container>
</sw-card>


<sw-card class="sw-card--grid"
v-if="showDIConfig"
:title="$tc('findologic.settingForm.directIntegration.title')">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,23 @@ Component.register('findologic-config', {
}];
},

mainVariantOptions() {
return [
{
label: this.$tc('findologic.settingForm.config.mainVariant.default.label'),
value: 'default'
},
{
label: this.$tc('findologic.settingForm.config.mainVariant.parent.label'),
value: 'parent'
},
{
label: this.$tc('findologic.settingForm.config.mainVariant.cheapest.label'),
value: 'cheapest'
}
];
},

integrationType() {
return this.actualConfigData['FinSearch.config.integrationType'];
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ Component.register('findologic-page', {
if (!values['FinSearch.config.filterPosition']) {
values['FinSearch.config.filterPosition'] = 'top';
}
if (!values['FinSearch.config.mainVariant']) {
values['FinSearch.config.mainVariant'] = 'default';
}

this.actualConfigData = values;
this.isLoading = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@
"left": {
"label": "Links"
}
},
"export": {
"title": "Export"
},
"mainVariant": {
"label": "Exportierte Hauptvariante",
"tooltipText": "Wählen um die Variante, die auf Listing-Seiten angezeigt wird, zu ändern.",
"default": {
"label": "Shopware Standard"
},
"parent": {
"label": "Haupt-/Eltern Produkt"
},
"cheapest": {
"label": "Günstigste Variante"
}
}
},
"titleSuccess": "Erfolgreich",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@
"left": {
"label": "Left"
}
},
"export": {
"title": "Export"
},
"mainVariant": {
"label": "Exported main variant",
"tooltipText": "Select to change the variant that is shown on listing pages.",
"default": {
"label": "Shopware default"
},
"parent": {
"label": "Main-/Parent product"
},
"cheapest": {
"label": "Cheapest variant"
}
}
},
"titleSuccess": "Success",
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/public/administration/js/fin-search.js

Large diffs are not rendered by default.

Loading