Skip to content

Commit

Permalink
Merge branch '2.4-develop-mainline' into 21853
Browse files Browse the repository at this point in the history
  • Loading branch information
engcom-Foxtrot committed Sep 25, 2020
2 parents 873b814 + 5977749 commit 392dbf6
Show file tree
Hide file tree
Showing 49 changed files with 1,518 additions and 213 deletions.
68 changes: 68 additions & 0 deletions .github/stale.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Configuration for probot-stale - https://github.com/probot/stale

# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 76

# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14

# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []

# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- "Priority: P0"
- "Priority: P1"
- "Priority: P2"
- "Progress: dev in progress"
- "Progress: PR in progress"
- "Progress: done"
- "B2B: GraphQL"
- "Progress: PR Created"
- "PAP"
- "Project: Login as Customer"
- "Project: GraphQL"

# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false

# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false

# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false

# Label to use when marking as stale
staleLabel: "stale issue"

# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed after 14 days if no further activity occurs. Thank you
for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.

# Comment to post when closing a stale Issue or Pull Request.
# closeComment: >
# Your comment here.

# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30

# Limit to only `issues` or `pulls`
only: issues

# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.

# issues:
# exemptLabels:
# - confirmed
2 changes: 1 addition & 1 deletion app/code/Magento/AsynchronousOperations/etc/db_schema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<table name="magento_operation" resource="default" engine="innodb" comment="Operation entity">
<column xsi:type="int" name="id" padding="10" unsigned="true" nullable="false" identity="true"
comment="Operation ID"/>
<column xsi:type="int" name="operation_key" padding="10" unsigned="true" nullable="false"
<column xsi:type="int" name="operation_key" padding="10" unsigned="true" nullable="true"
comment="Operation Key"/>
<column xsi:type="varbinary" name="bulk_uuid" nullable="true" length="39" comment="Related Bulk UUID"/>
<column xsi:type="varchar" name="topic_name" nullable="true" length="255"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
class Validate extends AttributeAction implements HttpGetActionInterface, HttpPostActionInterface
{
const DEFAULT_MESSAGE_KEY = 'message';
private const RESERVED_ATTRIBUTE_CODES = ['product_type', 'type_id'];

/**
* @var JsonFactory
Expand Down Expand Up @@ -145,11 +146,16 @@ public function execute()
);
}

if ($attribute->getId() && !$attributeId || $attributeCode === 'product_type' || $attributeCode === 'type_id') {
if (in_array($attributeCode, self::RESERVED_ATTRIBUTE_CODES, true)) {
$message = __('Code (%1) is a reserved key and cannot be used as attribute code.', $attributeCode);
$this->setMessageToResponse($response, [$message]);
$response->setError(true);
}

if ($attribute->getId() && !$attributeId) {
$message = strlen($this->getRequest()->getParam('attribute_code'))
? __('An attribute with this code already exists.')
: __('An attribute with the same code (%1) already exists.', $attributeCode);

$this->setMessageToResponse($response, [$message]);

$response->setError(true);
Expand Down
66 changes: 52 additions & 14 deletions app/code/Magento/Catalog/Pricing/Price/TierPrice.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,27 @@
use Magento\Catalog\Model\Product;
use Magento\Customer\Api\GroupManagementInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Pricing\Adjustment\CalculatorInterface;
use Magento\Framework\Pricing\Amount\AmountInterface;
use Magento\Framework\Pricing\Price\AbstractPrice;
use Magento\Framework\Pricing\Price\BasePriceProviderInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Framework\Pricing\PriceInfoInterface;
use Magento\Customer\Model\Group\RetrieverInterface as CustomerGroupRetrieverInterface;
use Magento\Tax\Model\Config;

/**
* @api
* @since 100.0.2
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class TierPrice extends AbstractPrice implements TierPriceInterface, BasePriceProviderInterface
{
private const XML_PATH_TAX_DISPLAY_TYPE = 'tax/display/type';

/**
* Price type tier
*/
Expand Down Expand Up @@ -62,35 +70,43 @@ class TierPrice extends AbstractPrice implements TierPriceInterface, BasePricePr
*/
private $customerGroupRetriever;

/**
* @var ScopeConfigInterface
*/
private $scopeConfig;

/**
* @param Product $saleableItem
* @param float $quantity
* @param CalculatorInterface $calculator
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
* @param PriceCurrencyInterface $priceCurrency
* @param Session $customerSession
* @param GroupManagementInterface $groupManagement
* @param CustomerGroupRetrieverInterface|null $customerGroupRetriever
* @param ScopeConfigInterface|null $scopeConfig
*/
public function __construct(
Product $saleableItem,
$quantity,
CalculatorInterface $calculator,
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
PriceCurrencyInterface $priceCurrency,
Session $customerSession,
GroupManagementInterface $groupManagement,
CustomerGroupRetrieverInterface $customerGroupRetriever = null
CustomerGroupRetrieverInterface $customerGroupRetriever = null,
?ScopeConfigInterface $scopeConfig = null
) {
$quantity = (float)$quantity ? $quantity : 1;
parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
$this->customerSession = $customerSession;
$this->groupManagement = $groupManagement;
$this->customerGroupRetriever = $customerGroupRetriever
?? \Magento\Framework\App\ObjectManager::getInstance()->get(CustomerGroupRetrieverInterface::class);
?? ObjectManager::getInstance()->get(CustomerGroupRetrieverInterface::class);
if ($saleableItem->hasCustomerGroupId()) {
$this->customerGroup = (int) $saleableItem->getCustomerGroupId();
} else {
$this->customerGroup = (int) $this->customerGroupRetriever->getCustomerGroupId();
}
$this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
}

/**
Expand Down Expand Up @@ -136,6 +152,8 @@ protected function isFirstPriceBetter($firstPrice, $secondPrice)
}

/**
* Returns tier price count
*
* @return int
*/
public function getTierPriceCount()
Expand All @@ -144,6 +162,8 @@ public function getTierPriceCount()
}

/**
* Returns tier price list
*
* @return array
*/
public function getTierPriceList()
Expand All @@ -155,15 +175,32 @@ public function getTierPriceList()
$this->priceList,
function (&$priceData) {
/* convert string value to float */
$priceData['price_qty'] = $priceData['price_qty'] * 1;
$priceData['price_qty'] *= 1;
if ($this->getConfigTaxDisplayType() === Config::DISPLAY_TYPE_BOTH) {
$exclTaxPrice = $this->calculator->getAmount($priceData['price'], $this->product, true);
$priceData['excl_tax_price'] = $exclTaxPrice;
}
$priceData['price'] = $this->applyAdjustment($priceData['price']);
}
);
}

return $this->priceList;
}

/**
* Returns config tax display type
*
* @return int
*/
private function getConfigTaxDisplayType(): int
{
return (int) $this->scopeConfig->getValue(self::XML_PATH_TAX_DISPLAY_TYPE);
}

/**
* Filters tier prices
*
* @param array $priceList
* @return array
*/
Expand Down Expand Up @@ -204,6 +241,8 @@ protected function filterTierPrices(array $priceList)
}

/**
* Returns base price
*
* @return float
*/
protected function getBasePrice()
Expand All @@ -213,25 +252,22 @@ protected function getBasePrice()
}

/**
* Calculates savings percentage according to the given tier price amount
* and related product price amount.
* Calculates savings percentage according to the given tier price amount and related product price amount.
*
* @param AmountInterface $amount
*
* @return float
*/
public function getSavePercent(AmountInterface $amount)
{
$productPriceAmount = $this->priceInfo->getPrice(
FinalPrice::PRICE_CODE
)->getAmount();
$productPriceAmount = $this->priceInfo->getPrice(FinalPrice::PRICE_CODE)
->getAmount();

return round(
100 - ((100 / $productPriceAmount->getValue()) * $amount->getValue())
);
return round(100 - ((100 / $productPriceAmount->getValue()) * $amount->getValue()));
}

/**
* Apply adjustment to price
*
* @param float|string $price
* @return \Magento\Framework\Pricing\Amount\AmountInterface
*/
Expand Down Expand Up @@ -314,6 +350,8 @@ protected function getStoredTierPrices()
}

/**
* Return is percentage discount
*
* @return bool
*/
public function isPercentageDiscount()
Expand Down
14 changes: 14 additions & 0 deletions app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,20 @@
<data key="default_store_label" unique="suffix">Attribute Store label &lt;span&gt; </data>
<data key="frontend_input">text</data>
</entity>
<entity name="ProductTypeIdAttribute" type="ProductAttribute">
<data key="frontend_label">Type id</data>
<data key="attribute_code">type_id</data>
<data key="frontend_input">text</data>
<data key="is_required">No</data>
<data key="is_required_admin">No</data>
</entity>
<entity name="ProductProductTypeAttribute" type="ProductAttribute">
<data key="frontend_label">Product type</data>
<data key="attribute_code">product_type</data>
<data key="frontend_input">text</data>
<data key="is_required">No</data>
<data key="is_required_admin">No</data>
</entity>
<!-- Product attribute from file "export_import_configurable_product.csv" -->
<entity name="ProductAttributeWithTwoOptionsForExportImport" extends="productAttributeDropdownTwoOptions" type="ProductAttribute">
<data key="attribute_code">attribute</data>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="CreateProductAttributeEntityWithReservedKeysTest">
<annotations>
<features value="Catalog"/>
<stories value="Create Product Attributes"/>
<title value="Attributess with reserved codes should not be created"/>
<description value="Admin should not be able to create product attribute with reserved codes"/>
<severity value="MINOR"/>
<testCaseId value="MC-37806"/>
<group value="catalog"/>
</annotations>

<before>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
</before>
<after>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
</after>

<!--Navigate to Stores > Attributes > Product.-->
<amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="goToProductAttributesGrid"/>

<!--Create new Product Attribute as TextField, with type_id code.-->
<actionGroup ref="CreateProductAttributeActionGroup" stepKey="createAttribute">
<argument name="attribute" value="ProductTypeIdAttribute"/>
</actionGroup>
<see stepKey="seeErrorMessage" selector="{{AdminMessagesSection.errorMessage}}" userInput="Code (type_id) is a reserved key and cannot be used as attribute code."/>

<!--Navigate to Stores > Attributes > Product.-->
<amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="backToProductAttributesGrid"/>

<!--Create new Product Attribute as TextField, with product_type code.-->
<actionGroup ref="CreateProductAttributeActionGroup" stepKey="createAttribute2">
<argument name="attribute" value="ProductProductTypeAttribute"/>
</actionGroup>

<see stepKey="seeErrorMessage2" selector="{{AdminMessagesSection.errorMessage}}" userInput="Code (product_type) is a reserved key and cannot be used as attribute code."/>
</test>
</tests>
1 change: 1 addition & 0 deletions app/code/Magento/Catalog/i18n/en_US.csv
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ Catalog,Catalog
"You saved the product attribute.","You saved the product attribute."
"An attribute with this code already exists.","An attribute with this code already exists."
"An attribute with the same code (%1) already exists.","An attribute with the same code (%1) already exists."
"Code (%1) is a reserved key and cannot be used as attribute code.","Code (%1) is a reserved key and cannot be used as attribute code."
"The value of Admin must be unique.","The value of Admin must be unique."
"The value of Admin scope can't be empty.","The value of Admin scope can't be empty."
"You duplicated the product.","You duplicated the product."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ class CategoryUrlRewriteGenerator
*/
private $mergeDataProviderPrototype;

/**
* @var CategoryRepositoryInterface
*/
private $categoryRepository;

/**
* @var bool
*/
Expand Down Expand Up @@ -124,10 +129,11 @@ protected function generateForGlobalScope(
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
$categoryId = $category->getId();
foreach ($category->getStoreIds() as $storeId) {
$category->setStoreId($storeId);
if (!$this->isGlobalScope($storeId)
&& $this->isOverrideUrlsForStore($storeId, $categoryId, $overrideStoreUrls)
) {
$category = clone $category; // prevent undesired side effects on original object
$category->setStoreId($storeId);
$this->updateCategoryUrlForStore($storeId, $category);
$mergeDataProvider->merge($this->generateForSpecificStoreView($storeId, $category, $rootCategoryId));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public function testGenerationForGlobalScope()
],
$this->categoryUrlRewriteGenerator->generate($this->category, false, $categoryId)
);
$this->assertEquals(0, $this->category->getStoreId(), 'Store ID should not have been modified');
}

/**
Expand Down
Loading

0 comments on commit 392dbf6

Please sign in to comment.