-
+
currentDirRead = $readFactory->create(getcwd());
$this->fileWriteFactory = $fileWriteFactory;
+ $this->domDocumentFactory = $domDocumentFactory ?: ObjectManager::getInstance()->get(DomDocumentFactory::class);
}
/**
@@ -57,26 +66,21 @@ public function generateCatalog(array $dictionary, $configFilePath)
\Magento\Framework\Filesystem\DriverPool::FILE,
'r'
);
- $dom = new \DOMDocument();
- $dom->loadXML($file->readAll());
+ $dom = $this->domDocumentFactory->create();
+ $fileContent = $file->readAll();
+ if (!empty($fileContent)) {
+ $dom->loadXML($fileContent);
+ } else {
+ $this->initEmptyFile($dom);
+ }
$xpath = new \DOMXPath($dom);
$nodeList = $xpath->query('/project');
$projectNode = $nodeList->item(0);
$file->close();
} catch (FileSystemException $f) {
//create file if does not exists
- $dom = new \DOMDocument();
- $projectNode = $dom->createElement('project');
-
- //PhpStorm 9 version for component is "4"
- $projectNode->setAttribute('version', '4');
- $dom->appendChild($projectNode);
- $rootComponentNode = $dom->createElement('component');
-
- //PhpStorm 9 version for ProjectRootManager is "2"
- $rootComponentNode->setAttribute('version', '2');
- $rootComponentNode->setAttribute('name', 'ProjectRootManager');
- $projectNode->appendChild($rootComponentNode);
+ $dom = $this->domDocumentFactory->create();
+ $projectNode = $this->initEmptyFile($dom);
}
$xpath = new \DOMXPath($dom);
@@ -103,4 +107,26 @@ public function generateCatalog(array $dictionary, $configFilePath)
$file->write($dom->saveXML());
$file->close();
}
+
+ /**
+ * Setup basic empty dom elements
+ *
+ * @param \DOMDocument $dom
+ * @return \DOMElement
+ */
+ private function initEmptyFile(\DOMDocument $dom)
+ {
+ $projectNode = $dom->createElement('project');
+
+ //PhpStorm 9 version for component is "4"
+ $projectNode->setAttribute('version', '4');
+ $dom->appendChild($projectNode);
+ $rootComponentNode = $dom->createElement('component');
+
+ //PhpStorm 9 version for ProjectRootManager is "2"
+ $rootComponentNode->setAttribute('version', '2');
+ $rootComponentNode->setAttribute('name', 'ProjectRootManager');
+ $projectNode->appendChild($rootComponentNode);
+ return $projectNode;
+ }
}
diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php
index 45a97e2287827..9a26efee744d5 100644
--- a/app/code/Magento/Dhl/Model/Carrier.php
+++ b/app/code/Magento/Dhl/Model/Carrier.php
@@ -606,7 +606,7 @@ public function getDhlProducts($doc)
'L' => __('Express 10:30'),
'G' => __('Domestic economy select'),
'W' => __('Economy select'),
- 'I' => __('Break bulk economy'),
+ 'I' => __('Domestic express 9:00'),
'N' => __('Domestic express'),
'O' => __('Others'),
'R' => __('Globalmail business'),
@@ -616,7 +616,7 @@ public function getDhlProducts($doc)
];
$nonDocType = [
- '1' => __('Customer services'),
+ '1' => __('Domestic express 12:00'),
'3' => __('Easy shop'),
'4' => __('Jetline'),
'8' => __('Express easy'),
diff --git a/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php
index 0f0d784813dfc..8738d3bb8dae2 100644
--- a/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php
+++ b/app/code/Magento/Dhl/Test/Unit/Model/CarrierTest.php
@@ -447,4 +447,67 @@ public function requestToShipmentDataProvider()
]
];
}
+
+ /**
+ * @dataProvider dhlProductsDataProvider
+ *
+ * @param string $docType
+ * @param array $products
+ */
+ public function testGetDhlProducts(string $docType, array $products)
+ {
+ $this->assertEquals($products, $this->model->getDhlProducts($docType));
+ }
+
+ /**
+ * @return array
+ */
+ public function dhlProductsDataProvider() : array
+ {
+ return [
+ 'doc' => [
+ 'docType' => \Magento\Dhl\Model\Carrier::DHL_CONTENT_TYPE_DOC,
+ 'products' => [
+ '2' => 'Easy shop',
+ '5' => 'Sprintline',
+ '6' => 'Secureline',
+ '7' => 'Express easy',
+ '9' => 'Europack',
+ 'B' => 'Break bulk express',
+ 'C' => 'Medical express',
+ 'D' => 'Express worldwide',
+ 'U' => 'Express worldwide',
+ 'K' => 'Express 9:00',
+ 'L' => 'Express 10:30',
+ 'G' => 'Domestic economy select',
+ 'W' => 'Economy select',
+ 'I' => 'Domestic express 9:00',
+ 'N' => 'Domestic express',
+ 'O' => 'Others',
+ 'R' => 'Globalmail business',
+ 'S' => 'Same day',
+ 'T' => 'Express 12:00',
+ 'X' => 'Express envelope',
+ ]
+ ],
+ 'non-doc' => [
+ 'docType' => \Magento\Dhl\Model\Carrier::DHL_CONTENT_TYPE_NON_DOC,
+ 'products' => [
+ '1' => 'Domestic express 12:00',
+ '3' => 'Easy shop',
+ '4' => 'Jetline',
+ '8' => 'Express easy',
+ 'P' => 'Express worldwide',
+ 'Q' => 'Medical express',
+ 'E' => 'Express 9:00',
+ 'F' => 'Freight worldwide',
+ 'H' => 'Economy select',
+ 'J' => 'Jumbo box',
+ 'M' => 'Express 10:30',
+ 'V' => 'Europack',
+ 'Y' => 'Express 12:00',
+ ]
+ ]
+ ];
+ }
}
diff --git a/app/code/Magento/Dhl/i18n/en_US.csv b/app/code/Magento/Dhl/i18n/en_US.csv
index 90ec8b5f17a22..a5532c2cea963 100644
--- a/app/code/Magento/Dhl/i18n/en_US.csv
+++ b/app/code/Magento/Dhl/i18n/en_US.csv
@@ -23,14 +23,12 @@ Europack,Europack
"Express 10:30","Express 10:30"
"Domestic economy select","Domestic economy select"
"Economy select","Economy select"
-"Break bulk economy","Break bulk economy"
"Domestic express","Domestic express"
Others,Others
"Globalmail business","Globalmail business"
"Same day","Same day"
"Express 12:00","Express 12:00"
"Express envelope","Express envelope"
-"Customer services","Customer services"
Jetline,Jetline
"Freight worldwide","Freight worldwide"
"Jumbo box","Jumbo box"
@@ -81,3 +79,5 @@ Size,Size
"Show Method if Not Applicable","Show Method if Not Applicable"
"Sort Order","Sort Order"
Debug,Debug
+"Domestic express 9:00","Domestic express 9:00"
+"Domestic express 12:00","Domestic express 12:00"
diff --git a/app/code/Magento/Directory/Model/PriceCurrency.php b/app/code/Magento/Directory/Model/PriceCurrency.php
index a211242d377f3..07d2e60d61335 100644
--- a/app/code/Magento/Directory/Model/PriceCurrency.php
+++ b/app/code/Magento/Directory/Model/PriceCurrency.php
@@ -77,8 +77,7 @@ public function format(
$scope = null,
$currency = null
) {
- return $this->getCurrency($scope, $currency)
- ->formatPrecision($amount, $precision, [], $includeContainer);
+ return $this->createCurrency($scope, $currency)->formatPrecision($amount, $precision, [], $includeContainer);
}
/**
@@ -101,20 +100,7 @@ public function convertAndFormat(
*/
public function getCurrency($scope = null, $currency = null)
{
- if ($currency instanceof Currency) {
- $currentCurrency = $currency;
- } elseif (is_string($currency)) {
- $currency = $this->currencyFactory->create()
- ->load($currency);
- $baseCurrency = $this->getStore($scope)
- ->getBaseCurrency();
- $currentCurrency = $baseCurrency->getRate($currency) ? $currency : $baseCurrency;
- } else {
- $currentCurrency = $this->getStore($scope)
- ->getCurrentCurrency();
- }
-
- return $currentCurrency;
+ return $this->createCurrency($scope, $currency, true);
}
/**
@@ -157,4 +143,30 @@ public function round($price)
{
return round($price, 2);
}
+
+ /**
+ * Get currency considering currency rate configuration.
+ *
+ * @param null|string|bool|int|\Magento\Framework\App\ScopeInterface $scope
+ * @param \Magento\Framework\Model\AbstractModel|string|null $currency
+ * @param bool $includeRate
+ *
+ * @return Currency
+ */
+ private function createCurrency($scope, $currency, bool $includeRate = false)
+ {
+ if ($currency instanceof Currency) {
+ $currentCurrency = $currency;
+ } elseif (is_string($currency)) {
+ $currentCurrency = $this->currencyFactory->create()->load($currency);
+ if ($includeRate) {
+ $baseCurrency = $this->getStore($scope)->getBaseCurrency();
+ $currentCurrency = $baseCurrency->getRate($currentCurrency) ? $currentCurrency : $baseCurrency;
+ }
+ } else {
+ $currentCurrency = $this->getStore($scope)->getCurrentCurrency();
+ }
+
+ return $currentCurrency;
+ }
}
diff --git a/app/code/Magento/Directory/Setup/UpgradeData.php b/app/code/Magento/Directory/Setup/UpgradeData.php
index aa0f81a32fff0..4ee9ea33673d7 100644
--- a/app/code/Magento/Directory/Setup/UpgradeData.php
+++ b/app/code/Magento/Directory/Setup/UpgradeData.php
@@ -41,23 +41,21 @@ public function __construct(Data $directoryData)
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
if (version_compare($context->getVersion(), '2.0.1', '<')) {
- $this->addCroatia($setup);
+ $this->addCountryRegions($setup, $this->getDataForCroatia());
+ }
+ if (version_compare($context->getVersion(), '2.0.2', '<')) {
+ $this->addCountryRegions($setup, $this->getDataForIndia());
}
}
/**
- * Add Croatia and it's states to appropriate tables.
+ * Croatian states data.
*
- * @param ModuleDataSetupInterface $setup
- * @return void
+ * @return array
*/
- private function addCroatia($setup)
+ private function getDataForCroatia()
{
- /**
- * Fill table directory/country_region
- * Fill table directory/country_region_name for en_US locale
- */
- $data = [
+ return [
['HR', 'HR-01', 'Zagrebačka županija'],
['HR', 'HR-02', 'Krapinsko-zagorska županija'],
['HR', 'HR-03', 'Sisačko-moslavačka županija'],
@@ -80,6 +78,68 @@ private function addCroatia($setup)
['HR', 'HR-20', 'Međimurska županija'],
['HR', 'HR-21', 'Grad Zagreb']
];
+ }
+
+ /**
+ * Indian states data.
+ *
+ * @return array
+ */
+ private function getDataForIndia()
+ {
+ return [
+ ['IN', 'AN', 'Andaman and Nicobar Islands'],
+ ['IN', 'AP', 'Andhra Pradesh'],
+ ['IN', 'AR', 'Arunachal Pradesh'],
+ ['IN', 'AS', 'Assam'],
+ ['IN', 'BR', 'Bihar'],
+ ['IN', 'CH', 'Chandigarh'],
+ ['IN', 'CT', 'Chhattisgarh'],
+ ['IN', 'DN', 'Dadra and Nagar Haveli'],
+ ['IN', 'DD', 'Daman and Diu'],
+ ['IN', 'DL', 'Delhi'],
+ ['IN', 'GA', 'Goa'],
+ ['IN', 'GJ', 'Gujarat'],
+ ['IN', 'HR', 'Haryana'],
+ ['IN', 'HP', 'Himachal Pradesh'],
+ ['IN', 'JK', 'Jammu and Kashmir'],
+ ['IN', 'JH', 'Jharkhand'],
+ ['IN', 'KA', 'Karnataka'],
+ ['IN', 'KL', 'Kerala'],
+ ['IN', 'LD', 'Lakshadweep'],
+ ['IN', 'MP', 'Madhya Pradesh'],
+ ['IN', 'MH', 'Maharashtra'],
+ ['IN', 'MN', 'Manipur'],
+ ['IN', 'ML', 'Meghalaya'],
+ ['IN', 'MZ', 'Mizoram'],
+ ['IN', 'NL', 'Nagaland'],
+ ['IN', 'OR', 'Odisha'],
+ ['IN', 'PY', 'Puducherry'],
+ ['IN', 'PB', 'Punjab'],
+ ['IN', 'RJ', 'Rajasthan'],
+ ['IN', 'SK', 'Sikkim'],
+ ['IN', 'TN', 'Tamil Nadu'],
+ ['IN', 'TG', 'Telangana'],
+ ['IN', 'TR', 'Tripura'],
+ ['IN', 'UP', 'Uttar Pradesh'],
+ ['IN', 'UT', 'Uttarakhand'],
+ ['IN', 'WB', 'West Bengal']
+ ];
+ }
+
+ /**
+ * Add country regions data to appropriate tables.
+ *
+ * @param ModuleDataSetupInterface $setup
+ * @param array $data
+ * @return void
+ */
+ private function addCountryRegions(ModuleDataSetupInterface $setup, array $data)
+ {
+ /**
+ * Fill table directory/country_region
+ * Fill table directory/country_region_name for en_US locale
+ */
foreach ($data as $row) {
$bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]];
$setup->getConnection()->insert($setup->getTable('directory_country_region'), $bind);
diff --git a/app/code/Magento/Directory/composer.json b/app/code/Magento/Directory/composer.json
index 6d29f3f9ba6db..5a3eb1932411b 100644
--- a/app/code/Magento/Directory/composer.json
+++ b/app/code/Magento/Directory/composer.json
@@ -10,7 +10,7 @@
"lib-libxml": "*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Directory/etc/module.xml b/app/code/Magento/Directory/etc/module.xml
index 2711a91577a9a..a3735ca6ddde1 100644
--- a/app/code/Magento/Directory/etc/module.xml
+++ b/app/code/Magento/Directory/etc/module.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json
index 8d06be0e4116d..160a51c83627f 100644
--- a/app/code/Magento/Downloadable/composer.json
+++ b/app/code/Magento/Downloadable/composer.json
@@ -25,7 +25,7 @@
"magento/module-downloadable-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Eav/Model/Attribute/GroupRepository.php b/app/code/Magento/Eav/Model/Attribute/GroupRepository.php
index 9d0fa78668382..0714f8efac88c 100644
--- a/app/code/Magento/Eav/Model/Attribute/GroupRepository.php
+++ b/app/code/Magento/Eav/Model/Attribute/GroupRepository.php
@@ -117,16 +117,6 @@ public function save(\Magento\Eav\Api\Data\AttributeGroupInterface $group)
*/
public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria)
{
- $attributeSetId = $this->retrieveAttributeSetIdFromSearchCriteria($searchCriteria);
- if (!$attributeSetId) {
- throw InputException::requiredField('attribute_set_id');
- }
- try {
- $this->setRepository->get($attributeSetId);
- } catch (\Exception $exception) {
- throw NoSuchEntityException::singleField('attributeSetId', $attributeSetId);
- }
-
/** @var \Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\Collection $collection */
$collection = $this->groupListFactory->create();
$this->joinProcessor->process($collection);
@@ -188,6 +178,7 @@ public function deleteById($groupId)
/**
* @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
* @return null|string
+ * @deprecated
*/
protected function retrieveAttributeSetIdFromSearchCriteria(
\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria
diff --git a/app/code/Magento/Eav/Model/Config.php b/app/code/Magento/Eav/Model/Config.php
index cc68709cd3b03..0eecca21b0d54 100644
--- a/app/code/Magento/Eav/Model/Config.php
+++ b/app/code/Magento/Eav/Model/Config.php
@@ -503,6 +503,7 @@ public function getAttribute($entityType, $code)
}
if (isset($this->attributes[$entityTypeCode][$code])) {
+ \Magento\Framework\Profiler::stop('EAV: ' . __METHOD__);
return $this->attributes[$entityTypeCode][$code];
}
diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
index 0c74b84457d40..b0d186705026f 100644
--- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
+++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
@@ -13,6 +13,7 @@
use Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend;
use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;
use Magento\Framework\App\Config\Element;
+use Magento\Framework\DataObject;
use Magento\Framework\DB\Adapter\DuplicateException;
use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\LocalizedException;
@@ -62,6 +63,13 @@ abstract class AbstractEntity extends AbstractResource implements EntityInterfac
*/
protected $_attributesByCode = [];
+ /**
+ * Attributes stored by scope (store id and attribute set id).
+ *
+ * @var array
+ */
+ private $attributesByScope = [];
+
/**
* Two-dimensional array by table name and attribute name
*
@@ -473,6 +481,46 @@ public function addAttribute(AbstractAttribute $attribute)
return $this;
}
+ /**
+ * Adding attribute to entity by scope.
+ *
+ * @param AbstractAttribute $attribute
+ * @param DataObject|null $entity
+ * @return $this
+ */
+ public function addAttributeByScope(AbstractAttribute $attribute, $entity = null)
+ {
+ $suffix = $entity !== null ? $this->getAttributesCacheSuffix($entity) : '0-0';
+ $attributeCode = $attribute->getAttributeCode();
+ $this->attributesByScope[$suffix][$attributeCode] = $attribute;
+ return $this->addAttribute($attribute);
+ }
+
+ /**
+ * Get attributes by scope
+ *
+ * @return array
+ */
+ private function getAttributesByScope($suffix)
+ {
+ return !empty($this->attributesByScope[$suffix])
+ ? $this->attributesByScope[$suffix]
+ : $this->getAttributesByCode();
+ }
+
+ /**
+ * Get attributes cache suffix.
+ *
+ * @param DataObject $object
+ * @return string
+ */
+ private function getAttributesCacheSuffix(DataObject $object)
+ {
+ $attributeSetId = $object->getAttributeSetId() ?: 0;
+ $storeId = $object->getStoreId() ?: 0;
+ return $storeId . '-' . $attributeSetId;
+ }
+
/**
* Retrieve partial load flag
*
@@ -506,7 +554,7 @@ public function isPartialSave($flag = null)
/**
* Retrieve configuration for all attributes
*
- * @param null|\Magento\Framework\DataObject $object
+ * @param null|DataObject $object
* @return $this
*/
public function loadAllAttributes($object = null)
@@ -566,7 +614,7 @@ public function attributesCompare($firstAttribute, $secondAttribute)
/**
* Check whether the attribute is Applicable to the object
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param AbstractAttribute $attribute
* @return bool
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
@@ -611,7 +659,8 @@ public function walkAttributes($partMethod, array $args = [], $collectExceptionM
break;
}
$results = [];
- foreach ($this->getAttributesByCode() as $attrCode => $attribute) {
+ $suffix = $this->getAttributesCacheSuffix($args[0]);
+ foreach ($this->getAttributesByScope($suffix) as $attrCode => $attribute) {
if (isset($args[0]) && is_object($args[0]) && !$this->_isApplicableAttribute($args[0], $attribute)) {
continue;
}
@@ -830,7 +879,7 @@ public function isAttributeStatic($attribute)
/**
* Validate all object's attributes against configuration
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @throws \Magento\Eav\Model\Entity\Attribute\Exception
* @return true|array
*/
@@ -856,10 +905,10 @@ public function validate($object)
/**
* Set new increment id to object
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- public function setNewIncrementId(\Magento\Framework\DataObject $object)
+ public function setNewIncrementId(DataObject $object)
{
if ($object->getIncrementId()) {
return $this;
@@ -878,7 +927,7 @@ public function setNewIncrementId(\Magento\Framework\DataObject $object)
* Check attribute unique value
*
* @param AbstractAttribute $attribute
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return bool
*/
public function checkAttributeUniqueValue(AbstractAttribute $attribute, $object)
@@ -1051,7 +1100,7 @@ protected function _prepareLoadSelect(array $selects)
/**
* Retrieve select object for loading base entity row
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param string|int $rowId
* @return \Magento\Framework\DB\Select
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
@@ -1071,7 +1120,7 @@ protected function _getLoadRowSelect($object, $rowId)
/**
* Retrieve select object for loading entity attributes values
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param string $table
* @return \Magento\Framework\DB\Select
*/
@@ -1091,7 +1140,7 @@ protected function _getLoadAttributesSelect($object, $table)
/**
* Initialize attribute value for object
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param array $valueRow
* @return $this
*/
@@ -1181,8 +1230,8 @@ protected function processSave($object)
/**
* Retrieve Object instance with original data
*
- * @param \Magento\Framework\DataObject $object
- * @return \Magento\Framework\DataObject
+ * @param DataObject $object
+ * @return DataObject
*/
protected function _getOrigObject($object)
{
@@ -1422,7 +1471,7 @@ protected function _processSaveData($saveData)
/**
* Process base row
*/
- $entityObject = new \Magento\Framework\DataObject($entityRow);
+ $entityObject = new DataObject($entityRow);
$entityRow = $this->_prepareDataForTable($entityObject, $entityTable);
if ($insertEntity) {
if (!empty($entityId)) {
@@ -1477,7 +1526,7 @@ protected function _processSaveData($saveData)
/**
* Insert entity attribute value
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param AbstractAttribute $attribute
* @param mixed $value
* @return $this
@@ -1490,7 +1539,7 @@ protected function _insertAttribute($object, $attribute, $value)
/**
* Update entity attribute value
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param AbstractAttribute $attribute
* @param mixed $valueId
* @param mixed $value
@@ -1585,10 +1634,10 @@ protected function _prepareValueForSave($value, AbstractAttribute $attribute)
/**
* Delete entity attribute values
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param string $table
* @param array $info
- * @return \Magento\Framework\DataObject
+ * @return DataObject
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function _deleteAttributes($object, $table, $info)
@@ -1614,13 +1663,13 @@ protected function _deleteAttributes($object, $table, $info)
/**
* Save attribute
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @param string $attributeCode
* @return $this
* @throws \Exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
- public function saveAttribute(\Magento\Framework\DataObject $object, $attributeCode)
+ public function saveAttribute(DataObject $object, $attributeCode)
{
$attribute = $this->getAttribute($attributeCode);
$backend = $attribute->getBackend();
@@ -1666,8 +1715,8 @@ public function saveAttribute(\Magento\Framework\DataObject $object, $attributeC
/**
* Return attribute row to prepare where statement
*
- * @param \Magento\Framework\DataObject $entity
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $entity
+ * @param DataObject $object
* @param \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute
* @return array
*/
@@ -1688,7 +1737,7 @@ protected function getAttributeRow($entity, $object, $attribute)
/**
* Delete entity using current object's data
*
- * @param \Magento\Framework\DataObject|int|string $object
+ * @param DataObject|int|string $object
* @return $this
* @throws \Exception
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
@@ -1730,7 +1779,7 @@ public function delete($object)
/**
* Evaluate Delete operations
*
- * @param \Magento\Framework\DataObject|int|string $object
+ * @param DataObject|int|string $object
* @param string|int $id
* @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
* @return void
@@ -1764,10 +1813,10 @@ protected function evaluateDelete($object, $id, $connection)
/**
* After Load Entity process
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- protected function _afterLoad(\Magento\Framework\DataObject $object)
+ protected function _afterLoad(DataObject $object)
{
\Magento\Framework\Profiler::start('after_load');
$this->walkAttributes('backend/afterLoad', [$object]);
@@ -1778,10 +1827,10 @@ protected function _afterLoad(\Magento\Framework\DataObject $object)
/**
* Before delete Entity process
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- protected function _beforeSave(\Magento\Framework\DataObject $object)
+ protected function _beforeSave(DataObject $object)
{
$this->walkAttributes('backend/beforeSave', [$object]);
return $this;
@@ -1790,10 +1839,10 @@ protected function _beforeSave(\Magento\Framework\DataObject $object)
/**
* After Save Entity process
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- protected function _afterSave(\Magento\Framework\DataObject $object)
+ protected function _afterSave(DataObject $object)
{
$this->walkAttributes('backend/afterSave', [$object]);
return $this;
@@ -1802,10 +1851,10 @@ protected function _afterSave(\Magento\Framework\DataObject $object)
/**
* Before Delete Entity process
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- protected function _beforeDelete(\Magento\Framework\DataObject $object)
+ protected function _beforeDelete(DataObject $object)
{
$this->walkAttributes('backend/beforeDelete', [$object]);
return $this;
@@ -1814,10 +1863,10 @@ protected function _beforeDelete(\Magento\Framework\DataObject $object)
/**
* After delete entity process
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @return $this
*/
- protected function _afterDelete(\Magento\Framework\DataObject $object)
+ protected function _afterDelete(DataObject $object)
{
$this->walkAttributes('backend/afterDelete', [$object]);
return $this;
@@ -1887,10 +1936,10 @@ protected function getAttributeLoader()
/**
* Perform actions after entity load
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @since 100.1.0
*/
- public function afterLoad(\Magento\Framework\DataObject $object)
+ public function afterLoad(DataObject $object)
{
$this->_afterLoad($object);
}
@@ -1898,10 +1947,10 @@ public function afterLoad(\Magento\Framework\DataObject $object)
/**
* Perform actions before entity save
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @since 100.1.0
*/
- public function beforeSave(\Magento\Framework\DataObject $object)
+ public function beforeSave(DataObject $object)
{
$this->_beforeSave($object);
}
@@ -1909,10 +1958,10 @@ public function beforeSave(\Magento\Framework\DataObject $object)
/**
* Perform actions after entity save
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @since 100.1.0
*/
- public function afterSave(\Magento\Framework\DataObject $object)
+ public function afterSave(DataObject $object)
{
$this->_afterSave($object);
}
@@ -1920,10 +1969,10 @@ public function afterSave(\Magento\Framework\DataObject $object)
/**
* Perform actions before entity delete
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @since 100.1.0
*/
- public function beforeDelete(\Magento\Framework\DataObject $object)
+ public function beforeDelete(DataObject $object)
{
$this->_beforeDelete($object);
}
@@ -1931,10 +1980,10 @@ public function beforeDelete(\Magento\Framework\DataObject $object)
/**
* Perform actions after entity delete
*
- * @param \Magento\Framework\DataObject $object
+ * @param DataObject $object
* @since 100.1.0
*/
- public function afterDelete(\Magento\Framework\DataObject $object)
+ public function afterDelete(DataObject $object)
{
$this->_afterDelete($object);
}
diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php
index a925f8e78ff33..bb452ad54ac84 100644
--- a/app/code/Magento/Eav/Model/Entity/AttributeLoader.php
+++ b/app/code/Magento/Eav/Model/Entity/AttributeLoader.php
@@ -51,13 +51,13 @@ public function __construct(
* Retrieve configuration for all attributes
*
* @param AbstractEntity $resource
- * @param DataObject|null $object
+ * @param DataObject|null $entity
* @return AbstractEntity
* @throws LocalizedException
*/
- public function loadAllAttributes(AbstractEntity $resource, DataObject $object = null)
+ public function loadAllAttributes(AbstractEntity $resource, DataObject $entity = null)
{
- $attributes = $this->config->getEntityAttributes($resource->getEntityType(), $object);
+ $attributes = $this->config->getEntityAttributes($resource->getEntityType(), $entity);
$attributeCodes = array_keys($attributes);
/**
* Check and init default attributes
@@ -67,10 +67,10 @@ public function loadAllAttributes(AbstractEntity $resource, DataObject $object =
$resource->unsetAttributes();
foreach ($defaultAttributesCodes as $attributeCode) {
- $resource->addAttribute($this->_getDefaultAttribute($resource, $attributeCode));
+ $resource->addAttributeByScope($this->_getDefaultAttribute($resource, $attributeCode), $entity);
}
foreach ($attributes as $attributeCode => $attribute) {
- $resource->addAttribute($attribute);
+ $resource->addAttributeByScope($attribute, $entity);
}
return $resource;
}
diff --git a/app/code/Magento/Eav/Model/Entity/AttributeLoaderInterface.php b/app/code/Magento/Eav/Model/Entity/AttributeLoaderInterface.php
index f3f8745fc535b..2440492070c66 100644
--- a/app/code/Magento/Eav/Model/Entity/AttributeLoaderInterface.php
+++ b/app/code/Magento/Eav/Model/Entity/AttributeLoaderInterface.php
@@ -17,8 +17,8 @@ interface AttributeLoaderInterface
* Retrieve configuration for all attributes
*
* @param AbstractEntity $resource
- * @param DataObject|null $object
+ * @param DataObject|null $entity
* @return AbstractEntity
*/
- public function loadAllAttributes(AbstractEntity $resource, DataObject $object = null);
+ public function loadAllAttributes(AbstractEntity $resource, DataObject $entity = null);
}
diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
index bd3fd17393d7c..f623cfc8c7b37 100644
--- a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
+++ b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
@@ -920,6 +920,7 @@ public function load($printQuery = false, $logQuery = false)
foreach ($this->_items as $item) {
$item->setOrigData();
$this->beforeAddLoadedItem($item);
+ $item->setDataChanges(false);
}
\Magento\Framework\Profiler::stop('set_orig_data');
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Attribute/GroupRepositoryTest.php b/app/code/Magento/Eav/Test/Unit/Model/Attribute/GroupRepositoryTest.php
index c07122e049a74..9b0f9704887bb 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Attribute/GroupRepositoryTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Attribute/GroupRepositoryTest.php
@@ -266,8 +266,6 @@ public function testSaveThrowExceptionIfProvidedGroupDoesNotExist()
*/
public function testGetList()
{
- $attributeSetId = 'filter';
-
$filterInterfaceMock = $this->getMockBuilder(\Magento\Framework\Api\Search\FilterGroup::class)
->disableOriginalConstructor()
->setMethods([
@@ -275,24 +273,18 @@ public function testGetList()
'getValue',
])
->getMock();
- $filterInterfaceMock->expects($this->once())
- ->method('getField')
- ->willReturn('attribute_set_id');
- $filterInterfaceMock->expects($this->once())
- ->method('getValue')
- ->willReturn($attributeSetId);
$filterGroupMock = $this->getMockBuilder(\Magento\Framework\Api\Search\FilterGroup::class)
->disableOriginalConstructor()
->getMock();
- $filterGroupMock->expects($this->once())
+ $filterGroupMock->expects($this->any())
->method('getFilters')
->willReturn([$filterInterfaceMock]);
$searchCriteriaMock = $this->getMockBuilder(\Magento\Framework\Api\SearchCriteriaInterface::class)
->disableOriginalConstructor()
->getMock();
- $searchCriteriaMock->expects($this->once())
+ $searchCriteriaMock->expects($this->any())
->method('getFilterGroups')
->willReturn([$filterGroupMock]);
@@ -324,52 +316,6 @@ public function testGetList()
$this->assertEquals($searchResultsMock, $this->model->getList($searchCriteriaMock));
}
- /**
- * Test get list with invalid input exception
- *
- * @expectedException \Magento\Framework\Exception\InputException
- * @expectedExceptionMessage attribute_set_id is a required field.
- * @throws \Magento\Framework\Exception\InputException
- * @throws \Magento\Framework\Exception\NoSuchEntityException
- * @return void
- */
- public function testGetListWithInvalidInputException()
- {
- $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
- $searchCriteriaMock->expects($this->once())->method('getFilterGroups')->willReturn([]);
- $this->model->getList($searchCriteriaMock);
- }
-
- /**
- * Test get list with no such entity exception
- *
- * @expectedException \Magento\Framework\Exception\NoSuchEntityException
- * @expectedExceptionMessage No such entity with attributeSetId = filter
- * @throws \Magento\Framework\Exception\InputException
- * @throws \Magento\Framework\Exception\NoSuchEntityException
- * @return void
- */
- public function testGetListWithNoSuchEntityException()
- {
- $attributeSetId = 'filter';
- $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
- $filterGroupMock = $this->createMock(\Magento\Framework\Api\Search\FilterGroup::class);
- $filterInterfaceMock = $this->createMock(\Magento\Framework\Api\Filter::class);
-
- $searchCriteriaMock->expects($this->once())->method('getFilterGroups')->willReturn([$filterGroupMock]);
-
- $filterGroupMock->expects($this->once())->method('getFilters')->willReturn([$filterInterfaceMock]);
- $filterInterfaceMock->expects($this->once())->method('getField')->willReturn('attribute_set_id');
- $filterInterfaceMock->expects($this->once())->method('getValue')->willReturn($attributeSetId);
-
- $searchCriteriaMock->expects($this->once())->method('getFilterGroups')->willReturn([]);
- $this->setRepositoryMock->expects($this->once())
- ->method('get')
- ->with($attributeSetId)
- ->willThrowException(new \Exception());
- $this->model->getList($searchCriteriaMock);
- }
-
/**
* Test get
*
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
index 682907e9c0a23..67899dc3902eb 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
@@ -320,19 +320,29 @@ public function productAttributesDataProvider()
[
'test_attr',
$attributeSetId,
- ['test_attr' => 'test_attr', 'attribute_set_id' => $attributeSetId, 'entity_id' => null],
+ [
+ 'test_attr' => 'test_attr',
+ 'attribute_set_id' => $attributeSetId,
+ 'entity_id' => null,
+ 'store_id' => 1
+ ],
null,
],
[
'test_attr',
$attributeSetId,
- ['test_attr' => 'test_attr', 'attribute_set_id' => $attributeSetId, 'entity_id' => 12345],
+ [
+ 'test_attr' => 'test_attr',
+ 'attribute_set_id' => $attributeSetId,
+ 'entity_id' => 12345,
+ 'store_id' => 1
+ ],
['test_attr' => 'test_attr']
],
[
'test_attr',
$attributeSetId,
- ['test_attr' => '99.99', 'attribute_set_id' => $attributeSetId, 'entity_id' => 12345],
+ ['test_attr' => '99.99', 'attribute_set_id' => $attributeSetId, 'entity_id' => 12345, 'store_id' => 1],
['test_attr' => '99.9900']
]
];
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php
index 3cfc3dafda3f5..3370695b47d7e 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AttributeLoaderTest.php
@@ -78,7 +78,7 @@ public function testLoadAllAttributes()
$attributeMock->expects($this->once())->method('setIsGlobal')->with(1)->willReturnSelf();
$attributeMock->expects($this->once())->method('setEntityType')->with($this->entityTypeMock)->willReturnSelf();
$attributeMock->expects($this->once())->method('setEntityTypeId')->with($entityTypeId)->willReturnSelf();
- $this->entityMock->expects($this->once())->method('addAttribute')->with($attributeMock)->willReturnSelf();
+ $this->entityMock->expects($this->once())->method('addAttributeByScope')->willReturnSelf();
$this->attributeLoader->loadAllAttributes($this->entityMock, $dataObject);
}
@@ -102,8 +102,7 @@ public function testLoadAllAttributesAttributeCodesPresentInDefaultAttributes()
->method('getEntityAttributes')->willReturn($attributeCodes);
$this->entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn($defaultAttributes);
$this->entityMock->expects($this->once())->method('unsetAttributes')->willReturnSelf();
- $this->entityMock->expects($this->atLeastOnce())
- ->method('addAttribute')->with($attributeMock)->willReturnSelf();
+ $this->entityMock->expects($this->atLeastOnce())->method('addAttributeByScope')->willReturnSelf();
$this->objectManagerMock->expects($this->never())->method('create');
$this->attributeLoader->loadAllAttributes($this->entityMock, $dataObject);
}
diff --git a/app/code/Magento/Eav/composer.json b/app/code/Magento/Eav/composer.json
index 2900d8397ff40..be753a6fca7d3 100644
--- a/app/code/Magento/Eav/composer.json
+++ b/app/code/Magento/Eav/composer.json
@@ -11,7 +11,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "101.0.0",
+ "version": "101.0.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Email/Model/Template/Config.php b/app/code/Magento/Email/Model/Template/Config.php
index bdd9054e7969b..8a7e7172a8e6e 100644
--- a/app/code/Magento/Email/Model/Template/Config.php
+++ b/app/code/Magento/Email/Model/Template/Config.php
@@ -205,8 +205,9 @@ public function getTemplateFilename($templateId, $designParams = [])
$designParams['module'] = $module;
$file = $this->_getInfo($templateId, 'file');
+ $filename = $this->getFilename($file, $designParams, $module);
- return $this->viewFileSystem->getEmailTemplateFileName($file, $designParams, $module);
+ return $filename;
}
/**
@@ -230,4 +231,24 @@ protected function _getInfo($templateId, $fieldName)
}
return $data[$templateId][$fieldName];
}
+
+ /**
+ * @param string $file
+ * @param array $designParams
+ * @param string $module
+ *
+ * @return string
+ *
+ * @throws \UnexpectedValueException
+ */
+ private function getFilename($file, array $designParams, $module)
+ {
+ $filename = $this->viewFileSystem->getEmailTemplateFileName($file, $designParams, $module);
+
+ if ($filename === false) {
+ throw new \UnexpectedValueException("Template file '{$file}' is not found.");
+ }
+
+ return $filename;
+ }
}
diff --git a/app/code/Magento/Email/Test/Unit/Model/Template/ConfigTest.php b/app/code/Magento/Email/Test/Unit/Model/Template/ConfigTest.php
index 47c3ac1e7e450..6a565ca08eb9b 100644
--- a/app/code/Magento/Email/Test/Unit/Model/Template/ConfigTest.php
+++ b/app/code/Magento/Email/Test/Unit/Model/Template/ConfigTest.php
@@ -272,6 +272,19 @@ public function testGetTemplateFilenameWithNoParams()
$this->assertEquals('_files/Fixture/ModuleOne/view/frontend/email/one.html', $actualResult);
}
+ /**
+ * @expectedException \UnexpectedValueException
+ * @expectedExceptionMessage Template file 'one.html' is not found
+ */
+ public function testGetTemplateFilenameWrongFileName()
+ {
+ $this->viewFileSystem->expects($this->once())->method('getEmailTemplateFileName')
+ ->with('one.html', $this->designParams, 'Fixture_ModuleOne')
+ ->willReturn(false);
+
+ $this->model->getTemplateFilename('template_one', $this->designParams);
+ }
+
/**
* @param string $getterMethod
* @param $argument
diff --git a/app/code/Magento/Email/composer.json b/app/code/Magento/Email/composer.json
index 2a651a44a4a54..9ef1c3ba39a6b 100644
--- a/app/code/Magento/Email/composer.json
+++ b/app/code/Magento/Email/composer.json
@@ -15,7 +15,7 @@
"magento/module-theme": "100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/GoogleOptimizer/composer.json b/app/code/Magento/GoogleOptimizer/composer.json
index 62534b81d9b3a..5aeadefbfda94 100644
--- a/app/code/Magento/GoogleOptimizer/composer.json
+++ b/app/code/Magento/GoogleOptimizer/composer.json
@@ -12,7 +12,7 @@
"magento/module-ui": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/GroupedProduct/composer.json b/app/code/Magento/GroupedProduct/composer.json
index 16d0f029539f8..22426af3852cb 100644
--- a/app/code/Magento/GroupedProduct/composer.json
+++ b/app/code/Magento/GroupedProduct/composer.json
@@ -21,7 +21,7 @@
"magento/module-grouped-product-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/ImportExport/composer.json b/app/code/Magento/ImportExport/composer.json
index 23ed2f6346ef7..1c159305c8920 100644
--- a/app/code/Magento/ImportExport/composer.json
+++ b/app/code/Magento/ImportExport/composer.json
@@ -12,7 +12,7 @@
"ext-ctype": "*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Indexer/composer.json b/app/code/Magento/Indexer/composer.json
index 58c2c7f3587f2..ced51945495f9 100644
--- a/app/code/Magento/Indexer/composer.json
+++ b/app/code/Magento/Indexer/composer.json
@@ -7,7 +7,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/InstantPurchase/Model/PlaceOrder.php b/app/code/Magento/InstantPurchase/Model/PlaceOrder.php
index 3129739ea0937..2ad56a8859cf3 100644
--- a/app/code/Magento/InstantPurchase/Model/PlaceOrder.php
+++ b/app/code/Magento/InstantPurchase/Model/PlaceOrder.php
@@ -13,7 +13,9 @@
use Magento\InstantPurchase\Model\QuoteManagement\QuoteCreation;
use Magento\InstantPurchase\Model\QuoteManagement\QuoteFilling;
use Magento\InstantPurchase\Model\QuoteManagement\ShippingConfiguration;
+use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Store\Model\Store;
+use \Throwable;
/**
* Place an order using instant purchase option.
@@ -22,6 +24,11 @@
*/
class PlaceOrder
{
+ /**
+ * @var CartRepositoryInterface
+ */
+ private $quoteRepository;
+
/**
* @var QuoteCreation
*/
@@ -49,6 +56,7 @@ class PlaceOrder
/**
* PlaceOrder constructor.
+ * @param CartRepositoryInterface $quoteRepository
* @param QuoteCreation $quoteCreation
* @param QuoteFilling $quoteFilling
* @param ShippingConfiguration $shippingConfiguration
@@ -56,12 +64,14 @@ class PlaceOrder
* @param Purchase $purchase
*/
public function __construct(
+ CartRepositoryInterface $quoteRepository,
QuoteCreation $quoteCreation,
QuoteFilling $quoteFilling,
ShippingConfiguration $shippingConfiguration,
PaymentConfiguration $paymentConfiguration,
Purchase $purchase
) {
+ $this->quoteRepository = $quoteRepository;
$this->quoteCreation = $quoteCreation;
$this->quoteFilling = $quoteFilling;
$this->shippingConfiguration = $shippingConfiguration;
@@ -79,6 +89,7 @@ public function __construct(
* @param array $productRequest
* @return int order identifier
* @throws LocalizedException if order can not be placed.
+ * @throws Throwable if unpredictable error occurred.
*/
public function placeOrder(
Store $store,
@@ -98,17 +109,28 @@ public function placeOrder(
$product,
$productRequest
);
- $quote = $this->shippingConfiguration->configureShippingMethod(
- $quote,
- $instantPurchaseOption->getShippingMethod()
- );
- $quote = $this->paymentConfiguration->configurePayment(
- $quote,
- $instantPurchaseOption->getPaymentToken()
- );
- $orderId = $this->purchase->purchase(
- $quote
- );
- return $orderId;
+
+ $quote->collectTotals();
+ $this->quoteRepository->save($quote);
+ $quote = $this->quoteRepository->get($quote->getId());
+
+ try {
+ $quote = $this->shippingConfiguration->configureShippingMethod(
+ $quote,
+ $instantPurchaseOption->getShippingMethod()
+ );
+ $quote = $this->paymentConfiguration->configurePayment(
+ $quote,
+ $instantPurchaseOption->getPaymentToken()
+ );
+ $orderId = $this->purchase->purchase(
+ $quote
+ );
+ return $orderId;
+ } catch (Throwable $e) {
+ $quote->setIsActive(false);
+ $this->quoteRepository->save($quote);
+ throw $e;
+ }
}
}
diff --git a/app/code/Magento/InstantPurchase/composer.json b/app/code/Magento/InstantPurchase/composer.json
index 1c3b97a6beb94..a771869ddd1b8 100644
--- a/app/code/Magento/InstantPurchase/composer.json
+++ b/app/code/Magento/InstantPurchase/composer.json
@@ -1,29 +1,29 @@
{
- "name": "magento/module-instant-purchase",
- "description": "N/A",
- "type": "magento2-module",
- "version": "100.2.0",
- "license": [
- "OSL-3.0",
- "AFL-3.0"
- ],
- "require": {
- "php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-store": "100.2.*",
- "magento/module-catalog": "102.0.*",
- "magento/module-customer": "101.0.*",
- "magento/module-sales": "101.0.*",
- "magento/module-shipping": "100.2.*",
- "magento/module-quote": "101.0.*",
- "magento/module-vault": "101.0.*",
- "magento/framework": "100.2.*"
- },
- "autoload": {
- "files": [
- "registration.php"
+ "name": "magento/module-instant-purchase",
+ "description": "N/A",
+ "type": "magento2-module",
+ "version": "100.2.0",
+ "license": [
+ "OSL-3.0",
+ "AFL-3.0"
],
- "psr-4": {
- "Magento\\InstantPurchase\\": ""
+ "require": {
+ "php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
+ "magento/module-store": "100.2.*",
+ "magento/module-catalog": "102.0.*",
+ "magento/module-customer": "101.0.*",
+ "magento/module-sales": "101.0.*",
+ "magento/module-shipping": "100.2.*",
+ "magento/module-quote": "101.0.*",
+ "magento/module-vault": "101.0.*",
+ "magento/framework": "101.0.*"
+ },
+ "autoload": {
+ "files": [
+ "registration.php"
+ ],
+ "psr-4": {
+ "Magento\\InstantPurchase\\": ""
+ }
}
- }
-}
\ No newline at end of file
+}
diff --git a/app/code/Magento/InstantPurchase/view/frontend/web/js/view/instant-purchase.js b/app/code/Magento/InstantPurchase/view/frontend/web/js/view/instant-purchase.js
index b5c5b1f0a0853..533cd8ea90e3e 100644
--- a/app/code/Magento/InstantPurchase/view/frontend/web/js/view/instant-purchase.js
+++ b/app/code/Magento/InstantPurchase/view/frontend/web/js/view/instant-purchase.js
@@ -1,111 +1,115 @@
-/*jshint browser:true*/
-/*global define*/
-define(
- [
- 'uiComponent',
- 'ko',
- 'Magento_Ui/js/modal/confirm',
- 'jquery',
- 'Magento_Customer/js/customer-data',
- 'mage/url',
- 'mage/template',
- 'jquery/ui',
- 'mage/translate'
- ], function (
- Component,
- ko,
- confirm,
- $,
- customerData,
- urlBuilder,
- mageTemplate
- ) {
- 'use strict';
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+ 'ko',
+ 'jquery',
+ 'underscore',
+ 'uiComponent',
+ 'Magento_Ui/js/modal/confirm',
+ 'Magento_Customer/js/customer-data',
+ 'mage/url',
+ 'mage/template',
+ 'mage/translate',
+ 'text!Magento_InstantPurchase/template/confirmation.html',
+ 'mage/validation'
+], function (ko, $, _, Component, confirm, customerData, urlBuilder, mageTemplate, $t, confirmationTemplate) {
+ 'use strict';
- return Component.extend({
- showButton: ko.observable(false),
- paymentToken: ko.observable(null),
- shippingAddress: ko.observable(null),
- billingAddress: ko.observable(null),
- shippingMethod: ko.observable(null),
- defaults: {
- template: 'Magento_InstantPurchase/instant-purchase',
- buttonText: $.mage.__('Instant Purchase'),
- purchaseUrl: urlBuilder.build('instantpurchase/button/placeOrder')
- },
- options: {
- message: $.mage.__('Are you sure you want to place order and pay?'),
- formSelector: '#product_addtocart_form',
- confirmTemplate: '<%- data.message %>
' +
- '' + $.mage.__('Shipping Address') + ':' +
- '<%- data.shippingAddress().summary %>
' +
- '' + $.mage.__('Billing Address') + ':' +
- '<%- data.billingAddress().summary %>
' +
- '' + $.mage.__('Payment Method') + ':\n' +
- '<%- data.paymentToken().summary %>
' +
- '' + $.mage.__('Shipping Method') + ':\n' +
- '<%- data.shippingMethod().summary %>
'
- },
+ return Component.extend({
+ defaults: {
+ template: 'Magento_InstantPurchase/instant-purchase',
+ buttonText: $t('Instant Purchase'),
+ purchaseUrl: urlBuilder.build('instantpurchase/button/placeOrder'),
+ showButton: false,
+ paymentToken: null,
+ shippingAddress: null,
+ billingAddress: null,
+ shippingMethod: null,
+ productFormSelector: '#product_addtocart_form',
+ confirmationTitle: $t('Instant Purchase Confirmation'),
+ confirmationData: {
+ message: $t('Are you sure you want to place order and pay?'),
+ shippingAddressTitle: $t('Shipping Address'),
+ billingAddressTitle: $t('Billing Address'),
+ paymentMethodTitle: $t('Payment Method'),
+ shippingMethodTitle: $t('Shipping Method')
+ }
+ },
- /** @inheritdoc */
- initialize: function () {
- var self = this,
- data = customerData.get('instant-purchase')();
+ /** @inheritdoc */
+ initialize: function () {
+ var instantPurchase = customerData.get('instant-purchase');
- this._super();
+ this._super();
- self.showButton(data.available);
- self.paymentToken(data.paymentToken);
- self.shippingAddress(data.shippingAddress);
- self.billingAddress(data.billingAddress);
- self.shippingMethod(data.shippingMethod);
- },
+ this.setPurchaseData(instantPurchase());
+ instantPurchase.subscribe(this.setPurchaseData, this);
+ },
- /**
- * Confirmation method
- */
- instantPurchase: function () {
- var self = this,
- form = $(self.options.formSelector),
- confirmTemplate = mageTemplate(this.options.confirmTemplate);
+ /** @inheritdoc */
+ initObservable: function () {
+ this._super()
+ .observe('showButton paymentToken shippingAddress billingAddress shippingMethod');
- if (!(form.validation() && form.validation('isValid'))) {
- return;
- }
+ return this;
+ },
- confirm({
- title: $.mage.__('Instant Purchase Confirmation'),
- content: confirmTemplate(
- {
- data: {
- message: self.options.message,
- paymentToken: self.paymentToken,
- shippingAddress: self.shippingAddress,
- billingAddress: self.billingAddress,
- shippingMethod: self.shippingMethod
- }
- }
- ),
- actions: {
- /** @inheritdoc */
- confirm: function () {
- $.ajax({
- url: self.purchaseUrl,
- data: form.serialize(),
- type: 'post',
- dataType: 'json',
+ /**
+ * Set data from customerData.
+ *
+ * @param {Object} data
+ */
+ setPurchaseData: function (data) {
+ this.showButton(data.available);
+ this.paymentToken(data.paymentToken);
+ this.shippingAddress(data.shippingAddress);
+ this.billingAddress(data.billingAddress);
+ this.shippingMethod(data.shippingMethod);
+ },
- /** Show loader before send */
- beforeSend: function () {
- $('body').trigger('processStart');
- }
- }).always(function () {
- $('body').trigger('processStop');
- });
- }
- }
+ /**
+ * Confirmation method
+ */
+ instantPurchase: function () {
+ var form = $(this.productFormSelector),
+ confirmTemplate = mageTemplate(confirmationTemplate),
+ confirmData = _.extend({}, this.confirmationData, {
+ paymentToken: this.paymentToken().summary,
+ shippingAddress: this.shippingAddress().summary,
+ billingAddress: this.billingAddress().summary,
+ shippingMethod: this.shippingMethod().summary
});
+
+ if (!(form.validation() && form.validation('isValid'))) {
+ return;
}
- });
- }
-);
+
+ confirm({
+ title: this.confirmationTitle,
+ content: confirmTemplate({
+ data: confirmData
+ }),
+ actions: {
+ /** @inheritdoc */
+ confirm: function () {
+ $.ajax({
+ url: this.purchaseUrl,
+ data: form.serialize(),
+ type: 'post',
+ dataType: 'json',
+
+ /** Show loader before send */
+ beforeSend: function () {
+ $('body').trigger('processStart');
+ }
+ }).always(function () {
+ $('body').trigger('processStop');
+ });
+ }.bind(this)
+ }
+ });
+ }
+ });
+});
diff --git a/app/code/Magento/InstantPurchase/view/frontend/web/template/confirmation.html b/app/code/Magento/InstantPurchase/view/frontend/web/template/confirmation.html
new file mode 100644
index 0000000000000..883cf1c2fd8f9
--- /dev/null
+++ b/app/code/Magento/InstantPurchase/view/frontend/web/template/confirmation.html
@@ -0,0 +1,15 @@
+
+<%- data.message %>
+<%- data.shippingAddressTitle %>:
+<%- data.shippingAddress %>
+<%- data.billingAddressTitle %>:
+<%- data.billingAddress %>
+<%- data.paymentMethodTitle %>:
+<%- data.paymentToken %>
+<%- data.shippingMethodTitle %>:
+<%- data.shippingMethod %>
\ No newline at end of file
diff --git a/app/code/Magento/InstantPurchase/view/frontend/web/template/instant-purchase.html b/app/code/Magento/InstantPurchase/view/frontend/web/template/instant-purchase.html
index 058b09e16a687..0373b25c9c523 100644
--- a/app/code/Magento/InstantPurchase/view/frontend/web/template/instant-purchase.html
+++ b/app/code/Magento/InstantPurchase/view/frontend/web/template/instant-purchase.html
@@ -1,29 +1,34 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Integration/composer.json b/app/code/Magento/Integration/composer.json
index ef591e69178c3..25c98161e6f2a 100644
--- a/app/code/Magento/Integration/composer.json
+++ b/app/code/Magento/Integration/composer.json
@@ -12,7 +12,7 @@
"magento/module-authorization": "100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml b/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml
index ec74b837e1077..a37306bf1eed7 100644
--- a/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml
+++ b/app/code/Magento/Marketplace/view/adminhtml/templates/index.phtml
@@ -46,9 +46,9 @@
@@ -61,7 +61,7 @@
); ?>
+ href="https://marketplace.magento.com/">
= /* @escapeNotVerified */ __('Visit Magento Marketplaces') ?>
diff --git a/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-connect.png b/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-connect.png
deleted file mode 100644
index 575563f341b35..0000000000000
Binary files a/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-connect.png and /dev/null differ
diff --git a/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-marketplace.svg b/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-marketplace.svg
new file mode 100644
index 0000000000000..388544d5d7f3d
--- /dev/null
+++ b/app/code/Magento/Marketplace/view/adminhtml/web/partners/images/magento-marketplace.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php
index f9d6d0adaae93..767f58bb9e4ed 100644
--- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php
+++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php
@@ -817,13 +817,21 @@ public function reset()
*/
public function validateMinimumAmount()
{
- return !($this->_scopeConfig->isSetFlag(
+ $minimumOrderActive = $this->_scopeConfig->isSetFlag(
'sales/minimum_order/active',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
- ) && $this->_scopeConfig->isSetFlag(
+ );
+
+ if ($this->_scopeConfig->isSetFlag(
'sales/minimum_order/multi_address',
- \Magento\Store\Model\ScopeInterface::SCOPE_STORE
- ) && !$this->getQuote()->validateMinimumAmount());
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE)
+ ) {
+ $result = !($minimumOrderActive && !$this->getQuote()->validateMinimumAmount());
+ } else {
+ $result = !($minimumOrderActive && !$this->validateMinimumAmountForAddressItems());
+ }
+
+ return $result;
}
/**
@@ -1031,4 +1039,41 @@ private function getShippingAssignmentProcessor()
}
return $this->shippingAssignmentProcessor;
}
+
+ /**
+ * Validate minimum amount for "Checkout with Multiple Addresses" when
+ * "Validate Each Address Separately in Multi-address Checkout" is No.
+ *
+ * @return bool
+ */
+ private function validateMinimumAmountForAddressItems()
+ {
+ $result = true;
+ $storeId = $this->getQuote()->getStoreId();
+
+ $minAmount = $this->_scopeConfig->getValue(
+ 'sales/minimum_order/amount',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+ $storeId
+ );
+ $taxInclude = $this->_scopeConfig->getValue(
+ 'sales/minimum_order/tax_including',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+ $storeId
+ );
+
+ $addresses = $this->getQuote()->getAllAddresses();
+
+ $baseTotal = 0;
+ foreach ($addresses as $address) {
+ $taxes = $taxInclude ? $address->getBaseTaxAmount() : 0;
+ $baseTotal += $address->getBaseSubtotalWithDiscount() + $taxes;
+ }
+
+ if ($baseTotal < $minAmount) {
+ $result = false;
+ }
+
+ return $result;
+ }
}
diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php
index 1d779c11d5935..f90e85a904352 100644
--- a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php
+++ b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php
@@ -118,13 +118,18 @@ class MultishippingTest extends \PHPUnit\Framework\TestCase
*/
private $quoteRepositoryMock;
+ /**
+ * @var PHPUnit_Framework_MockObject_MockObject
+ */
+ private $scopeConfigMock;
+
protected function setUp()
{
$this->checkoutSessionMock = $this->createSimpleMock(Session::class);
$this->customerSessionMock = $this->createSimpleMock(CustomerSession::class);
$orderFactoryMock = $this->createSimpleMock(OrderFactory::class);
$eventManagerMock = $this->createSimpleMock(ManagerInterface::class);
- $scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class);
+ $this->scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class);
$sessionMock = $this->createSimpleMock(Generic::class);
$addressFactoryMock = $this->createSimpleMock(AddressFactory::class);
$toOrderMock = $this->createSimpleMock(ToOrder::class);
@@ -166,7 +171,7 @@ protected function setUp()
$orderFactoryMock,
$this->addressRepositoryMock,
$eventManagerMock,
- $scopeConfigMock,
+ $this->scopeConfigMock,
$sessionMock,
$addressFactoryMock,
$toOrderMock,
@@ -497,4 +502,37 @@ private function createSimpleMock($className)
->disableOriginalConstructor()
->getMock();
}
+
+ public function testValidateMinimumAmountMultiAddressTrue()
+ {
+ $this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive(
+ ['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
+ ['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
+ )->willReturnOnConsecutiveCalls(true, true);
+
+ $this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock);
+ $this->quoteMock->expects($this->once())->method('validateMinimumAmount')->willReturn(false);
+ $this->assertFalse($this->model->validateMinimumAmount());
+ }
+
+ public function testValidateMinimumAmountMultiAddressFalse()
+ {
+ $addressMock = $this->createMock(\Magento\Quote\Model\Quote\Address::class);
+ $this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive(
+ ['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
+ ['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
+ )->willReturnOnConsecutiveCalls(true, false);
+
+ $this->scopeConfigMock->expects($this->exactly(2))->method('getValue')->withConsecutive(
+ ['sales/minimum_order/amount', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
+ ['sales/minimum_order/tax_including', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
+ )->willReturnOnConsecutiveCalls(100, false);
+
+ $this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock);
+ $this->quoteMock->expects($this->once())->method('getStoreId')->willReturn(1);
+ $this->quoteMock->expects($this->once())->method('getAllAddresses')->willReturn([$addressMock]);
+ $addressMock->expects($this->once())->method('getBaseSubtotalWithDiscount')->willReturn(101);
+
+ $this->assertTrue($this->model->validateMinimumAmount());
+ }
}
diff --git a/app/code/Magento/NewRelicReporting/Console/Command/DeployMarker.php b/app/code/Magento/NewRelicReporting/Console/Command/DeployMarker.php
new file mode 100644
index 0000000000000..795028cffd18d
--- /dev/null
+++ b/app/code/Magento/NewRelicReporting/Console/Command/DeployMarker.php
@@ -0,0 +1,81 @@
+deploymentsFactory = $deploymentsFactory;
+ $this->serviceShellUser = $serviceShellUser;
+ parent::__construct($name);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function configure()
+ {
+ $this->setName("newrelic:create:deploy-marker");
+ $this->setDescription("Check the deploy queue for entries and create an appropriate deploy marker.")
+ ->addArgument(
+ 'message',
+ InputArgument::REQUIRED,
+ 'Deploy Message?'
+ )
+ ->addArgument(
+ 'changelog',
+ InputArgument::REQUIRED,
+ 'Change Log?'
+ )
+ ->addArgument(
+ 'user',
+ InputArgument::OPTIONAL,
+ 'Deployment User'
+ );
+ parent::configure();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $this->deploymentsFactory->create()->setDeployment(
+ $input->getArgument('message'),
+ $input->getArgument('changelog'),
+ $this->serviceShellUser->get($input->getArgument('user'))
+ );
+ $output->writeln('
NewRelic deployment information sent');
+ }
+}
diff --git a/app/code/Magento/NewRelicReporting/Model/Cron/ReportNewRelicCron.php b/app/code/Magento/NewRelicReporting/Model/Cron/ReportNewRelicCron.php
index a4a7d30b44f5b..6b2bd50dc456b 100644
--- a/app/code/Magento/NewRelicReporting/Model/Cron/ReportNewRelicCron.php
+++ b/app/code/Magento/NewRelicReporting/Model/Cron/ReportNewRelicCron.php
@@ -175,7 +175,6 @@ protected function reportCounts()
public function report()
{
if ($this->config->isNewRelicEnabled()) {
- $this->reportModules();
$this->reportCounts();
}
diff --git a/app/code/Magento/NewRelicReporting/Model/ServiceShellUser.php b/app/code/Magento/NewRelicReporting/Model/ServiceShellUser.php
new file mode 100644
index 0000000000000..c038be4fb2a76
--- /dev/null
+++ b/app/code/Magento/NewRelicReporting/Model/ServiceShellUser.php
@@ -0,0 +1,34 @@
+ [
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'enabled'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'disabled'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'installed'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'uninstalled'],
- ],
- 'enabled' => 1,
- 'disabled' => 1,
- 'installed' => 1,
- ];
$this->config->expects($this->once())
->method('isNewRelicEnabled')
->willReturn(true);
- $this->collect->expects($this->once())
- ->method('getModuleData')
- ->willReturn($testModuleData);
$this->counter->expects($this->once())
->method('getAllProductsCount');
$this->counter->expects($this->once())
@@ -198,24 +184,10 @@ public function testReportNewRelicCron()
*/
public function testReportNewRelicCronRequestFailed()
{
- $testModuleData = [
- 'changes' => [
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'enabled'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'disabled'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'installed'],
- ['name' => 'name', 'setup_version' => '2.0.0', 'type' => 'uninstalled'],
- ],
- 'enabled' => 1,
- 'disabled' => 1,
- 'installed' => 1,
- ];
$this->config->expects($this->once())
->method('isNewRelicEnabled')
->willReturn(true);
- $this->collect->expects($this->once())
- ->method('getModuleData')
- ->willReturn($testModuleData);
$this->counter->expects($this->once())
->method('getAllProductsCount');
$this->counter->expects($this->once())
diff --git a/app/code/Magento/NewRelicReporting/composer.json b/app/code/Magento/NewRelicReporting/composer.json
index f8aa98ca11dc2..4a02d673a54f6 100644
--- a/app/code/Magento/NewRelicReporting/composer.json
+++ b/app/code/Magento/NewRelicReporting/composer.json
@@ -13,7 +13,7 @@
"magento/magento-composer-installer": "*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/NewRelicReporting/etc/di.xml b/app/code/Magento/NewRelicReporting/etc/di.xml
index cba92f91cd4bb..2dccc45c1129b 100644
--- a/app/code/Magento/NewRelicReporting/etc/di.xml
+++ b/app/code/Magento/NewRelicReporting/etc/di.xml
@@ -30,4 +30,11 @@
+
+
+
+ - Magento\NewRelicReporting\Console\Command\DeployMarker
+
+
+
diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php
index cc143fdc52e3b..b8d7ccf83af7c 100644
--- a/app/code/Magento/Newsletter/Model/Subscriber.php
+++ b/app/code/Magento/Newsletter/Model/Subscriber.php
@@ -633,6 +633,8 @@ public function confirm($code)
$this->setStatus(self::STATUS_SUBSCRIBED)
->setStatusChanged(true)
->save();
+
+ $this->sendConfirmationSuccessEmail();
return true;
}
diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php
index 5a4032dc4dffd..7dd96be11bcbe 100644
--- a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php
+++ b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php
@@ -341,6 +341,21 @@ public function testConfirm()
$code = 111;
$this->subscriber->setCode($code);
$this->resource->expects($this->once())->method('save')->willReturnSelf();
+ $storeModel = $this->getMockBuilder(\Magento\Store\Model\Store::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getId'])
+ ->getMock();
+ $transport = $this->createMock(\Magento\Framework\Mail\TransportInterface::class);
+ $this->scopeConfig->expects($this->any())->method('getValue')->willReturn(true);
+ $this->transportBuilder->expects($this->once())->method('setTemplateIdentifier')->willReturnSelf();
+ $this->transportBuilder->expects($this->once())->method('setTemplateOptions')->willReturnSelf();
+ $this->transportBuilder->expects($this->once())->method('setTemplateVars')->willReturnSelf();
+ $this->transportBuilder->expects($this->once())->method('setFrom')->willReturnSelf();
+ $this->transportBuilder->expects($this->once())->method('addTo')->willReturnSelf();
+ $this->storeManager->expects($this->any())->method('getStore')->willReturn($storeModel);
+ $storeModel->expects($this->any())->method('getId')->willReturn(1);
+ $this->transportBuilder->expects($this->once())->method('getTransport')->willReturn($transport);
+ $transport->expects($this->once())->method('sendMessage')->willReturnSelf();
$this->assertTrue($this->subscriber->confirm($code));
}
diff --git a/app/code/Magento/Newsletter/composer.json b/app/code/Magento/Newsletter/composer.json
index 12ce0c988288b..3cd5e15d46398 100644
--- a/app/code/Magento/Newsletter/composer.json
+++ b/app/code/Magento/Newsletter/composer.json
@@ -14,7 +14,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json
index 3998a83aa2d64..2ce66fa368d01 100644
--- a/app/code/Magento/OfflineShipping/composer.json
+++ b/app/code/Magento/OfflineShipping/composer.json
@@ -19,7 +19,7 @@
"magento/module-offline-shipping-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/PageCache/composer.json b/app/code/Magento/PageCache/composer.json
index bb05a371bd0b2..cdbd8327b9cdd 100644
--- a/app/code/Magento/PageCache/composer.json
+++ b/app/code/Magento/PageCache/composer.json
@@ -9,7 +9,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/PageCache/etc/varnish4.vcl b/app/code/Magento/PageCache/etc/varnish4.vcl
index 9e57f1e362320..793f8f81a03f9 100644
--- a/app/code/Magento/PageCache/etc/varnish4.vcl
+++ b/app/code/Magento/PageCache/etc/varnish4.vcl
@@ -157,6 +157,7 @@ sub vcl_backend_response {
}
# validate if we need to cache it and prevent from setting cookie
+ # images, css and js are cacheable by default so we have to remove cookie also
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
unset beresp.http.set-cookie;
}
@@ -187,6 +188,13 @@ sub vcl_deliver {
unset resp.http.Age;
}
+ # Not letting browser to cache non-static files.
+ if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
+ set resp.http.Pragma = "no-cache";
+ set resp.http.Expires = "-1";
+ set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
+ }
+
unset resp.http.X-Magento-Debug;
unset resp.http.X-Magento-Tags;
unset resp.http.X-Powered-By;
diff --git a/app/code/Magento/PageCache/etc/varnish5.vcl b/app/code/Magento/PageCache/etc/varnish5.vcl
index cfc2192688748..4dce6356d1e73 100644
--- a/app/code/Magento/PageCache/etc/varnish5.vcl
+++ b/app/code/Magento/PageCache/etc/varnish5.vcl
@@ -158,6 +158,7 @@ sub vcl_backend_response {
}
# validate if we need to cache it and prevent from setting cookie
+ # images, css and js are cacheable by default so we have to remove cookie also
if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) {
unset beresp.http.set-cookie;
}
@@ -188,6 +189,13 @@ sub vcl_deliver {
unset resp.http.Age;
}
+ # Not letting browser to cache non-static files.
+ if (resp.http.Cache-Control !~ "private" && req.url !~ "^/(pub/)?(media|static)/") {
+ set resp.http.Pragma = "no-cache";
+ set resp.http.Expires = "-1";
+ set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, max-age=0";
+ }
+
unset resp.http.X-Magento-Debug;
unset resp.http.X-Magento-Tags;
unset resp.http.X-Powered-By;
diff --git a/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php b/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php
index a6f9d4383918c..bb07408ad0e06 100644
--- a/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php
+++ b/app/code/Magento/Payment/Gateway/Command/GatewayCommand.php
@@ -5,14 +5,13 @@
*/
namespace Magento\Payment\Gateway\Command;
-use Magento\Framework\Phrase;
use Magento\Payment\Gateway\CommandInterface;
+use Magento\Payment\Gateway\ErrorMapper\ErrorMessageMapperInterface;
use Magento\Payment\Gateway\Http\ClientInterface;
use Magento\Payment\Gateway\Http\TransferFactoryInterface;
-use Magento\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
-use Magento\Payment\Gateway\Response;
use Magento\Payment\Gateway\Response\HandlerInterface;
+use Magento\Payment\Gateway\Validator\ResultInterface;
use Magento\Payment\Gateway\Validator\ValidatorInterface;
use Psr\Log\LoggerInterface;
@@ -54,6 +53,11 @@ class GatewayCommand implements CommandInterface
*/
private $logger;
+ /**
+ * @var ErrorMessageMapperInterface
+ */
+ private $errorMessageMapper;
+
/**
* @param BuilderInterface $requestBuilder
* @param TransferFactoryInterface $transferFactory
@@ -61,6 +65,7 @@ class GatewayCommand implements CommandInterface
* @param LoggerInterface $logger
* @param HandlerInterface $handler
* @param ValidatorInterface $validator
+ * @param ErrorMessageMapperInterface|null $errorMessageMapper
*/
public function __construct(
BuilderInterface $requestBuilder,
@@ -68,7 +73,8 @@ public function __construct(
ClientInterface $client,
LoggerInterface $logger,
HandlerInterface $handler = null,
- ValidatorInterface $validator = null
+ ValidatorInterface $validator = null,
+ ErrorMessageMapperInterface $errorMessageMapper = null
) {
$this->requestBuilder = $requestBuilder;
$this->transferFactory = $transferFactory;
@@ -76,6 +82,7 @@ public function __construct(
$this->handler = $handler;
$this->validator = $validator;
$this->logger = $logger;
+ $this->errorMessageMapper = $errorMessageMapper;
}
/**
@@ -98,10 +105,7 @@ public function execute(array $commandSubject)
array_merge($commandSubject, ['response' => $response])
);
if (!$result->isValid()) {
- $this->logExceptions($result->getFailsDescription());
- throw new CommandException(
- __('Transaction has been declined. Please try again later.')
- );
+ $this->processErrors($result);
}
}
@@ -114,13 +118,33 @@ public function execute(array $commandSubject)
}
/**
- * @param Phrase[] $fails
- * @return void
+ * Tries to map error messages from validation result and logs processed message.
+ * Throws an exception with mapped message or default error.
+ *
+ * @param ResultInterface $result
+ * @throws CommandException
*/
- private function logExceptions(array $fails)
+ private function processErrors(ResultInterface $result)
{
- foreach ($fails as $failPhrase) {
- $this->logger->critical((string) $failPhrase);
+ $messages = [];
+ foreach ($result->getFailsDescription() as $failPhrase) {
+ $message = (string) $failPhrase;
+
+ // error messages mapper can be not configured if payment method doesn't have custom error messages.
+ if ($this->errorMessageMapper !== null) {
+ $mapped = (string) $this->errorMessageMapper->getMessage($message);
+ if (!empty($mapped)) {
+ $messages[] = $mapped;
+ $message = $mapped;
+ }
+ }
+ $this->logger->critical('Payment Error: ' . $message);
}
+
+ throw new CommandException(
+ !empty($messages)
+ ? __(implode(PHP_EOL, $messages))
+ : __('Transaction has been declined. Please try again later.')
+ );
}
}
diff --git a/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapper.php b/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapper.php
new file mode 100644
index 0000000000000..c5759d41bf4d7
--- /dev/null
+++ b/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapper.php
@@ -0,0 +1,40 @@
+messageMapping = $messageMapping;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getMessage(string $code)
+ {
+ $message = $this->messageMapping->get($code);
+ return $message ? __($message) : null;
+ }
+}
diff --git a/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapperInterface.php b/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapperInterface.php
new file mode 100644
index 0000000000000..077226fd9a062
--- /dev/null
+++ b/app/code/Magento/Payment/Gateway/ErrorMapper/ErrorMessageMapperInterface.php
@@ -0,0 +1,23 @@
+message` format and converts it to [code => message] array format.
+ */
+class XmlToArrayConverter implements ConverterInterface
+{
+ /**
+ * @inheritdoc
+ */
+ public function convert($source)
+ {
+ $result = [];
+ $messageList = $source->getElementsByTagName('message');
+ foreach ($messageList as $messageNode) {
+ $result[(string) $messageNode->getAttribute('code')] = (string) $messageNode->nodeValue;
+ }
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php b/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php
index df8bdc9bca54b..d17a7f302f31b 100644
--- a/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php
+++ b/app/code/Magento/Payment/Test/Unit/Gateway/Command/GatewayCommandTest.php
@@ -6,11 +6,15 @@
namespace Magento\Payment\Test\Unit\Gateway\Command;
use Magento\Payment\Gateway\Command\GatewayCommand;
+use Magento\Payment\Gateway\ErrorMapper\ErrorMessageMapperInterface;
use Magento\Payment\Gateway\Http\ClientInterface;
use Magento\Payment\Gateway\Http\TransferFactoryInterface;
+use Magento\Payment\Gateway\Http\TransferInterface;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Magento\Payment\Gateway\Response\HandlerInterface;
+use Magento\Payment\Gateway\Validator\ResultInterface;
use Magento\Payment\Gateway\Validator\ValidatorInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
use Psr\Log\LoggerInterface;
/**
@@ -18,175 +22,176 @@
*/
class GatewayCommandTest extends \PHPUnit\Framework\TestCase
{
- /** @var GatewayCommand */
- protected $command;
+ /**
+ * @var GatewayCommand
+ */
+ private $command;
/**
- * @var BuilderInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var BuilderInterface|MockObject
*/
- protected $requestBuilderMock;
+ private $requestBuilder;
/**
- * @var TransferFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var TransferFactoryInterface|MockObject
*/
- protected $transferFactoryMock;
+ private $transferFactory;
/**
- * @var ClientInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var ClientInterface|MockObject
*/
- protected $clientMock;
+ private $client;
/**
- * @var HandlerInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var HandlerInterface|MockObject
*/
- protected $responseHandlerMock;
+ private $responseHandler;
/**
- * @var ValidatorInterface|\PHPUnit_Framework_MockObject_MockObject
+ * @var ValidatorInterface|MockObject
*/
- protected $validatorMock;
+ private $validator;
/**
- * @var LoggerInterface |\PHPUnit_Framework_MockObject_MockObject
+ * @var LoggerInterface|MockObject
*/
private $logger;
+ /**
+ * @var ErrorMessageMapperInterface|MockObject
+ */
+ private $errorMessageMapper;
+
protected function setUp()
{
- $this->requestBuilderMock = $this->createMock(
- BuilderInterface::class
- );
- $this->transferFactoryMock = $this->createMock(
- TransferFactoryInterface::class
- );
- $this->clientMock = $this->createMock(
- ClientInterface::class
- );
- $this->responseHandlerMock = $this->createMock(
- HandlerInterface::class
- );
- $this->validatorMock = $this->createMock(
- ValidatorInterface::class
- );
+ $this->requestBuilder = $this->createMock(BuilderInterface::class);
+ $this->transferFactory = $this->createMock(TransferFactoryInterface::class);
+ $this->client = $this->createMock(ClientInterface::class);
+ $this->responseHandler = $this->createMock(HandlerInterface::class);
+ $this->validator = $this->createMock(ValidatorInterface::class);
$this->logger = $this->createMock(LoggerInterface::class);
+ $this->errorMessageMapper = $this->createMock(ErrorMessageMapperInterface::class);
$this->command = new GatewayCommand(
- $this->requestBuilderMock,
- $this->transferFactoryMock,
- $this->clientMock,
+ $this->requestBuilder,
+ $this->transferFactory,
+ $this->client,
$this->logger,
- $this->responseHandlerMock,
- $this->validatorMock
+ $this->responseHandler,
+ $this->validator,
+ $this->errorMessageMapper
);
}
public function testExecute()
{
$commandSubject = ['authorize'];
- $request = [
- 'request_field1' => 'request_value1',
- 'request_field2' => 'request_value2'
- ];
- $response = ['response_field1' => 'response_value1'];
- $validationResult = $this->getMockBuilder(
- \Magento\Payment\Gateway\Validator\ResultInterface::class
- )
- ->getMockForAbstractClass();
+ $this->processRequest($commandSubject, true);
- $transferO = $this->getMockBuilder(
- \Magento\Payment\Gateway\Http\TransferInterface::class
- )
- ->getMockForAbstractClass();
+ $this->responseHandler->method('handle')
+ ->with($commandSubject, ['response_field1' => 'response_value1']);
- $this->requestBuilderMock->expects(static::once())
- ->method('build')
- ->with($commandSubject)
- ->willReturn($request);
+ $this->command->execute($commandSubject);
+ }
- $this->transferFactoryMock->expects(static::once())
- ->method('create')
- ->with($request)
- ->willReturn($transferO);
+ /**
+ * Checks a case when request fails.
+ *
+ * @expectedException \Magento\Payment\Gateway\Command\CommandException
+ * @expectedExceptionMessage Transaction has been declined. Please try again later.
+ */
+ public function testExecuteValidationFail()
+ {
+ $commandSubject = ['authorize'];
+ $validationFailures = [
+ __('Failure #1'),
+ __('Failure #2'),
+ ];
- $this->clientMock->expects(static::once())
- ->method('placeRequest')
- ->with($transferO)
- ->willReturn($response);
- $this->validatorMock->expects(static::once())
- ->method('validate')
- ->with(array_merge($commandSubject, ['response' =>$response]))
- ->willReturn($validationResult);
- $validationResult->expects(static::once())
- ->method('isValid')
- ->willReturn(true);
+ $this->processRequest($commandSubject, false, $validationFailures);
- $this->responseHandlerMock->expects(static::once())
- ->method('handle')
- ->with($commandSubject, $response);
+ $this->logger->expects(self::exactly(count($validationFailures)))
+ ->method('critical')
+ ->withConsecutive(
+ [self::equalTo('Payment Error: ' . $validationFailures[0])],
+ [self::equalTo('Payment Error: ' . $validationFailures[1])]
+ );
$this->command->execute($commandSubject);
}
- public function testExecuteValidationFail()
+ /**
+ * Checks a case when request fails and response errors are mapped.
+ *
+ * @expectedException \Magento\Payment\Gateway\Command\CommandException
+ * @expectedExceptionMessage Failure Mapped
+ */
+ public function testExecuteValidationFailWithMappedErrors()
{
- $this->expectException(
- \Magento\Payment\Gateway\Command\CommandException::class
- );
-
$commandSubject = ['authorize'];
- $request = [
- 'request_field1' => 'request_value1',
- 'request_field2' => 'request_value2'
- ];
- $response = ['response_field1' => 'response_value1'];
$validationFailures = [
__('Failure #1'),
__('Failure #2'),
];
- $validationResult = $this->getMockBuilder(
- \Magento\Payment\Gateway\Validator\ResultInterface::class
- )
- ->getMockForAbstractClass();
- $transferO = $this->getMockBuilder(
- \Magento\Payment\Gateway\Http\TransferInterface::class
- )
+ $this->processRequest($commandSubject, false, $validationFailures);
+
+ $this->errorMessageMapper->method('getMessage')
+ ->willReturnMap(
+ [
+ ['Failure #1', 'Failure Mapped'],
+ ['Failure #2', null]
+ ]
+ );
+
+ $this->logger->expects(self::exactly(count($validationFailures)))
+ ->method('critical')
+ ->withConsecutive(
+ [self::equalTo('Payment Error: Failure Mapped')],
+ [self::equalTo('Payment Error: Failure #2')]
+ );
+
+ $this->command->execute($commandSubject);
+ }
+
+ /**
+ * Performs command actions like request, response and validation.
+ *
+ * @param array $commandSubject
+ * @param bool $validationResult
+ * @param array $validationFailures
+ */
+ private function processRequest(array $commandSubject, bool $validationResult, array $validationFailures = [])
+ {
+ $request = [
+ 'request_field1' => 'request_value1',
+ 'request_field2' => 'request_value2'
+ ];
+ $response = ['response_field1' => 'response_value1'];
+ $transferO = $this->getMockBuilder(TransferInterface::class)
->getMockForAbstractClass();
- $this->requestBuilderMock->expects(static::once())
- ->method('build')
+ $this->requestBuilder->method('build')
->with($commandSubject)
->willReturn($request);
- $this->transferFactoryMock->expects(static::once())
- ->method('create')
+ $this->transferFactory->method('create')
->with($request)
->willReturn($transferO);
- $this->clientMock->expects(static::once())
- ->method('placeRequest')
+ $this->client->method('placeRequest')
->with($transferO)
->willReturn($response);
- $this->validatorMock->expects(static::once())
- ->method('validate')
- ->with(array_merge($commandSubject, ['response' =>$response]))
- ->willReturn($validationResult);
- $validationResult->expects(static::once())
- ->method('isValid')
- ->willReturn(false);
- $validationResult->expects(static::once())
- ->method('getFailsDescription')
- ->willReturn(
- $validationFailures
- );
- $this->logger->expects(static::exactly(count($validationFailures)))
- ->method('critical')
- ->withConsecutive(
- [$validationFailures[0]],
- [$validationFailures[1]]
- );
+ $result = $this->getMockBuilder(ResultInterface::class)
+ ->getMockForAbstractClass();
- $this->command->execute($commandSubject);
+ $this->validator->method('validate')
+ ->with(array_merge($commandSubject, ['response' => $response]))
+ ->willReturn($result);
+ $result->method('isValid')
+ ->willReturn($validationResult);
+ $result->method('getFailsDescription')
+ ->willReturn($validationFailures);
}
}
diff --git a/app/code/Magento/Payment/Test/Unit/Model/Method/FactoryTest.php b/app/code/Magento/Payment/Test/Unit/Model/Method/FactoryTest.php
deleted file mode 100644
index f0cb19ef0fa0f..0000000000000
--- a/app/code/Magento/Payment/Test/Unit/Model/Method/FactoryTest.php
+++ /dev/null
@@ -1,89 +0,0 @@
-_objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
- $this->_factory = $objectManagerHelper->getObject(
- \Magento\Payment\Model\Method\Factory::class,
- ['objectManager' => $this->_objectManagerMock]
- );
- }
-
- public function testCreateMethod()
- {
- $className = \Magento\Payment\Model\Method\AbstractMethod::class;
- $methodMock = $this->createMock($className);
- $this->_objectManagerMock->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- $className,
- []
- )->will(
- $this->returnValue($methodMock)
- );
-
- $this->assertEquals($methodMock, $this->_factory->create($className));
- }
-
- public function testCreateMethodWithArguments()
- {
- $className = \Magento\Payment\Model\Method\AbstractMethod::class;
- $data = ['param1', 'param2'];
- $methodMock = $this->createMock($className);
- $this->_objectManagerMock->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- $className,
- $data
- )->will(
- $this->returnValue($methodMock)
- );
-
- $this->assertEquals($methodMock, $this->_factory->create($className, $data));
- }
-
- /**
- * @expectedException \Magento\Framework\Exception\LocalizedException
- * @expectedExceptionMessage WrongClass class doesn't implement \Magento\Payment\Model\MethodInterface
- */
- public function testWrongTypeException()
- {
- $className = 'WrongClass';
- $methodMock = $this->createMock($className);
- $this->_objectManagerMock->expects(
- $this->once()
- )->method(
- 'create'
- )->with(
- $className,
- []
- )->will(
- $this->returnValue($methodMock)
- );
-
- $this->_factory->create($className);
- }
-}
diff --git a/app/code/Magento/Payment/Test/Unit/Model/Method/Specification/FactoryTest.php b/app/code/Magento/Payment/Test/Unit/Model/Method/Specification/FactoryTest.php
deleted file mode 100644
index 9bdc90829f6fe..0000000000000
--- a/app/code/Magento/Payment/Test/Unit/Model/Method/Specification/FactoryTest.php
+++ /dev/null
@@ -1,71 +0,0 @@
-objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class);
-
- $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
- $this->factory = $objectManagerHelper->getObject(
- \Magento\Payment\Model\Method\Specification\Factory::class,
- ['objectManager' => $this->objectManagerMock]
- );
- }
-
- public function testCreateMethod()
- {
- $className = \Magento\Payment\Model\Method\SpecificationInterface::class;
- $methodMock = $this->createMock($className);
- $this->objectManagerMock->expects(
- $this->once()
- )->method(
- 'get'
- )->with(
- $className
- )->will(
- $this->returnValue($methodMock)
- );
-
- $this->assertEquals($methodMock, $this->factory->create($className));
- }
-
- /**
- * @expectedException \InvalidArgumentException
- * @expectedExceptionMessage Specification must implement SpecificationInterface
- */
- public function testWrongTypeException()
- {
- $className = 'WrongClass';
- $methodMock = $this->createMock($className);
- $this->objectManagerMock->expects(
- $this->once()
- )->method(
- 'get'
- )->with(
- $className
- )->will(
- $this->returnValue($methodMock)
- );
-
- $this->factory->create($className);
- }
-}
diff --git a/app/code/Magento/Payment/composer.json b/app/code/Magento/Payment/composer.json
index d8124f52fb0fc..b8dbf6cd7f16f 100644
--- a/app/code/Magento/Payment/composer.json
+++ b/app/code/Magento/Payment/composer.json
@@ -12,7 +12,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Payment/etc/di.xml b/app/code/Magento/Payment/etc/di.xml
index e2de2244bff89..e62c5e1c1cd4d 100644
--- a/app/code/Magento/Payment/etc/di.xml
+++ b/app/code/Magento/Payment/etc/di.xml
@@ -12,6 +12,7 @@
+
@@ -36,4 +37,29 @@
Magento\Payment\Gateway\Config\Config
+
+
+
+ Magento_Payment
+ error_mapping.xsd
+
+
+
+
+ Magento\Payment\Gateway\ErrorMapper\XmlToArrayConverter
+ Magento\Payment\Gateway\ErrorMapper\VirtualSchemaLocator
+ error_mapping.xml
+
+
+
+
+ Magento\Payment\Gateway\ErrorMapper\VirtualConfigReader
+ payment_error_mapper
+
+
+
+
+ Magento\Payment\Gateway\ErrorMapper\NullMappingData
+
+
diff --git a/app/code/Magento/Payment/etc/error_mapping.xsd b/app/code/Magento/Payment/etc/error_mapping.xsd
new file mode 100644
index 0000000000000..97f3c181beb37
--- /dev/null
+++ b/app/code/Magento/Payment/etc/error_mapping.xsd
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json
index 6e59371da3cd4..8aec470cb65ac 100644
--- a/app/code/Magento/Paypal/composer.json
+++ b/app/code/Magento/Paypal/composer.json
@@ -26,7 +26,7 @@
"magento/module-checkout-agreements": "100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"proprietary"
],
diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json
index 0844358cccb37..d40707a06de8a 100644
--- a/app/code/Magento/ProductVideo/composer.json
+++ b/app/code/Magento/ProductVideo/composer.json
@@ -16,7 +16,7 @@
"magento/module-config": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"proprietary"
],
diff --git a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
index c0036b71ac86a..3104fdc6190dc 100644
--- a/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
+++ b/app/code/Magento/ProductVideo/view/frontend/web/js/fotorama-add-video-events.js
@@ -207,7 +207,7 @@ define([
if (options.dataMergeStrategy === 'prepend') {
this.options.videoData = [].concat(
this.options.optionsVideoData[options.selectedOption],
- this.options.videoData
+ this.defaultVideoData
);
} else {
this.options.videoData = this.options.optionsVideoData[options.selectedOption];
diff --git a/app/code/Magento/Quote/Model/CouponManagement.php b/app/code/Magento/Quote/Model/CouponManagement.php
index 7701e41e0b55a..87398ad36cfab 100644
--- a/app/code/Magento/Quote/Model/CouponManagement.php
+++ b/app/code/Magento/Quote/Model/CouponManagement.php
@@ -50,6 +50,7 @@ public function get($cartId)
*/
public function set($cartId, $couponCode)
{
+ $couponCode = trim($couponCode);
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $this->quoteRepository->getActive($cartId);
if (!$quote->getItemsCount()) {
diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote.php b/app/code/Magento/Quote/Model/ResourceModel/Quote.php
index 9f491b749a812..2645d52c87da5 100644
--- a/app/code/Magento/Quote/Model/ResourceModel/Quote.php
+++ b/app/code/Magento/Quote/Model/ResourceModel/Quote.php
@@ -167,7 +167,7 @@ public function getReservedOrderId($quote)
{
return $this->sequenceManager->getSequence(
\Magento\Sales\Model\Order::ENTITY,
- $quote->getStore()->getGroup()->getDefaultStoreId()
+ $quote->getStoreId()
)
->getNextValue();
}
@@ -211,7 +211,7 @@ public function markQuotesRecollectOnCatalogRules()
* @param \Magento\Catalog\Model\Product $product
* @return $this
*/
- public function substractProductFromQuotes($product)
+ public function subtractProductFromQuotes($product)
{
$productId = (int)$product->getId();
if (!$productId) {
@@ -251,6 +251,21 @@ public function substractProductFromQuotes($product)
return $this;
}
+ /**
+ * Subtract product from all quotes quantities
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ *
+ * @deprecated 101.0.1
+ * @see \Magento\Quote\Model\ResourceModel\Quote::subtractProductFromQuotes
+ *
+ * @return $this
+ */
+ public function substractProductFromQuotes($product)
+ {
+ return $this->subtractProductFromQuotes($product);
+ }
+
/**
* Mark recollect contain product(s) quotes
*
diff --git a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php
index 5161c3a7f01f2..0487d7e46eb26 100644
--- a/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php
+++ b/app/code/Magento/Quote/Model/ResourceModel/Quote/Item/Collection.php
@@ -147,21 +147,6 @@ public function resetJoinQuotes($quotesTableName, $productId = null)
return $this;
}
- /**
- * Join product entities to select existing products items only
- *
- * @return void
- */
- protected function _beforeLoad()
- {
- parent::_beforeLoad();
- $this->join(
- ['cpe' => $this->getResource()->getTable('catalog_product_entity')],
- "cpe.entity_id = main_table.product_id",
- []
- );
- }
-
/**
* After load processing
*
@@ -171,18 +156,20 @@ protected function _afterLoad()
{
parent::_afterLoad();
- /**
- * Assign parent items
- */
+ $productIds = [];
foreach ($this as $item) {
+ // Assign parent items
if ($item->getParentItemId()) {
$item->setParentItem($this->getItemById($item->getParentItemId()));
}
if ($this->_quote) {
$item->setQuote($this->_quote);
}
+ // Collect quote products ids
+ $productIds[] = (int)$item->getProductId();
}
-
+ $this->_productIds = array_merge($this->_productIds, $productIds);
+ $this->removeItemsWithAbsentProducts();
/**
* Assign options and products
*/
@@ -220,12 +207,6 @@ protected function _assignOptions()
protected function _assignProducts()
{
\Magento\Framework\Profiler::start('QUOTE:' . __METHOD__, ['group' => 'QUOTE', 'method' => __METHOD__]);
- $productIds = [];
- foreach ($this as $item) {
- $productIds[] = (int)$item->getProductId();
- }
- $this->_productIds = array_merge($this->_productIds, $productIds);
-
$productCollection = $this->_productCollectionFactory->create()->setStoreId(
$this->getStoreId()
)->addIdFilter(
@@ -320,4 +301,24 @@ private function addTierPriceData(ProductCollection $productCollection)
$productCollection->addTierPriceDataByGroupId($this->_quote->getCustomerGroupId());
}
}
+
+ /**
+ * Find and remove quote items with non existing products
+ *
+ * @return void
+ */
+ private function removeItemsWithAbsentProducts()
+ {
+ $productCollection = $this->_productCollectionFactory->create()->addIdFilter($this->_productIds);
+ $existingProductsIds = $productCollection->getAllIds();
+ $absentProductsIds = array_diff($this->_productIds, $existingProductsIds);
+ // Remove not existing products from items collection
+ if (!empty($absentProductsIds)) {
+ foreach ($absentProductsIds as $productIdToExclude) {
+ /** @var \Magento\Quote\Model\Quote\Item $quoteItem */
+ $quoteItem = $this->getItemByColumnValue('product_id', $productIdToExclude);
+ $this->removeItemByKey($quoteItem->getId());
+ }
+ }
+ }
}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php b/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php
new file mode 100644
index 0000000000000..ab36746da5e73
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/ResourceModel/QuoteTest.php
@@ -0,0 +1,103 @@
+getMockBuilder(Context::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $snapshot = $this->getMockBuilder(Snapshot::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $relationComposite = $this->getMockBuilder(RelationComposite::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->quoteMock = $this->getMockBuilder(Quote::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->sequenceManagerMock = $this->getMockBuilder(Manager::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->sequenceMock = $this->getMockBuilder(SequenceInterface::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->quote = new \Magento\Quote\Model\ResourceModel\Quote(
+ $context,
+ $snapshot,
+ $relationComposite,
+ $this->sequenceManagerMock,
+ null
+ );
+ }
+
+ /**
+ * @param $entityType
+ * @param $storeId
+ * @param $reservedOrderId
+ * @dataProvider getReservedOrderIdDataProvider
+ */
+ public function testGetReservedOrderId($entityType, $storeId, $reservedOrderId)
+ {
+ $this->sequenceManagerMock->expects($this->once())
+ ->method('getSequence')
+ ->with($entityType, $storeId)
+ ->willReturn($this->sequenceMock);
+ $this->quoteMock->expects($this->once())
+ ->method('getStoreId')
+ ->willReturn($storeId);
+ $this->sequenceMock->expects($this->once())
+ ->method('getNextValue')
+ ->willReturn($reservedOrderId);
+
+ $this->assertEquals($reservedOrderId, $this->quote->getReservedOrderId($this->quoteMock));
+ }
+
+ /**
+ * @return array
+ */
+ public function getReservedOrderIdDataProvider(): array
+ {
+ return [
+ [\Magento\Sales\Model\Order::ENTITY, 1, '1000000001'],
+ [\Magento\Sales\Model\Order::ENTITY, 2, '2000000001'],
+ [\Magento\Sales\Model\Order::ENTITY, 3, '3000000001']
+ ];
+ }
+}
diff --git a/app/code/Magento/Quote/composer.json b/app/code/Magento/Quote/composer.json
index a892697802e63..31f875a0f9a35 100644
--- a/app/code/Magento/Quote/composer.json
+++ b/app/code/Magento/Quote/composer.json
@@ -23,7 +23,7 @@
"magento/module-webapi": "100.2.*"
},
"type": "magento2-module",
- "version": "101.0.1",
+ "version": "101.0.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/QuoteAnalytics/composer.json b/app/code/Magento/QuoteAnalytics/composer.json
index abbb0ce7a042b..c75abc5bb5da2 100644
--- a/app/code/Magento/QuoteAnalytics/composer.json
+++ b/app/code/Magento/QuoteAnalytics/composer.json
@@ -3,8 +3,8 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/framework": "100.2.*",
- "magento/module-quote": "100.2.*"
+ "magento/framework": "101.0.*",
+ "magento/module-quote": "101.0.*"
},
"type": "magento2-module",
"version": "100.2.0",
diff --git a/app/code/Magento/ReleaseNotification/composer.json b/app/code/Magento/ReleaseNotification/composer.json
index b338420a2c143..40e9e02db9217 100644
--- a/app/code/Magento/ReleaseNotification/composer.json
+++ b/app/code/Magento/ReleaseNotification/composer.json
@@ -1,24 +1,24 @@
{
- "name": "magento/module-release-notification",
- "description": "N/A",
- "require": {
- "php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/module-user": "101.0.*",
- "magento/module-backend": "100.2.*",
- "magento/framework": "101.0.*"
- },
- "type": "magento2-module",
- "version": "100.2.0",
- "license": [
- "OSL-3.0",
- "AFL-3.0"
- ],
- "autoload": {
- "files": [
- "registration.php"
+ "name": "magento/module-release-notification",
+ "description": "N/A",
+ "require": {
+ "php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
+ "magento/module-user": "101.0.*",
+ "magento/module-backend": "100.2.*",
+ "magento/framework": "101.0.*"
+ },
+ "type": "magento2-module",
+ "version": "100.2.0",
+ "license": [
+ "OSL-3.0",
+ "AFL-3.0"
],
- "psr-4": {
- "Magento\\ReleaseNotification\\": ""
+ "autoload": {
+ "files": [
+ "registration.php"
+ ],
+ "psr-4": {
+ "Magento\\ReleaseNotification\\": ""
+ }
}
- }
}
diff --git a/app/code/Magento/Reports/composer.json b/app/code/Magento/Reports/composer.json
index 1058052dd1122..45514175aa9f1 100644
--- a/app/code/Magento/Reports/composer.json
+++ b/app/code/Magento/Reports/composer.json
@@ -22,7 +22,7 @@
"magento/framework": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json
index 47680b454c29f..608dd51273d2e 100644
--- a/app/code/Magento/Review/composer.json
+++ b/app/code/Magento/Review/composer.json
@@ -18,7 +18,7 @@
"magento/module-review-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/ReviewAnalytics/composer.json b/app/code/Magento/ReviewAnalytics/composer.json
index 965b6294db16a..2c982969a391f 100644
--- a/app/code/Magento/ReviewAnalytics/composer.json
+++ b/app/code/Magento/ReviewAnalytics/composer.json
@@ -3,7 +3,7 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/framework": "100.2.*",
+ "magento/framework": "101.0.*",
"magento/module-review": "100.2.*"
},
"type": "magento2-module",
diff --git a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
index 5ab1379b96cf6..9a6f1b48620dc 100644
--- a/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
+++ b/app/code/Magento/Rule/Model/Condition/Product/AbstractProduct.php
@@ -241,7 +241,9 @@ protected function _prepareValueOptions()
} else {
$addEmptyOption = true;
}
- $selectOptions = $attributeObject->getSource()->getAllOptions($addEmptyOption);
+ $selectOptions = $this->removeTagsFromLabel(
+ $attributeObject->getSource()->getAllOptions($addEmptyOption)
+ );
}
}
@@ -734,4 +736,21 @@ protected function getEavAttributeTableAlias()
return 'at_' . $attribute->getAttributeCode();
}
+
+ /**
+ * Remove html tags from attribute labels.
+ *
+ * @param array $selectOptions
+ * @return array
+ */
+ private function removeTagsFromLabel(array $selectOptions)
+ {
+ foreach ($selectOptions as &$option) {
+ if (isset($option['label'])) {
+ $option['label'] = strip_tags($option['label']);
+ }
+ }
+
+ return $selectOptions;
+ }
}
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Address/Form.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Address/Form.php
index f2b454260dc22..2d23bca110ae2 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Address/Form.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Address/Form.php
@@ -135,4 +135,20 @@ public function getFormValues()
{
return $this->_getAddress()->getData();
}
+
+ /**
+ * @inheritdoc
+ */
+ protected function processCountryOptions(
+ \Magento\Framework\Data\Form\Element\AbstractElement $countryElement,
+ $storeId = null
+ ) {
+ /** @var \Magento\Sales\Model\Order\Address $address */
+ $address = $this->_coreRegistry->registry('order_address');
+ if ($address !== null) {
+ $storeId = $address->getOrder()->getStoreId();
+ }
+
+ parent::processCountryOptions($countryElement, $storeId);
+ }
}
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Address.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Address.php
index 5738e8ee33399..6625f438f9515 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Address.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Address.php
@@ -293,11 +293,17 @@ protected function _prepareForm()
/**
* @param \Magento\Framework\Data\Form\Element\AbstractElement $countryElement
+ * @param string|int $storeId
+ *
* @return void
*/
- private function processCountryOptions(\Magento\Framework\Data\Form\Element\AbstractElement $countryElement)
- {
- $storeId = $this->getBackendQuoteSession()->getStoreId();
+ protected function processCountryOptions(
+ \Magento\Framework\Data\Form\Element\AbstractElement $countryElement,
+ $storeId = null
+ ) {
+ if ($storeId === null) {
+ $storeId = $this->getBackendQuoteSession()->getStoreId();
+ }
$options = $this->getCountriesCollection()
->loadByStore($storeId)
->toOptionArray();
diff --git a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php
index 850e9cf08413b..1a25ff7bfdb80 100644
--- a/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php
+++ b/app/code/Magento/Sales/Model/Order/Pdf/AbstractPdf.php
@@ -953,7 +953,7 @@ public function newPage(array $settings = [])
* feed int; x position (required)
* font string; font style, optional: bold, italic, regular
* font_file string; path to font file (optional for use your custom font)
- * font_size int; font size (default 7)
+ * font_size int; font size (default 10)
* align string; text align (also see feed parametr), optional left, right
* height int;line spacing (default 10)
*
@@ -1005,24 +1005,8 @@ public function drawLineBlocks(\Zend_Pdf_Page $page, array $draw, array $pageSet
foreach ($lines as $line) {
$maxHeight = 0;
foreach ($line as $column) {
- $fontSize = empty($column['font_size']) ? 10 : $column['font_size'];
- if (!empty($column['font_file'])) {
- $font = \Zend_Pdf_Font::fontWithPath($column['font_file']);
- $page->setFont($font, $fontSize);
- } else {
- $fontStyle = empty($column['font']) ? 'regular' : $column['font'];
- switch ($fontStyle) {
- case 'bold':
- $font = $this->_setFontBold($page, $fontSize);
- break;
- case 'italic':
- $font = $this->_setFontItalic($page, $fontSize);
- break;
- default:
- $font = $this->_setFontRegular($page, $fontSize);
- break;
- }
- }
+ $font = $this->setFont($page, $column);
+ $fontSize = $column['font_size'];
if (!is_array($column['text'])) {
$column['text'] = [$column['text']];
@@ -1033,6 +1017,8 @@ public function drawLineBlocks(\Zend_Pdf_Page $page, array $draw, array $pageSet
foreach ($column['text'] as $part) {
if ($this->y - $lineSpacing < 15) {
$page = $this->newPage($pageSettings);
+ $font = $this->setFont($page, $column);
+ $fontSize = $column['font_size'];
}
$feed = $column['feed'];
@@ -1066,4 +1052,42 @@ public function drawLineBlocks(\Zend_Pdf_Page $page, array $draw, array $pageSet
return $page;
}
+
+ /**
+ * Set page font.
+ *
+ * column array format
+ * font string; font style, optional: bold, italic, regular
+ * font_file string; path to font file (optional for use your custom font)
+ * font_size int; font size (default 10)
+ *
+ * @param \Zend_Pdf_Page $page
+ * @param array $column
+ * @return \Zend_Pdf_Resource_Font
+ * @throws \Zend_Pdf_Exception
+ */
+ private function setFont($page, &$column)
+ {
+ $fontSize = empty($column['font_size']) ? 10 : $column['font_size'];
+ $column['font_size'] = $fontSize;
+ if (!empty($column['font_file'])) {
+ $font = \Zend_Pdf_Font::fontWithPath($column['font_file']);
+ $page->setFont($font, $fontSize);
+ } else {
+ $fontStyle = empty($column['font']) ? 'regular' : $column['font'];
+ switch ($fontStyle) {
+ case 'bold':
+ $font = $this->_setFontBold($page, $fontSize);
+ break;
+ case 'italic':
+ $font = $this->_setFontItalic($page, $fontSize);
+ break;
+ default:
+ $font = $this->_setFontRegular($page, $fontSize);
+ break;
+ }
+ }
+
+ return $font;
+ }
}
diff --git a/app/code/Magento/Sales/Observer/Backend/SubtractQtyFromQuotesObserver.php b/app/code/Magento/Sales/Observer/Backend/SubtractQtyFromQuotesObserver.php
index 775a7dab95cfe..cd8c705750d6c 100644
--- a/app/code/Magento/Sales/Observer/Backend/SubtractQtyFromQuotesObserver.php
+++ b/app/code/Magento/Sales/Observer/Backend/SubtractQtyFromQuotesObserver.php
@@ -31,6 +31,6 @@ public function __construct(\Magento\Quote\Model\ResourceModel\Quote $quote)
public function execute(\Magento\Framework\Event\Observer $observer)
{
$product = $observer->getEvent()->getProduct();
- $this->_quote->substractProductFromQuotes($product);
+ $this->_quote->subtractProductFromQuotes($product);
}
}
diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php
index 1c36a9a538366..16455d616d853 100644
--- a/app/code/Magento/Sales/Setup/UpgradeData.php
+++ b/app/code/Magento/Sales/Setup/UpgradeData.php
@@ -108,6 +108,14 @@ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface
[$setup]
);
}
+ if (version_compare($context->getVersion(), '2.0.9', '<')) {
+ //Correct wrong source model for "invoice" entity type, introduced by mistake in 2.0.1 upgrade.
+ $salesSetup->updateEntityType(
+ 'invoice',
+ 'entity_model',
+ \Magento\Sales\Model\ResourceModel\Order\Invoice::class
+ );
+ }
$this->eavConfig->clear();
}
diff --git a/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Address/FormTest.php b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Address/FormTest.php
new file mode 100644
index 0000000000000..8a11717c95420
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Unit/Block/Adminhtml/Order/Address/FormTest.php
@@ -0,0 +1,92 @@
+formFactoryMock = $this->createMock(\Magento\Framework\Data\FormFactory::class);
+ $this->customerFormFactoryMock = $this->createMock(\Magento\Customer\Model\Metadata\FormFactory::class);
+ $this->coreRegistryMock = $this->createMock(\Magento\Framework\Registry::class);
+ $this->countriesCollection = $this->createMock(
+ \Magento\Directory\Model\ResourceModel\Country\Collection::class
+ );
+
+ $this->addressBlock = $objectManager->getObject(
+ \Magento\Sales\Block\Adminhtml\Order\Address\Form::class,
+ [
+ '_formFactory' => $this->formFactoryMock,
+ '_customerFormFactory' => $this->customerFormFactoryMock,
+ '_coreRegistry' => $this->coreRegistryMock,
+ 'countriesCollection' => $this->countriesCollection,
+ ]
+ );
+ }
+
+ public function testGetForm()
+ {
+ $formMock = $this->createMock(\Magento\Framework\Data\Form::class);
+ $fieldsetMock = $this->createMock(\Magento\Framework\Data\Form\Element\Fieldset::class);
+ $addressFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class);
+ $addressMock = $this->createMock(\Magento\Sales\Model\Order\Address::class);
+ $selectMock = $this->createMock(\Magento\Framework\Data\Form\Element\Select::class);
+ $orderMock = $this->createMock(\Magento\Sales\Model\Order::class);
+
+ $this->formFactoryMock->expects($this->atLeastOnce())->method('create')->willReturn($formMock);
+ $formMock->expects($this->atLeastOnce())->method('addFieldset')->willReturn($fieldsetMock);
+ $this->customerFormFactoryMock->expects($this->atLeastOnce())->method('create')->willReturn($addressFormMock);
+ $addressFormMock->expects($this->atLeastOnce())->method('getAttributes')->willReturn([]);
+ $this->coreRegistryMock->expects($this->atLeastOnce())->method('registry')->willReturn($addressMock);
+ $formMock->expects($this->atLeastOnce())->method('getElement')->willReturnOnConsecutiveCalls(
+ $selectMock,
+ $selectMock,
+ $selectMock,
+ $selectMock,
+ $selectMock,
+ $selectMock,
+ $selectMock,
+ null
+ );
+ $addressMock->expects($this->once())->method('getOrder')->willReturn($orderMock);
+ $orderMock->expects($this->once())->method('getStoreId')->willReturn(5);
+ $this->countriesCollection->expects($this->atLeastOnce())->method('loadByStore')
+ ->willReturn($this->countriesCollection);
+
+ $this->addressBlock->getForm();
+ }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Observer/Backend/SubtractQtyFromQuotesObserverTest.php b/app/code/Magento/Sales/Test/Unit/Observer/Backend/SubtractQtyFromQuotesObserverTest.php
index a6a828c888fc0..6b94605108866 100644
--- a/app/code/Magento/Sales/Test/Unit/Observer/Backend/SubtractQtyFromQuotesObserverTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Observer/Backend/SubtractQtyFromQuotesObserverTest.php
@@ -15,12 +15,12 @@ class SubtractQtyFromQuotesObserverTest extends \PHPUnit\Framework\TestCase
protected $_model;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Quote\Model\ResourceModel\Quote|\PHPUnit_Framework_MockObject_MockObject
*/
protected $_quoteMock;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject
*/
protected $_observerMock;
@@ -48,7 +48,7 @@ public function testSubtractQtyFromQuotes()
['getId', 'getStatus', '__wakeup']
);
$this->_eventMock->expects($this->once())->method('getProduct')->will($this->returnValue($productMock));
- $this->_quoteMock->expects($this->once())->method('substractProductFromQuotes')->with($productMock);
+ $this->_quoteMock->expects($this->once())->method('subtractProductFromQuotes')->with($productMock);
$this->_model->execute($this->_observerMock);
}
}
diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json
index 9761f82d1894a..5468f1dad5f06 100644
--- a/app/code/Magento/Sales/composer.json
+++ b/app/code/Magento/Sales/composer.json
@@ -32,7 +32,7 @@
"magento/module-sales-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "101.0.1",
+ "version": "101.0.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml
index 58c7a4f21202a..b234cdad876cc 100644
--- a/app/code/Magento/Sales/etc/module.xml
+++ b/app/code/Magento/Sales/etc/module.xml
@@ -6,7 +6,7 @@
*/
-->
-
+
diff --git a/app/code/Magento/SalesAnalytics/composer.json b/app/code/Magento/SalesAnalytics/composer.json
index 344971d7056cf..e1e60bed3bd53 100644
--- a/app/code/Magento/SalesAnalytics/composer.json
+++ b/app/code/Magento/SalesAnalytics/composer.json
@@ -3,8 +3,8 @@
"description": "N/A",
"require": {
"php": "7.0.2|7.0.4|~7.0.6|~7.1.0",
- "magento/framework": "100.2.*",
- "magento/module-sales": "100.2.*"
+ "magento/framework": "101.0.*",
+ "magento/module-sales": "101.0.*"
},
"type": "magento2-module",
"version": "100.2.0",
diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json
index 2b142135271d2..b84eb3b0682dc 100644
--- a/app/code/Magento/SalesRule/composer.json
+++ b/app/code/Magento/SalesRule/composer.json
@@ -25,7 +25,7 @@
"magento/module-sales-rule-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "101.0.0",
+ "version": "101.0.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/SampleData/composer.json b/app/code/Magento/SampleData/composer.json
index 57d69977afb1c..9c2c84a1365e9 100644
--- a/app/code/Magento/SampleData/composer.json
+++ b/app/code/Magento/SampleData/composer.json
@@ -9,7 +9,7 @@
"magento/sample-data-media": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Search/Block/Term.php b/app/code/Magento/Search/Block/Term.php
index d92ba03bfcff8..ee62129051b97 100644
--- a/app/code/Magento/Search/Block/Term.php
+++ b/app/code/Magento/Search/Block/Term.php
@@ -95,8 +95,8 @@ protected function _loadTerms()
continue;
}
$term->setRatio(($term->getPopularity() - $this->_minPopularity) / $range);
- $temp[$term->getName()] = $term;
- $termKeys[] = $term->getName();
+ $temp[$term->getData('query_text')] = $term;
+ $termKeys[] = $term->getData('query_text');
}
natcasesort($termKeys);
@@ -128,7 +128,7 @@ public function getSearchUrl($obj)
* url encoding will be done in Url.php http_build_query
* so no need to explicitly called urlencode for the text
*/
- $url->setQueryParam('q', $obj->getName());
+ $url->setQueryParam('q', $obj->getData('query_text'));
return $url->getUrl('catalogsearch/result');
}
diff --git a/app/code/Magento/Search/composer.json b/app/code/Magento/Search/composer.json
index c6aecd101fc6f..5dc05010c525a 100644
--- a/app/code/Magento/Search/composer.json
+++ b/app/code/Magento/Search/composer.json
@@ -11,7 +11,7 @@
"magento/module-ui": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Search/view/frontend/templates/term.phtml b/app/code/Magento/Search/view/frontend/templates/term.phtml
index 4285b42fa0329..8acee0cf3d408 100644
--- a/app/code/Magento/Search/view/frontend/templates/term.phtml
+++ b/app/code/Magento/Search/view/frontend/templates/term.phtml
@@ -13,7 +13,7 @@
- = $block->escapeHtml($_term->getName()) ?>
+ = $block->escapeHtml($_term->getData('query_text')) ?>
diff --git a/app/code/Magento/Shipping/Helper/Data.php b/app/code/Magento/Shipping/Helper/Data.php
index 78e23cb4aeac2..dd0933b5a340e 100644
--- a/app/code/Magento/Shipping/Helper/Data.php
+++ b/app/code/Magento/Shipping/Helper/Data.php
@@ -11,6 +11,10 @@
*/
namespace Magento\Shipping\Helper;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\UrlInterface;
+use Magento\Store\Model\StoreManagerInterface;
+
class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
/**
@@ -21,19 +25,28 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
protected $_allowedHashKeys = ['ship_id', 'order_id', 'track_id'];
/**
- * @var \Magento\Store\Model\StoreManagerInterface
+ * @var StoreManagerInterface
*/
protected $_storeManager;
+ /**
+ * @var UrlInterface|null
+ */
+ private $url;
+
/**
* @param \Magento\Framework\App\Helper\Context $context
- * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+ * @param StoreManagerInterface $storeManager
+ * @param UrlInterface|null $url
*/
public function __construct(
\Magento\Framework\App\Helper\Context $context,
- \Magento\Store\Model\StoreManagerInterface $storeManager
+ StoreManagerInterface $storeManager,
+ UrlInterface $url = null
) {
$this->_storeManager = $storeManager;
+ $this->url = $url ?: ObjectManager::getInstance()->get(UrlInterface::class);
+
parent::__construct($context);
}
@@ -64,12 +77,13 @@ protected function _getTrackingUrl($key, $model, $method = 'getId')
{
$urlPart = "{$key}:{$model->{$method}()}:{$model->getProtectCode()}";
$params = [
+ '_scope' => $model->getStoreId(),
+ '_nosid' => true,
'_direct' => 'shipping/tracking/popup',
'_query' => ['hash' => $this->urlEncoder->encode($urlPart)]
];
- $storeModel = $this->_storeManager->getStore($model->getStoreId());
- return $storeModel->getUrl('', $params);
+ return $this->url->getUrl('', $params);
}
/**
diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json
index a7a2a3d48b06e..25766e8a45e31 100644
--- a/app/code/Magento/Shipping/composer.json
+++ b/app/code/Magento/Shipping/composer.json
@@ -25,7 +25,7 @@
"magento/module-config": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Shipping/etc/adminhtml/di.xml b/app/code/Magento/Shipping/etc/adminhtml/di.xml
index 54d5d9664e66f..36bd1ae9d3505 100644
--- a/app/code/Magento/Shipping/etc/adminhtml/di.xml
+++ b/app/code/Magento/Shipping/etc/adminhtml/di.xml
@@ -7,4 +7,11 @@
-->
+
+
+
+
+ Magento\Framework\Url
+
+
diff --git a/app/code/Magento/Sitemap/Model/Sitemap.php b/app/code/Magento/Sitemap/Model/Sitemap.php
index f6a5f029eafca..cad8023bd2794 100644
--- a/app/code/Magento/Sitemap/Model/Sitemap.php
+++ b/app/code/Magento/Sitemap/Model/Sitemap.php
@@ -273,6 +273,7 @@ public function collectSitemapItems()
/** @var $helper \Magento\Sitemap\Helper\Data */
$helper = $this->_sitemapData;
$storeId = $this->getStoreId();
+ $this->_storeManager->setCurrentStore($storeId);
$this->addSitemapItem(new DataObject(
[
diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php
index 83210c5789776..4f55653fad311 100644
--- a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php
+++ b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php
@@ -253,6 +253,8 @@ public function testGenerateXml($maxLines, $maxFileSize, $expectedFile, $expecte
$expectedWrites,
null
);
+ $this->storeManagerMock->expects($this->once())->method('setCurrentStore')->with(1);
+
$model->generateXml();
$this->assertCount(count($expectedFile), $actualData, 'Number of generated files is incorrect');
@@ -360,6 +362,8 @@ public function testAddSitemapToRobotsTxt($maxLines, $maxFileSize, $expectedFile
$expectedWrites,
$robotsInfo
);
+ $this->storeManagerMock->expects($this->once())->method('setCurrentStore')->with(1);
+
$model->generateXml();
}
diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json
index 88be3616eebd0..678e6f5fe198e 100644
--- a/app/code/Magento/Sitemap/composer.json
+++ b/app/code/Magento/Sitemap/composer.json
@@ -18,7 +18,7 @@
"magento/module-config": "101.0.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Store/App/Request/PathInfoProcessor.php b/app/code/Magento/Store/App/Request/PathInfoProcessor.php
index a38ea6d1272e8..3fa78dc94aa35 100644
--- a/app/code/Magento/Store/App/Request/PathInfoProcessor.php
+++ b/app/code/Magento/Store/App/Request/PathInfoProcessor.php
@@ -44,7 +44,7 @@ public function process(\Magento\Framework\App\RequestInterface $request, $pathI
if ($store->isUseStoreInUrl()) {
if (!$request->isDirectAccessFrontendName($storeCode) && $storeCode != Store::ADMIN_CODE) {
- $this->storeManager->setCurrentStore($storeCode);
+ $this->storeManager->setCurrentStore($store->getCode());
$pathInfo = '/' . (isset($pathParts[1]) ? $pathParts[1] : '');
return $pathInfo;
} elseif (!empty($storeCode)) {
diff --git a/app/code/Magento/Store/Test/Unit/App/Request/PathInfoProcessorTest.php b/app/code/Magento/Store/Test/Unit/App/Request/PathInfoProcessorTest.php
index f2bd401cea3fb..7d2fb54014967 100644
--- a/app/code/Magento/Store/Test/Unit/App/Request/PathInfoProcessorTest.php
+++ b/app/code/Magento/Store/Test/Unit/App/Request/PathInfoProcessorTest.php
@@ -47,6 +47,7 @@ public function testProcessIfStoreExistsAndIsNotDirectAcccessToFrontName()
)->with(
'storeCode'
)->willReturn($store);
+ $store->expects($this->once())->method('getCode')->will($this->returnValue('storeCode'));
$store->expects($this->once())->method('isUseStoreInUrl')->will($this->returnValue(true));
$this->_requestMock->expects(
$this->once()
diff --git a/app/code/Magento/Store/composer.json b/app/code/Magento/Store/composer.json
index f9eb84e2f9fa1..b3bbb680bcd78 100644
--- a/app/code/Magento/Store/composer.json
+++ b/app/code/Magento/Store/composer.json
@@ -14,7 +14,7 @@
"magento/module-deploy": "100.2.*"
},
"type": "magento2-module",
- "version": "100.2.1",
+ "version": "100.2.2",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json
index 6efeb62a23b78..65ba7251f45d0 100644
--- a/app/code/Magento/Swatches/composer.json
+++ b/app/code/Magento/Swatches/composer.json
@@ -19,7 +19,7 @@
"magento/module-swatches-sample-data": "Sample Data version:100.2.*"
},
"type": "magento2-module",
- "version": "100.2.0",
+ "version": "100.2.1",
"license": [
"proprietary"
],
diff --git a/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml b/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml
index 4152c06fa3ddc..2fdf5f3cd0ea9 100644
--- a/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml
+++ b/app/code/Magento/Swatches/view/adminhtml/ui_component/product_attribute_add_form.xml
@@ -87,7 +87,6 @@
true
- text_swatch
dynamicRows
@@ -96,8 +95,6 @@
- true
- true
- container
- - text_swatch.position
-
@@ -183,15 +180,11 @@
-
- true
-
text
false
- position
-
+
-
- true
@@ -227,7 +220,6 @@
true
true
- visual_swatch
dynamicRows
@@ -236,8 +228,6 @@
- true
- true
- container
- - text_swatch.position
-
@@ -276,7 +266,6 @@
true
- swatchvisual
@@ -290,7 +279,6 @@
text
- optionvisual_default_store_view
@@ -304,7 +292,6 @@
text
- optionvisual_admin
@@ -315,15 +302,10 @@
-
- true
-
- text
- false
- position
+ false
-
+
-
- true
diff --git a/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js b/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js
index e63c9a2138a36..2fbce5aefbdeb 100644
--- a/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js
+++ b/app/code/Magento/Swatches/view/adminhtml/web/js/form/element/swatch-visual.js
@@ -305,18 +305,30 @@ define([
*/
initialize: function () {
this._super()
- .initOldCode();
+ .initOldCode()
+ .on('value', this.onChangeColor.bind(this));
return this;
},
+ /**
+ * Handler function that execute when color changes.
+ *
+ * @param {String} data - color
+ */
+ onChangeColor: function (data) {
+ if (!data) {
+ jQuery('.' + this.elementName).parent().removeClass('unavailable');
+ }
+ },
+
/**
* Initialize wrapped former implementation.
*
* @returns {Object} Chainable.
*/
initOldCode: function () {
- jQuery.async('.' + this.elementName, function (elem) {
+ jQuery.async('.' + this.elementName, this.name, function (elem) {
oldCode(this.value(), elem.parentElement, this.uploadUrl, this.elementName);
}.bind(this));
@@ -336,9 +348,15 @@ define([
this.elementName = this.prefixElementName + recordId;
this.inputName = prefixName + '[' + this.elementName + ']';
- this.dataScope = 'data.' + this.prefixName + '.' + this.elementName;
+ this.exportDataLink = 'data.' + this.prefixName + '.' + this.elementName;
+ this.exports.value = this.provider + ':' + this.exportDataLink;
+ },
+
+ /** @inheritdoc */
+ destroy: function () {
+ this._super();
- this.links.value = this.provider + ':' + this.dataScope;
+ this.source.remove(this.exportDataLink);
},
/**
diff --git a/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html b/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html
index 271cea918b7be..8296e944a8ed3 100644
--- a/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html
+++ b/app/code/Magento/Swatches/view/adminhtml/web/template/swatch-visual.html
@@ -11,7 +11,7 @@
},
value: value
"/>
-
+