diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml index c9680034e1e21..3f15701216005 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml @@ -53,9 +53,7 @@ diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js index ab46c78c6f6e7..4e2fbdc5dfa50 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js @@ -11,13 +11,18 @@ define([], function () { */ return function (addressData) { var identifier = Date.now(); + var regionId = null; + + if (addressData.region && addressData.region.region_id) { + regionId = addressData.region.region_id; + } else if (addressData.country_id && addressData.country_id == window.checkoutConfig.defaultCountryId) { + regionId = window.checkoutConfig.defaultRegionId; + } return { email: addressData.email, countryId: (addressData.country_id) ? addressData.country_id : window.checkoutConfig.defaultCountryId, - regionId: (addressData.region && addressData.region.region_id) ? - addressData.region.region_id - : window.checkoutConfig.defaultRegionId, + regionId: regionId, regionCode: (addressData.region) ? addressData.region.region_code : null, region: (addressData.region) ? addressData.region.region : null, customerId: addressData.customer_id, diff --git a/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php b/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php new file mode 100644 index 0000000000000..49d9be6bcf8ff --- /dev/null +++ b/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php @@ -0,0 +1,40 @@ +quoteItemsCleaner = $quoteItemsCleaner; + } + + /** + * @param \Magento\Catalog\Model\ResourceModel\Product $subject + * @param \Closure $proceed + * @param \Magento\Catalog\Api\Data\ProductInterface $product + * @return mixed + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * TODO: reimplement with after plugin + */ + public function aroundDelete( + \Magento\Catalog\Model\ResourceModel\Product $subject, + \Closure $proceed, + \Magento\Catalog\Api\Data\ProductInterface $product + ) { + $result = $proceed($product); + $this->quoteItemsCleaner->execute($product); + return $result; + } +} diff --git a/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php b/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php new file mode 100644 index 0000000000000..ec0e6809c48f7 --- /dev/null +++ b/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php @@ -0,0 +1,33 @@ +itemResource = $itemResource; + } + + /** + * {@inheritdoc} + */ + public function execute(\Magento\Catalog\Api\Data\ProductInterface $product) + { + $this->itemResource->getConnection()->delete( + $this->itemResource->getMainTable(), + 'product_id = ' . $product->getId() + ); + } +} diff --git a/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php b/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php new file mode 100644 index 0000000000000..1691efab5e541 --- /dev/null +++ b/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php @@ -0,0 +1,17 @@ +getTable('quote_item'), 'item_id', \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - )->addForeignKey( - $installer->getFkName('quote_item', 'product_id', 'catalog_product_entity', 'entity_id'), - 'product_id', - $installer->getTable('catalog_product_entity'), - 'entity_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE )->addForeignKey( $installer->getFkName('quote_item', 'quote_id', 'quote', 'entity_id'), 'quote_id', diff --git a/app/code/Magento/Quote/Setup/Recurring.php b/app/code/Magento/Quote/Setup/Recurring.php deleted file mode 100644 index 03fe30bf80272..0000000000000 --- a/app/code/Magento/Quote/Setup/Recurring.php +++ /dev/null @@ -1,73 +0,0 @@ -metadataPool = $metadataPool; - $this->externalFKSetup = $externalFKSetup; - } - - /** - * {@inheritdoc} - */ - public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) - { - $installer = $setup; - $installer->startSetup(); - - $this->addExternalForeignKeys($installer); - - $installer->endSetup(); - } - - /** - * Add external foreign keys - * - * @param SchemaSetupInterface $installer - * @return void - * @throws \Exception - */ - protected function addExternalForeignKeys(SchemaSetupInterface $installer) - { - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - $this->externalFKSetup->install( - $installer, - $metadata->getEntityTable(), - $metadata->getIdentifierField(), - 'quote_item', - 'product_id' - ); - } -} diff --git a/app/code/Magento/Quote/Setup/UpgradeSchema.php b/app/code/Magento/Quote/Setup/UpgradeSchema.php index 602f93e0445f0..d2163035bdcbf 100644 --- a/app/code/Magento/Quote/Setup/UpgradeSchema.php +++ b/app/code/Magento/Quote/Setup/UpgradeSchema.php @@ -41,7 +41,15 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con ] ); } - + //drop foreign key for single DB case + if (version_compare($context->getVersion(), '2.0.3', '<') + && $setup->tableExists($setup->getTable('quote_item')) + ) { + $setup->getConnection()->dropForeignKey( + $setup->getTable('quote_item'), + $setup->getFkName('quote_item', 'product_id', 'catalog_product_entity', 'entity_id') + ); + } $setup->endSetup(); } } diff --git a/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php new file mode 100644 index 0000000000000..083722f3a1bb3 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php @@ -0,0 +1,38 @@ +quoteItemsCleanerMock = $this->getMock(\Magento\Quote\Model\Product\QuoteItemsCleanerInterface::class); + $this->model = new \Magento\Quote\Model\Product\Plugin\RemoveQuoteItems($this->quoteItemsCleanerMock); + } + + public function testAroundDelete() + { + $productResourceMock = $this->getMock(\Magento\Catalog\Model\ResourceModel\Product::class, [], [], '', false); + $productMock = $this->getMock(\Magento\Catalog\Api\Data\ProductInterface::class); + $closure = function () use ($productResourceMock) { + return $productResourceMock; + }; + + $this->quoteItemsCleanerMock->expects($this->once())->method('execute')->with($productMock); + $result = $this->model->aroundDelete($productResourceMock, $closure, $productMock); + $this->assertEquals($result, $productResourceMock); + } +} diff --git a/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php b/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php new file mode 100644 index 0000000000000..d6bb3e5ae31a8 --- /dev/null +++ b/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php @@ -0,0 +1,45 @@ +itemResourceMock = $this->getMock( + \Magento\Quote\Model\ResourceModel\Quote\Item::class, + [], + [], + '', + false + ); + $this->model = new \Magento\Quote\Model\Product\QuoteItemsCleaner($this->itemResourceMock); + } + + public function testExecute() + { + $tableName = 'table_name'; + $productMock = $this->getMock(\Magento\Catalog\Api\Data\ProductInterface::class); + $productMock->expects($this->once())->method('getId')->willReturn(1); + + $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + $this->itemResourceMock->expects($this->once())->method('getConnection')->willReturn($connectionMock); + $this->itemResourceMock->expects($this->once())->method('getMainTable')->willReturn($tableName); + + $connectionMock->expects($this->once())->method('delete')->with($tableName, 'product_id = 1'); + $this->model->execute($productMock); + } +} diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml index e3192f1c1d58e..384f5ca143b86 100644 --- a/app/code/Magento/Quote/etc/di.xml +++ b/app/code/Magento/Quote/etc/di.xml @@ -40,7 +40,6 @@ - @@ -90,4 +89,8 @@ + + + + diff --git a/app/code/Magento/Quote/etc/module.xml b/app/code/Magento/Quote/etc/module.xml index 8350b4c4f87ea..281cde9eeb9d1 100644 --- a/app/code/Magento/Quote/etc/module.xml +++ b/app/code/Magento/Quote/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php index 907d782e8deaf..34e7c29b6c6a0 100644 --- a/app/code/Magento/Sales/Setup/UpgradeSchema.php +++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php @@ -4,6 +4,8 @@ * See COPYING.txt for license details. */ namespace Magento\Sales\Setup; + +use Magento\Framework\App\ResourceConnection; use Magento\Framework\Setup\UpgradeSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; @@ -14,6 +16,11 @@ */ class UpgradeSchema implements UpgradeSchemaInterface { + /** + * @var AdapterInterface + */ + private $salesConnection; + /** * {@inheritdoc} */ @@ -30,7 +37,8 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con 'sales_bestsellers_aggregated_daily', 'product_id', 'catalog_product_entity', - 'entity_id') + 'entity_id' + ) ); //sales_bestsellers_aggregated_monthly $connection->dropForeignKey( @@ -39,7 +47,8 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con 'sales_bestsellers_aggregated_monthly', 'product_id', 'catalog_product_entity', - 'entity_id') + 'entity_id' + ) ); //sales_bestsellers_aggregated_yearly @@ -49,7 +58,8 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con 'sales_bestsellers_aggregated_yearly', 'product_id', 'catalog_product_entity', - 'entity_id') + 'entity_id' + ) ); $installer->endSetup(); @@ -66,7 +76,7 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con */ private function addColumnBaseGrandTotal(SchemaSetupInterface $installer) { - $connection = $installer->getConnection(); + $connection = $this->getSalesConnection(); $connection->addColumn( $installer->getTable('sales_invoice_grid'), 'base_grand_total', @@ -86,11 +96,29 @@ private function addColumnBaseGrandTotal(SchemaSetupInterface $installer) */ private function addIndexBaseGrandTotal(SchemaSetupInterface $installer) { - $connection = $installer->getConnection(); + $connection = $this->getSalesConnection(); $connection->addIndex( $installer->getTable('sales_invoice_grid'), $installer->getIdxName('sales_invoice_grid', ['base_grand_total']), ['base_grand_total'] ); } + + /** + * @return AdapterInterface + */ + private function getSalesConnection() + { + if ($this->salesConnection === null) { + $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); + /** @var ResourceConnection $resourceConnection */ + $resourceConnection = $objectManager->get(ResourceConnection::class); + try { + $this->salesConnection = $resourceConnection->getConnectionByName('sales'); + } catch (\DomainException $e) { + $this->salesConnection = $resourceConnection->getConnection(); + } + } + return $this->salesConnection; + } } diff --git a/app/code/Magento/Tax/Model/TaxConfigProvider.php b/app/code/Magento/Tax/Model/TaxConfigProvider.php index a56663a8d558a..95f371da1726a 100644 --- a/app/code/Magento/Tax/Model/TaxConfigProvider.php +++ b/app/code/Magento/Tax/Model/TaxConfigProvider.php @@ -55,6 +55,14 @@ public function __construct( */ public function getConfig() { + $defaultRegionId = $this->scopeConfig->getValue( + \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_REGION, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + // prevent wrong assignment on shipping rate estimation requests + if (0 == $defaultRegionId) { + $defaultRegionId = null; + } return [ 'isDisplayShippingPriceExclTax' => $this->isDisplayShippingPriceExclTax(), 'isDisplayShippingBothPrices' => $this->isDisplayShippingBothPrices(), @@ -69,10 +77,7 @@ public function getConfig() \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_COUNTRY, \Magento\Store\Model\ScopeInterface::SCOPE_STORE ), - 'defaultRegionId' => $this->scopeConfig->getValue( - \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_REGION, - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ), + 'defaultRegionId' => $defaultRegionId, 'defaultPostcode' => $this->scopeConfig->getValue( \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_POSTCODE, \Magento\Store\Model\ScopeInterface::SCOPE_STORE diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php index 0cb720329c134..0ce7a40a5d1db 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php @@ -302,6 +302,35 @@ public function getConfigDataProvider() Config::CONFIG_XML_PATH_DEFAULT_POSTCODE => '*', ], ], + 'zeroRegionToNull' => [ + 'expectedResult' => [ + 'isDisplayShippingPriceExclTax' => 1, + 'isDisplayShippingBothPrices' => 1, + 'reviewShippingDisplayMode' => 'excluding', + 'reviewItemPriceDisplayMode' => 'including', + 'reviewTotalsDisplayMode' => 'both', + 'includeTaxInGrandTotal' => 1, + 'isFullTaxSummaryDisplayed' => 1, + 'isZeroTaxDisplayed' => 1, + 'reloadOnBillingAddress' => false, + 'defaultCountryId' => 'US', + 'defaultRegionId' => null, + 'defaultPostcode' => '*', + ], + 'cartShippingBoth' => 0, + 'cartShippingExclTax' => 1, + 'cartBothPrices' => 0, + 'cartPriceExclTax' => 0, + 'cartSubTotalBoth' => 1, + 'cartSubTotalExclTax' => 0, + 'isQuoteVirtual' => false, + 'config' => [ + Config::CONFIG_XML_PATH_BASED_ON => 'shipping', + Config::CONFIG_XML_PATH_DEFAULT_COUNTRY => 'US', + Config::CONFIG_XML_PATH_DEFAULT_REGION => 0, + Config::CONFIG_XML_PATH_DEFAULT_POSTCODE => '*', + ], + ], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php index d3ea0ce15eb68..5a5b1d5c4dbde 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php @@ -107,6 +107,13 @@ try { $productToDelete = $productRepository->getById(1); $productRepository->delete($productToDelete); + + /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */ + $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class); + $itemResource->getConnection()->delete( + $itemResource->getMainTable(), + 'product_id = ' . $productToDelete->getId() + ); } catch (\Exception $e) { // Nothing to remove } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index 6184dd7ee4355..78342c886de96 100755 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -4225,4 +4225,5 @@ ['Magento\Catalog\Test\Unit\Webapi\Product\Option\Type\File\ValidatorTest'], ['Magento\Framework\Search\Document', 'Magento\Framework\Api\Search\Document'], ['Magento\Framework\Search\DocumentField'], + ['Magento\Quote\Setup\Recurring'], ];