Skip to content

Commit 51f6ade

Browse files
committed
Merge pull request #3271 in SW/shopware from sw-14070/5.1/revert-article-notification-tickets to 5.1
* commit '55a08f822f3146fe370b79b684736c7dfae4c4d0': SW-14070 - Reverted out-of-stock variant selection due to problems
2 parents dc9a9ec + 55a08f8 commit 51f6ade

File tree

14 files changed

+170
-21
lines changed

14 files changed

+170
-21
lines changed

UPGRADE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ In this document you will find a changelog of the important changes related to t
1212
* `frontend_index_footer_column_service_menu_headline`
1313
* `frontend_index_footer_column_information_menu_headline`
1414
* `frontend_index_footer_column_newsletter_headline`
15-
* Changed `ProductNumberService::getAvailableNumber()` to ignore the `hideNoInstock` config option
15+
* Removed out-of-stock variant selection due to problems
1616

1717
## 5.1.2
1818
* Out-of-stock variants on the detail page are now selectable

engine/Shopware/Bundle/StoreFrontBundle/Service/Core/ProductNumberService.php

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,35 @@ public function getAvailableNumber($number, ShopContextInterface $context, $sele
104104
return $selected;
105105
}
106106

107-
return $number;
107+
if ($this->isNumberAvailable($number)) {
108+
return $number;
109+
}
110+
111+
$selected = $this->findFallbackById($productId);
112+
if (!$selected) {
113+
throw new \RuntimeException("No active product variant found");
114+
}
115+
116+
return $selected;
117+
}
118+
119+
/**
120+
* @param int $productId
121+
* @return string|false
122+
*/
123+
private function findFallbackById($productId)
124+
{
125+
$selected = $this->getMainVariantNumberById($productId);
126+
if ($selected) {
127+
return $selected;
128+
}
129+
130+
$selected = $this->getAvailableFallbackVariant($productId);
131+
if ($selected) {
132+
return $selected;
133+
}
134+
135+
return $this->getFallbackVariant($productId);
108136
}
109137

110138
/**
@@ -123,7 +151,7 @@ private function getProductIdByNumber($number)
123151

124152
/**@var $statement \PDOStatement*/
125153
$statement = $query->execute();
126-
154+
127155
return $statement->fetch(\PDO::FETCH_COLUMN);
128156
}
129157

@@ -158,17 +186,110 @@ private function getNumberBySelection($productId, array $selection)
158186
$query->setParameter(':' . $alias, (int) $optionId);
159187
}
160188

189+
if ($this->config->get('hideNoInStock')) {
190+
$query->innerJoin('variant', 's_articles', 'product', 'product.id = variant.articleID');
191+
$query->andWhere('(product.laststock * variant.instock) >= (product.laststock * variant.minpurchase)');
192+
}
193+
161194
/**@var $statement \Doctrine\DBAL\Driver\ResultStatement */
162195
$statement = $query->execute();
163196

164197
return $statement->fetch(\PDO::FETCH_COLUMN);
165198
}
166199

200+
/**
201+
* @param string $number
202+
* @return boolean
203+
*/
204+
private function isNumberAvailable($number)
205+
{
206+
$query = $this->getProductNumberQuery();
207+
$query->where('variant.ordernumber = :number')
208+
->andWhere('(product.laststock * variant.instock) >= (product.laststock * variant.minpurchase)')
209+
->setParameter(':number', $number);
210+
211+
$statement = $query->execute();
212+
$selected = $statement->fetch(\PDO::FETCH_COLUMN);
213+
214+
return (bool) $selected;
215+
}
216+
217+
/**
218+
* @param int $productId
219+
* @return string|false
220+
*/
221+
private function getMainVariantNumberById($productId)
222+
{
223+
$query = $this->getProductNumberQuery();
224+
$query->where('variant.id = product.main_detail_id')
225+
->andWhere('product.id = :productId')
226+
->andWhere('(product.laststock * variant.instock) >= (product.laststock * variant.minpurchase)')
227+
->setParameter(':productId', $productId);
228+
229+
$statement = $query->execute();
230+
$selected = $statement->fetch(\PDO::FETCH_COLUMN);
231+
232+
return $selected;
233+
}
234+
235+
/**
236+
* Returns the first active variant number
237+
*
238+
* @param int $productId
239+
* @return string|false
240+
*/
241+
private function getFallbackVariant($productId)
242+
{
243+
$query = $this->getProductNumberQuery();
244+
245+
$query->andWhere('product.id = :productId');
246+
$query->setMaxResults(1);
247+
$query->setParameter(':productId', $productId);
248+
249+
$statement = $query->execute();
250+
$selected = $statement->fetch(\PDO::FETCH_COLUMN);
251+
252+
return $selected;
253+
}
254+
255+
/**
256+
* Returns the first active variant number that is available for purchase
257+
*
258+
* @param int $productId
259+
* @return string|false
260+
*/
261+
private function getAvailableFallbackVariant($productId)
262+
{
263+
$query = $this->getProductNumberQuery();
264+
265+
$query->andWhere('product.id = :productId');
266+
$query->andWhere('(product.laststock * variant.instock) >= (product.laststock * variant.minpurchase)');
267+
$query->setMaxResults(1);
268+
$query->setParameter(':productId', $productId);
269+
270+
$statement = $query->execute();
271+
$selected = $statement->fetch(\PDO::FETCH_COLUMN);
272+
273+
return $selected;
274+
}
275+
276+
/**
277+
* @return \Doctrine\DBAL\Query\QueryBuilder
278+
*/
279+
private function getProductNumberQuery()
280+
{
281+
$query = $this->connection->createQueryBuilder();
282+
$query->select(['variant.ordernumber']);
283+
$query->from('s_articles_details', 'variant');
284+
$query->innerJoin('variant', 's_articles', 'product', 'product.id = variant.articleID AND variant.active = 1');
285+
$query->setMaxResults(1);
286+
return $query;
287+
}
288+
167289
/**
168290
* Validates if the product is available in the current shop
169291
* @param int $productId
170292
* @param Shop $shop
171-
* @return int
172293
*/
173294
private function isProductAvailableInShop($productId, $shop)
174295
{

engine/Shopware/Core/sArticles.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,12 +1205,24 @@ public function sGetArticleById($id = 0, $sCategoryID = null, $number = null, ar
12051205
}
12061206

12071207
$hideNoInstock = $this->config->get('hideNoInstock');
1208-
if ($hideNoInstock && !$product->hasAvailableVariant()) {
1208+
if ($hideNoInstock && !$product->isAvailable()) {
12091209
return [];
12101210
}
12111211

12121212
if ($product->hasConfigurator()) {
1213-
$selection = $product->getSelectedOptions();
1213+
$type = $this->getConfiguratorType($product->getId());
1214+
1215+
/**
1216+
* Check if a variant should be loaded. And load the configuration for the variant for pre selection.
1217+
*
1218+
* Requires the following scenario:
1219+
* 1. $number has to be set (without a number we can't load a configuration)
1220+
* 2. $number is equals to $productNumber (if the order number is invalid or inactive fallback to main variant)
1221+
* 3. $configuration is empty (Customer hasn't not set an own configuration)
1222+
*/
1223+
if ($providedNumber && $providedNumber == $productNumber && empty($configuration) || $type === 0) {
1224+
$selection = $product->getSelectedOptions();
1225+
}
12141226
}
12151227

12161228
$categoryId = (int) $sCategoryID;

templates/_emotion/frontend/_resources/styles/emotion.css

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3816,17 +3816,24 @@ body #content .banner-slider-emotion .ajaxSlider .slide_navigation {
38163816
color: #333333;
38173817
border-color: #333333;
38183818
}
3819+
#buybox .configurator--variant .option--input:hover ~ label.is--disabled {
3820+
color: #999999;
3821+
border-color: #DFDFDF;
3822+
}
38193823
#buybox .configurator--variant .option--input:checked ~ label {
38203824
color: #E1540F;
38213825
border-color: #E1540F;
38223826
}
3823-
#buybox .configurator--variant .option--input.is--disabled ~ label {
3827+
#buybox .configurator--variant .option--input:disabled ~ label {
38243828
-khtml-opacity: 0.5;
38253829
-moz-opacity: 0.5;
38263830
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
38273831
filter: alpha(opacity = 50);
38283832
opacity: 0.5;
38293833
}
3834+
#buybox .configurator--variant .option--input:disabled {
3835+
cursor: default;
3836+
}
38303837
#buybox .configurator--variant .option--label {
38313838
display: block;
38323839
height: 57px;

templates/_emotion/frontend/detail/config_step.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
{/if}
3030

3131
{foreach from=$sConfigurator.values item=configValue name=option key=optionID}
32-
<option {if $configValue.selected && $sConfigurator.user_selected} selected="selected"{/if} value="{$configValue.optionID}">
32+
<option {if !$configValue.selectable}disabled{/if} {if $configValue.selected && $sConfigurator.user_selected} selected="selected"{/if} value="{$configValue.optionID}">
3333
{$configValue.optionname}{if $configValue.upprice && !$configValue.reset} {if $configValue.upprice > 0}{/if}{/if}
3434
{if !$configValue.selectable}{s name="DetailConfigValueNotAvailable"}{/s}{/if}
3535
</option>

templates/_emotion/frontend/detail/config_variant.tpl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,13 @@
2222

2323
{block name='frontend_detail_configurator_variant_group_option_input'}
2424
<input type="radio"
25-
class="option--input{if !$option.selectable} is--disabled{/if}"
25+
class="option--input"
2626
id="group[{$option.groupID}]"
2727
name="group[{$option.groupID}]"
2828
value="{$option.optionID}"
2929
data-auto-submit="true"
30-
{if $option.selected}checked="checked"{/if} />
30+
{if !$option.selectable}disabled="disabled"{/if}
31+
{if $option.selected && $option.selectable}checked="checked"{/if} />
3132
{/block}
3233

3334
{block name='frontend_detail_configurator_variant_group_option_label'}

templates/_emotion/frontend/detail/index.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393

9494
{* Article notification *}
9595
{block name="frontend_detail_index_notification"}
96-
{if $sArticle.laststock && $sArticle.notification && ($sArticle.instock <= 0 || $sArticle.sVariants) && $ShowNotification}
96+
{if $sArticle.notification && ($sArticle.instock <= 0 || $sArticle.sVariants) && $ShowNotification}
9797
{include file="frontend/plugins/notification/index.tpl"}
9898
{/if}
9999
{/block}

tests/Mink/features/bootstrap/ShopwareContext.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public function iConfirmTheLinkInTheEmail($limit = 1)
159159
switch ($args['action']) {
160160
//Artikel-Benachrichtigungen
161161
case 'notify':
162-
$mask = '%s&action=notifyConfirm&sNotificationConfirmation=%s&sNotify=1';
162+
$mask = '%sConfirm&sNotificationConfirmation=%s&sNotify=1';
163163
break;
164164

165165
//Artikel-Bewertungen

themes/Frontend/Bare/frontend/detail/buy.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
{if (!isset($sArticle.active) || $sArticle.active)}
5252
{if $sArticle.isAvailable}
5353
{block name="frontend_detail_buy_button_container"}
54-
<div class="buybox--button-container block-group{if $NotifyHideBasket && $sArticle.notification && $sArticle.laststock && $sArticle.instock <= 0} is--hidden{/if}">
54+
<div class="buybox--button-container block-group{if $NotifyHideBasket && $sArticle.notification && $sArticle.instock <= 0} is--hidden{/if}">
5555

5656
{* Quantity selection *}
5757
{block name='frontend_detail_buy_quantity'}

themes/Frontend/Bare/frontend/detail/config_step.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
{/if}
3333

3434
{foreach from=$sConfigurator.values item=configValue name=option key=optionID}
35-
<option {if $configValue.selected && $sConfigurator.user_selected} selected="selected"{/if} value="{$configValue.optionID}">
35+
<option {if !$configValue.selectable}disabled{/if} {if $configValue.selected && $sConfigurator.user_selected} selected="selected"{/if} value="{$configValue.optionID}">
3636
{$configValue.optionname}{if $configValue.upprice && !$configValue.reset} {if $configValue.upprice > 0}{/if}{/if}
3737
{if !$configValue.selectable}{s name="DetailConfigValueNotAvailable"}{/s}{/if}
3838
</option>

0 commit comments

Comments
 (0)