From 56eee0a9844ed31fbc151e2f84a838466683b956 Mon Sep 17 00:00:00 2001 From: Yurii Borysov Date: Thu, 6 Sep 2018 17:52:44 +0300 Subject: [PATCH 001/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information --- .../Order/View/Info/PaymentDetails.php | 26 +++++++++++++++++++ .../Magento/Authorizenet/Model/Directpost.php | 12 +++++++-- app/code/Magento/Authorizenet/etc/config.xml | 1 + app/code/Magento/Authorizenet/etc/di.xml | 5 ++++ app/code/Magento/Authorizenet/i18n/en_US.csv | 5 ++++ 5 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php new file mode 100644 index 0000000000000..40bd0f293a5fd --- /dev/null +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -0,0 +1,26 @@ +setIsTransactionPending(true) ->setIsFraudDetected(true); } + + $additionalInformationKeys = explode(',', $this->getValue('paymentInfoKeys')); + foreach ($additionalInformationKeys as $paymentInfoKey) { + $paymentInfoValue = $response->getDataByKey($paymentInfoKey); + if($paymentInfoValue !== null) { + $payment->setAdditionalInformation($paymentInfoKey, $paymentInfoValue); + } + } } /** @@ -918,7 +926,7 @@ public function fetchTransactionInfo(\Magento\Payment\Model\InfoInterface $payme $payment->setIsTransactionDenied(true); } $this->addStatusCommentOnUpdate($payment, $response, $transactionId); - return []; + return $response->getData(); } /** diff --git a/app/code/Magento/Authorizenet/etc/config.xml b/app/code/Magento/Authorizenet/etc/config.xml index eacf77cda1e77..3a192646b6f7e 100644 --- a/app/code/Magento/Authorizenet/etc/config.xml +++ b/app/code/Magento/Authorizenet/etc/config.xml @@ -32,6 +32,7 @@ https://secure.authorize.net/gateway/transact.dll https://apitest.authorize.net/xml/v1/request.api https://api2.authorize.net/xml/v1/request.api + x_card_type,x_account_number,x_avs_code,x_auth_code,x_response_reason_text,x_cvv2_resp_code diff --git a/app/code/Magento/Authorizenet/etc/di.xml b/app/code/Magento/Authorizenet/etc/di.xml index 4beb2456be110..69d24019f2fb7 100644 --- a/app/code/Magento/Authorizenet/etc/di.xml +++ b/app/code/Magento/Authorizenet/etc/di.xml @@ -35,4 +35,9 @@ + + + Magento\Authorizenet\Model\Directpost + + diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index bb59afffff2c6..eb22bc4fad311 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -67,3 +67,8 @@ Debug,Debug "Minimum Order Total","Minimum Order Total" "Maximum Order Total","Maximum Order Total" "Sort Order","Sort Order" +"x_card_type","Credit Card Type" +"x_account_number", "Credit Card Number" +"x_avs_code","AVS Response Code" +"x_auth_code","Processor Authentication Code" +"x_response_reason_text","Processor Response Text" From 87bc13a86363d16bce0f816b35c249174518b70d Mon Sep 17 00:00:00 2001 From: Yurii Borysov Date: Mon, 10 Sep 2018 13:32:58 +0300 Subject: [PATCH 002/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Added CVV2 Response code to i18n file --- app/code/Magento/Authorizenet/i18n/en_US.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Authorizenet/i18n/en_US.csv b/app/code/Magento/Authorizenet/i18n/en_US.csv index eb22bc4fad311..6228d5102b13c 100644 --- a/app/code/Magento/Authorizenet/i18n/en_US.csv +++ b/app/code/Magento/Authorizenet/i18n/en_US.csv @@ -72,3 +72,4 @@ Debug,Debug "x_avs_code","AVS Response Code" "x_auth_code","Processor Authentication Code" "x_response_reason_text","Processor Response Text" +"x_cvv2_resp_code","CVV2 Response Code" From 6cc067a431bb9c347c2e174c58b9983c1904e16b Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu Date: Tue, 18 Sep 2018 13:13:29 +0300 Subject: [PATCH 003/216] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Added possibility to recalculate tax amounts in case of '0' shipping value refund --- .../Magento/Sales/Model/Order/Creditmemo/Total/Tax.php | 7 ++++++- .../Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index a842c0470ad85..98b854fb07778 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -5,9 +5,14 @@ */ namespace Magento\Sales\Model\Order\Creditmemo\Total; +/** + * Order credit memo tax total calculation model + */ class Tax extends AbstractTotal { /** + * Collect credit memo tax total + * * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo * @return $this * @@ -72,7 +77,7 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $isPartialShippingRefunded = false; if ($invoice = $creditmemo->getInvoice()) { //recalculate tax amounts in case if refund shipping value was changed - if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount()) { + if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount() !== null) { $taxFactor = $creditmemo->getBaseShippingAmount() / $order->getBaseShippingAmount(); $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php index 4bca669f089b7..565d51ff515a2 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php @@ -447,10 +447,10 @@ public function collectDataProvider() ], ], 'creditmemo_data' => [ - 'grand_total' => 64.95, - 'base_grand_total' => 64.95, - 'tax_amount' => 4.95, - 'base_tax_amount' => 4.95, + 'grand_total' => 64.94, + 'base_grand_total' => 64.94, + 'tax_amount' => 4.94, + 'base_tax_amount' => 4.94, ], ], ]; From f5aeea6e7ee4f9b8eacb5814830316eff597a06a Mon Sep 17 00:00:00 2001 From: Stsiapan Korf Date: Mon, 17 Sep 2018 15:57:28 +0300 Subject: [PATCH 004/216] MAGETWO-91639: Tax is added despite customer group changes - Add recollect quote after customer group change --- .../Quote/Plugin/RecollectOnGroupChange.php | 61 +++++++++++++++++++ app/code/Magento/Quote/etc/frontend/di.xml | 3 + 2 files changed, 64 insertions(+) create mode 100644 app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php new file mode 100644 index 0000000000000..af6599879de50 --- /dev/null +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -0,0 +1,61 @@ +cartRepository = $cartRepository; + } + + /** + * Recollect totals if customer group change + * + * @param CustomerResource $subject + * @param CustomerResource $result + * @param Customer $customer + * @return CustomerResource + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterSave(CustomerResource $subject, CustomerResource $result, Customer $customer) + { + if ($customer->getOrigData('group_id') !== null + && $customer->getOrigData('group_id') != $customer->getGroupId() + ) { + try { + /** @var \Magento\Quote\Model\Quote $quote */ + $quote = $this->cartRepository->getActiveForCustomer($customer->getId()); + $quote->setCustomerGroupId($customer->getGroupId()); + $quote->collectTotals(); + $this->cartRepository->save($quote); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //no active cart for customer + } + } + + return $result; + } +} diff --git a/app/code/Magento/Quote/etc/frontend/di.xml b/app/code/Magento/Quote/etc/frontend/di.xml index 25acd6763ba56..125afb96f20fd 100644 --- a/app/code/Magento/Quote/etc/frontend/di.xml +++ b/app/code/Magento/Quote/etc/frontend/di.xml @@ -15,4 +15,7 @@ + + + From 1e4dd7d86305c48709001082c4865b3460161cbd Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi Date: Wed, 19 Sep 2018 00:39:10 +0300 Subject: [PATCH 005/216] Clean code --- .../Catalog/Ui/Component/ColumnFactory.php | 20 +- .../Component/Listing/Columns/Thumbnail.php | 2 +- .../Model/ObjectRegistry.php | 6 +- .../Block/Adminhtml/Edit/Tab/View/Sales.php | 18 +- .../Model/Address/AbstractAddress.php | 2 +- app/code/Magento/Fedex/Model/Carrier.php | 13 +- .../IntegrationFactory.php | 2 +- .../DataProvider/NotificationDataProvider.php | 2 +- .../Magento/Sales/Model/Order/Address.php | 2 +- .../Sales/Model/Order/Payment/Info.php | 2 +- .../Sales/Model/Order/Payment/Transaction.php | 4 +- .../Model/ResourceModel/AbstractGrid.php | 2 +- .../Model/Carrier/AbstractCarrierOnline.php | 6 +- .../Request/AddressBuilder.php | 2 +- app/code/Magento/Store/Model/Store.php | 189 ++++++++++-------- .../Model/ResourceModel/Layout/Update.php | 34 ++-- 16 files changed, 168 insertions(+), 138 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index cbc67fee8a5a3..8daec1fa6ca78 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -46,12 +46,14 @@ public function __construct(\Magento\Framework\View\Element\UiComponentFactory $ $this->componentFactory = $componentFactory; } - /** - * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute - * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context - * @param array $config - * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface - */ + /** + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context + * @param array $config + * + * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface + * @throws \Magento\Framework\Exception\LocalizedException + */ public function create($attribute, $context, array $config = []) { $columnName = $attribute->getAttributeCode(); @@ -96,9 +98,7 @@ protected function getJsComponent($dataType) */ protected function getDataType($attribute) { - return isset($this->dataTypeMap[$attribute->getFrontendInput()]) - ? $this->dataTypeMap[$attribute->getFrontendInput()] - : $this->dataTypeMap['default']; + return $this->dataTypeMap[$attribute->getFrontendInput()] ?? $this->dataTypeMap['default']; } /** @@ -111,6 +111,6 @@ protected function getFilterType($frontendInput) { $filtersMap = ['date' => 'dateRange']; $result = array_replace_recursive($this->dataTypeMap, $filtersMap); - return isset($result[$frontendInput]) ? $result[$frontendInput] : $result['default']; + return $result[$frontendInput] ?? $result['default']; } } diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php index d4dc9ddd7ca3b..dc3c94f384632 100644 --- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php +++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php @@ -74,6 +74,6 @@ public function prepareDataSource(array $dataSource) protected function getAlt($row) { $altField = $this->getData('config/altField') ?: self::ALT_FIELD; - return isset($row[$altField]) ? $row[$altField] : null; + return $row[$altField] ?? null; } } diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index 019959f9c1fea..ecc4ff04ab8a7 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -26,15 +26,19 @@ public function __construct($entities) } /** + * Get + * * @param int $entityId * @return \Magento\Framework\DataObject|null */ public function get($entityId) { - return isset($this->entitiesMap[$entityId]) ? $this->entitiesMap[$entityId] : null; + return $this->entitiesMap[$entityId] ?? null; } /** + * List + * * @return \Magento\Framework\DataObject[] */ public function getList() diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index 76c33f143e671..b9442797765c6 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -147,7 +147,7 @@ public function _beforeToHtml() */ public function getWebsiteCount($websiteId) { - return isset($this->_websiteCounts[$websiteId]) ? $this->_websiteCounts[$websiteId] : 0; + return $this->_websiteCounts[$websiteId] ?? 0; } /** @@ -166,13 +166,15 @@ public function getTotals() return $this->_collection->getTotals(); } - /** - * Format price by specified website - * - * @param float $price - * @param null|int $websiteId - * @return string - */ + /** + * Format price by specified website + * + * @param float $price + * @param null|int $websiteId + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function formatCurrency($price, $websiteId = null) { return $this->_storeManager->getWebsite($websiteId)->getBaseCurrency()->format($price); diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 6408276630c3f..2c0c7812ca669 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -230,7 +230,7 @@ public function getStreet() public function getStreetLine($number) { $lines = $this->getStreet(); - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } /** diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index f6e63e04ac559..843867e183cac 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -982,11 +982,12 @@ public function getCode($type, $code = '') } } - /** - * Return FeDex currency ISO code by Magento Base Currency Code - * - * @return string 3-digit currency code - */ + /** + * Return FeDex currency ISO code by Magento Base Currency Code + * + * @return string 3-digit currency code + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrencyCode() { $codes = [ @@ -1008,7 +1009,7 @@ public function getCurrencyCode() ]; $currencyCode = $this->_storeManager->getStore()->getBaseCurrencyCode(); - return isset($codes[$currencyCode]) ? $codes[$currencyCode] : $currencyCode; + return $codes[$currencyCode] ?? $currencyCode; } /** diff --git a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php index cdca81ed98b7a..dbcb62907736c 100644 --- a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php +++ b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php @@ -72,6 +72,6 @@ public function create(VaultPaymentInterface $paymentMethod, int $storeId): Inte */ private function extractFromConfig($config, string $field, string $default): string { - return isset($config[$field]) ? $config[$field] : $default; + return $config[$field] ?? $default; } } diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index cdf7e0c6ac7c2..68090f12e99be 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -119,7 +119,7 @@ public function getName() */ public function getConfigData() { - return isset($this->data['config']) ? $this->data['config'] : []; + return $this->data['config'] ?? []; } /** diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 77d8330a72550..eab671fdb85da 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -251,7 +251,7 @@ public function getStreet() public function getStreetLine($number) { $lines = $this->getStreet(); - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } //@codeCoverageIgnoreStart diff --git a/app/code/Magento/Sales/Model/Order/Payment/Info.php b/app/code/Magento/Sales/Model/Order/Payment/Info.php index 063b3eaa71f1b..0a6b257846bfa 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Info.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Info.php @@ -181,7 +181,7 @@ public function getAdditionalInformation($key = null) if (null === $key) { return $this->additionalInformation; } - return isset($this->additionalInformation[$key]) ? $this->additionalInformation[$key] : null; + return $this->additionalInformation[$key] ?? null; } /** diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 8d8de47ba99cf..96312e7e0192b 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -472,7 +472,7 @@ public function getAdditionalInformation($key = null) $info = []; } if ($key) { - return isset($info[$key]) ? $info[$key] : null; + return $info[$key] ?? null; } return $info; } @@ -898,7 +898,7 @@ public function getTxnId() public function getHtmlTxnId() { $this->_eventManager->dispatch($this->_eventPrefix . '_html_txn_id', $this->_getEventData()); - return isset($this->_data['html_txn_id']) ? $this->_data['html_txn_id'] : $this->getTxnId(); + return $this->_data['html_txn_id'] ?? $this->getTxnId(); } /** diff --git a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php index 87c5b917f6963..25c15449a9fb4 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php +++ b/app/code/Magento/Sales/Model/ResourceModel/AbstractGrid.php @@ -103,6 +103,6 @@ protected function getLastUpdatedAtValue($default = '0000-00-00 00:00:00') $row = $this->getConnection()->fetchRow($select); - return isset($row['updated_at']) ? $row['updated_at'] : $default; + return $row['updated_at'] ?? $default; } } diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php index be2588dc48711..844258f80a284 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php @@ -184,11 +184,11 @@ public function setActiveFlag($code = 'active') /** * Return code of carrier * - * @return string + * @return string|null */ public function getCarrierCode() { - return isset($this->_code) ? $this->_code : null; + return $this->_code ?? null; } /** @@ -410,7 +410,7 @@ protected function _getCachedQuotes($requestParams) { $key = $this->_getQuotesCacheKey($requestParams); - return isset(self::$_quotesCache[$key]) ? self::$_quotesCache[$key] : null; + return self::$_quotesCache[$key] ?? null; } /** diff --git a/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php b/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php index f95968d4a1bf7..482f243f6f05d 100644 --- a/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php +++ b/app/code/Magento/Signifyd/Model/SignifydGateway/Request/AddressBuilder.php @@ -41,6 +41,6 @@ private function getStreetLine($number, $street) { $lines = is_array($street) ? $street : []; - return isset($lines[$number - 1]) ? $lines[$number - 1] : ''; + return $lines[$number - 1] ?? ''; } } diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index af25957257421..47d89112c08ea 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -460,11 +460,12 @@ protected function _getSession() return $this->_session; } - /** - * Validation rules for store - * - * @return \Zend_Validate_Interface|null - */ + /** + * Validation rules for store + * + * @return \Zend_Validate_Interface|null + * @throws \Zend_Validate_Exception + */ protected function _getValidationRulesBeforeSave() { $validator = new \Magento\Framework\Validator\DataObject(); @@ -486,13 +487,15 @@ protected function _getValidationRulesBeforeSave() return $validator; } - /** - * Loading store data - * - * @param mixed $key - * @param string $field - * @return $this - */ + /** + * Loading store data + * + * @param mixed $key + * @param string $field + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function load($key, $field = null) { if (!is_numeric($key) && $field === null) { @@ -562,11 +565,12 @@ public function setWebsite(Website $website) $this->setWebsiteId($website->getId()); } - /** - * Retrieve store website - * - * @return Website|bool - */ + /** + * Retrieve store website + * + * @return Website|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getWebsite() { if ($this->getWebsiteId() === null) { @@ -575,13 +579,15 @@ public function getWebsite() return $this->websiteRepository->getById($this->getWebsiteId()); } - /** - * Retrieve url using store configuration specific - * - * @param string $route - * @param array $params - * @return string - */ + /** + * Retrieve url using store configuration specific + * + * @param string $route + * @param array $params + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getUrl($route = '', $params = []) { /** @var $url UrlInterface */ @@ -877,12 +883,14 @@ public function getDefaultCurrency() return $currency; } - /** - * Set current store currency code - * - * @param string $code - * @return string - */ + /** + * Set current store currency code + * + * @param string $code + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function setCurrentCurrencyCode($code) { $code = strtoupper($code); @@ -968,11 +976,12 @@ public function getAllowedCurrencies() return explode(',', $this->getConfig($this->_currencyInstalled)); } - /** - * Retrieve store current currency - * - * @return Currency - */ + /** + * Retrieve store current currency + * + * @return Currency + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrency() { $currency = $this->getData('current_currency'); @@ -990,21 +999,23 @@ public function getCurrentCurrency() return $currency; } - /** - * Retrieve current currency rate - * - * @return float - */ + /** + * Retrieve current currency rate + * + * @return float + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrencyRate() { return $this->getBaseCurrency()->getRate($this->getCurrentCurrency()); } - /** - * Retrieve root category identifier - * - * @return int - */ + /** + * Retrieve root category identifier + * + * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getRootCategoryId() { if (!$this->getGroup()) { @@ -1025,11 +1036,12 @@ public function setGroup(Group $group) return $this; } - /** - * Retrieve group model - * - * @return Group|bool - */ + /** + * Retrieve group model + * + * @return Group|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getGroup() { if (null === $this->getGroupId()) { @@ -1132,11 +1144,12 @@ public function getDefaultGroupId() return $this->_getData('default_group_id'); } - /** - * Check if store can be deleted - * - * @return boolean - */ + /** + * Check if store can be deleted + * + * @return boolean + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isCanDelete() { if (!$this->getId()) { @@ -1146,12 +1159,13 @@ public function isCanDelete() return $this->getGroup()->getStoresCount() > 1; } - /** - * Check if store is default - * - * @return boolean - * @since 100.1.0 - */ + /** + * Check if store is default + * + * @return boolean + * @since 100.1.0 + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isDefault() { if (!$this->getId() && $this->getWebsite() && $this->getWebsite()->getStoresCount() == 0) { @@ -1160,14 +1174,16 @@ public function isDefault() return $this->getGroup()->getDefaultStoreId() == $this->getId(); } - /** - * Retrieve current url for store - * - * @param bool $fromStore - * @return string - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ + /** + * Retrieve current url for store + * + * @param bool $fromStore + * + * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrentUrl($fromStore = true) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); @@ -1238,22 +1254,24 @@ public function isActive() return (bool)$this->_getData('is_active'); } - /** - * Protect delete from non admin area - * - * @return $this - */ + /** + * Protect delete from non admin area + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function beforeDelete() { $this->_configDataResource->clearScopeData(ScopeInterface::SCOPE_STORES, $this->getId()); return parent::beforeDelete(); } - /** - * Rewrite in order to clear configuration cache - * - * @return $this - */ + /** + * Rewrite in order to clear configuration cache + * + * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function afterDelete() { $store = $this; @@ -1308,11 +1326,12 @@ public function isReadOnly($value = null) return $this->_isReadOnly; } - /** - * Retrieve store group name - * - * @return string - */ + /** + * Retrieve store group name + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getFrontendName() { if (null === $this->_frontendName) { @@ -1349,7 +1368,7 @@ public function getIdentities() public function getStorePath() { $parsedUrl = parse_url($this->getBaseUrl()); - return isset($parsedUrl['path']) ? $parsedUrl['path'] : '/'; + return $parsedUrl['path'] ?? '/'; } /** diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index d7e3bf94f548f..a951954600365 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -45,14 +45,16 @@ protected function _construct() $this->_init('layout_update', 'layout_update_id'); } - /** - * Retrieve layout updates by handle - * - * @param string $handle - * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store - * @return string - */ + /** + * Retrieve layout updates by handle + * + * @param string $handle + * @param \Magento\Framework\View\Design\ThemeInterface $theme + * @param \Magento\Framework\App\ScopeInterface $store + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function fetchUpdatesByHandle( $handle, \Magento\Framework\View\Design\ThemeInterface $theme, @@ -69,15 +71,17 @@ public function fetchUpdatesByHandle( $this->layoutUpdateCache[$cacheKey][$layout['handle']] .= $layout['xml']; } } - return isset($this->layoutUpdateCache[$cacheKey][$handle]) ? $this->layoutUpdateCache[$cacheKey][$handle] : ''; + return $this->layoutUpdateCache[$cacheKey][$handle] ?? ''; } - /** - * Get select to fetch updates by handle - * - * @param bool $loadAllUpdates - * @return \Magento\Framework\DB\Select - */ + /** + * Get select to fetch updates by handle + * + * @param bool $loadAllUpdates + * + * @return \Magento\Framework\DB\Select + * @throws \Magento\Framework\Exception\LocalizedException + */ protected function _getFetchUpdatesByHandleSelect($loadAllUpdates = false) { //@todo Why it also loads layout updates for store_id=0, isn't it Admin Store View? From 46fdf6db5b43313e197b4717ee51ca24cc6c2bd6 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi Date: Thu, 20 Sep 2018 22:00:41 +0300 Subject: [PATCH 006/216] Update Tests --- .../Catalog/Ui/Component/ColumnFactory.php | 18 +- .../Model/ObjectRegistry.php | 4 +- .../Block/Adminhtml/Edit/Tab/View/Sales.php | 18 +- app/code/Magento/Fedex/Model/Carrier.php | 12 +- app/code/Magento/Store/Model/Store.php | 206 +++++++++--------- .../Model/ResourceModel/Layout/Update.php | 36 +-- 6 files changed, 148 insertions(+), 146 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index 8daec1fa6ca78..f400a699f7dde 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -46,14 +46,16 @@ public function __construct(\Magento\Framework\View\Element\UiComponentFactory $ $this->componentFactory = $componentFactory; } - /** - * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute - * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context - * @param array $config - * - * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Create Factory + * + * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * @param \Magento\Framework\View\Element\UiComponent\ContextInterface $context + * @param array $config + * + * @return \Magento\Ui\Component\Listing\Columns\ColumnInterface + * @throws \Magento\Framework\Exception\LocalizedException + */ public function create($attribute, $context, array $config = []) { $columnName = $attribute->getAttributeCode(); diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index ecc4ff04ab8a7..352948b8338bc 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -26,7 +26,7 @@ public function __construct($entities) } /** - * Get + * Get Entity * * @param int $entityId * @return \Magento\Framework\DataObject|null @@ -37,7 +37,7 @@ public function get($entityId) } /** - * List + * List Entities * * @return \Magento\Framework\DataObject[] */ diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index b9442797765c6..38732803aae63 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -166,15 +166,15 @@ public function getTotals() return $this->_collection->getTotals(); } - /** - * Format price by specified website - * - * @param float $price - * @param null|int $websiteId - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Format price by specified website + * + * @param float $price + * @param null|int $websiteId + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function formatCurrency($price, $websiteId = null) { return $this->_storeManager->getWebsite($websiteId)->getBaseCurrency()->format($price); diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 843867e183cac..5a869d44b075d 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -982,12 +982,12 @@ public function getCode($type, $code = '') } } - /** - * Return FeDex currency ISO code by Magento Base Currency Code - * - * @return string 3-digit currency code - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Return FeDex currency ISO code by Magento Base Currency Code + * + * @return string 3-digit currency code + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrencyCode() { $codes = [ diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 47d89112c08ea..d55bf0b5e1cd0 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -460,12 +460,12 @@ protected function _getSession() return $this->_session; } - /** - * Validation rules for store - * - * @return \Zend_Validate_Interface|null - * @throws \Zend_Validate_Exception - */ + /** + * Validation rules for store + * + * @return \Zend_Validate_Interface|null + * @throws \Zend_Validate_Exception + */ protected function _getValidationRulesBeforeSave() { $validator = new \Magento\Framework\Validator\DataObject(); @@ -487,15 +487,15 @@ protected function _getValidationRulesBeforeSave() return $validator; } - /** - * Loading store data - * - * @param mixed $key - * @param string $field - * - * @return $this - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Loading store data + * + * @param mixed $key + * @param string $field + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function load($key, $field = null) { if (!is_numeric($key) && $field === null) { @@ -565,12 +565,12 @@ public function setWebsite(Website $website) $this->setWebsiteId($website->getId()); } - /** - * Retrieve store website - * - * @return Website|bool - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve store website + * + * @return Website|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getWebsite() { if ($this->getWebsiteId() === null) { @@ -579,15 +579,15 @@ public function getWebsite() return $this->websiteRepository->getById($this->getWebsiteId()); } - /** - * Retrieve url using store configuration specific - * - * @param string $route - * @param array $params - * - * @return string - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve url using store configuration specific + * + * @param string $route + * @param array $params + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getUrl($route = '', $params = []) { /** @var $url UrlInterface */ @@ -883,14 +883,14 @@ public function getDefaultCurrency() return $currency; } - /** - * Set current store currency code - * - * @param string $code - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Set current store currency code + * + * @param string $code + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function setCurrentCurrencyCode($code) { $code = strtoupper($code); @@ -976,12 +976,12 @@ public function getAllowedCurrencies() return explode(',', $this->getConfig($this->_currencyInstalled)); } - /** - * Retrieve store current currency - * - * @return Currency - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve store current currency + * + * @return Currency + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrency() { $currency = $this->getData('current_currency'); @@ -999,23 +999,23 @@ public function getCurrentCurrency() return $currency; } - /** - * Retrieve current currency rate - * - * @return float - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve current currency rate + * + * @return float + * @throws \Magento\Framework\Exception\LocalizedException + */ public function getCurrentCurrencyRate() { return $this->getBaseCurrency()->getRate($this->getCurrentCurrency()); } - /** - * Retrieve root category identifier - * - * @return int - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve root category identifier + * + * @return int + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getRootCategoryId() { if (!$this->getGroup()) { @@ -1036,12 +1036,12 @@ public function setGroup(Group $group) return $this; } - /** - * Retrieve group model - * - * @return Group|bool - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve group model + * + * @return Group|bool + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getGroup() { if (null === $this->getGroupId()) { @@ -1144,12 +1144,12 @@ public function getDefaultGroupId() return $this->_getData('default_group_id'); } - /** - * Check if store can be deleted - * - * @return boolean - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Check if store can be deleted + * + * @return boolean + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isCanDelete() { if (!$this->getId()) { @@ -1159,13 +1159,13 @@ public function isCanDelete() return $this->getGroup()->getStoresCount() > 1; } - /** - * Check if store is default - * - * @return boolean - * @since 100.1.0 - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Check if store is default + * + * @return boolean + * @since 100.1.0 + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function isDefault() { if (!$this->getId() && $this->getWebsite() && $this->getWebsite()->getStoresCount() == 0) { @@ -1174,16 +1174,16 @@ public function isDefault() return $this->getGroup()->getDefaultStoreId() == $this->getId(); } - /** - * Retrieve current url for store - * - * @param bool $fromStore - * - * @return string - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve current url for store + * + * @param bool $fromStore + * + * @return string + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getCurrentUrl($fromStore = true) { $sidQueryParam = $this->_sidResolver->getSessionIdQueryParam($this->_getSession()); @@ -1254,24 +1254,24 @@ public function isActive() return (bool)$this->_getData('is_active'); } - /** - * Protect delete from non admin area - * - * @return $this - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Protect delete from non admin area + * + * @return $this + * @throws \Magento\Framework\Exception\LocalizedException + */ public function beforeDelete() { $this->_configDataResource->clearScopeData(ScopeInterface::SCOPE_STORES, $this->getId()); return parent::beforeDelete(); } - /** - * Rewrite in order to clear configuration cache - * - * @return $this - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Rewrite in order to clear configuration cache + * + * @return $this + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function afterDelete() { $store = $this; @@ -1326,12 +1326,12 @@ public function isReadOnly($value = null) return $this->_isReadOnly; } - /** - * Retrieve store group name - * - * @return string - * @throws \Magento\Framework\Exception\NoSuchEntityException - */ + /** + * Retrieve store group name + * + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ public function getFrontendName() { if (null === $this->_frontendName) { diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index a951954600365..8817a947f835e 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -45,16 +45,16 @@ protected function _construct() $this->_init('layout_update', 'layout_update_id'); } - /** - * Retrieve layout updates by handle - * - * @param string $handle - * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store - * - * @return string - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Retrieve layout updates by handle + * + * @param string $handle + * @param \Magento\Framework\View\Design\ThemeInterface $theme + * @param \Magento\Framework\App\ScopeInterface $store + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ public function fetchUpdatesByHandle( $handle, \Magento\Framework\View\Design\ThemeInterface $theme, @@ -74,14 +74,14 @@ public function fetchUpdatesByHandle( return $this->layoutUpdateCache[$cacheKey][$handle] ?? ''; } - /** - * Get select to fetch updates by handle - * - * @param bool $loadAllUpdates - * - * @return \Magento\Framework\DB\Select - * @throws \Magento\Framework\Exception\LocalizedException - */ + /** + * Get select to fetch updates by handle + * + * @param bool $loadAllUpdates + * + * @return \Magento\Framework\DB\Select + * @throws \Magento\Framework\Exception\LocalizedException + */ protected function _getFetchUpdatesByHandleSelect($loadAllUpdates = false) { //@todo Why it also loads layout updates for store_id=0, isn't it Admin Store View? From 1b5f7c5db19aec08fd832fe82a59e691ce2edf81 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi Date: Sun, 23 Sep 2018 01:02:47 +0300 Subject: [PATCH 007/216] fix tests --- .../Catalog/Ui/Component/ColumnFactory.php | 8 + .../Component/Listing/Columns/Thumbnail.php | 4 + .../Model/ObjectRegistry.php | 3 + .../Block/Adminhtml/Edit/Tab/View/Sales.php | 4 + .../Model/Address/AbstractAddress.php | 26 ++- app/code/Magento/Fedex/Model/Carrier.php | 18 +- .../IntegrationFactory.php | 2 +- .../DataProvider/NotificationDataProvider.php | 78 +++++++-- .../Magento/Sales/Model/Order/Address.php | 156 ++++++++++++++---- .../Sales/Model/Order/Payment/Info.php | 7 +- .../Sales/Model/Order/Payment/Transaction.php | 60 +++++-- .../Model/Carrier/AbstractCarrierOnline.php | 13 +- app/code/Magento/Store/Model/Store.php | 14 ++ .../Model/ResourceModel/Layout/Update.php | 4 +- 14 files changed, 317 insertions(+), 80 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php index f400a699f7dde..1903bcd144831 100644 --- a/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php +++ b/app/code/Magento/Catalog/Ui/Component/ColumnFactory.php @@ -6,6 +6,8 @@ namespace Magento\Catalog\Ui\Component; /** + * Column Factory + * * @api * @since 100.0.2 */ @@ -86,7 +88,10 @@ public function create($attribute, $context, array $config = []) } /** + * Get Js Component + * * @param string $dataType + * * @return string */ protected function getJsComponent($dataType) @@ -95,7 +100,10 @@ protected function getJsComponent($dataType) } /** + * Get Data Type + * * @param \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute + * * @return string */ protected function getDataType($attribute) diff --git a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php index dc3c94f384632..09c9782fc0e32 100644 --- a/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php +++ b/app/code/Magento/Catalog/Ui/Component/Listing/Columns/Thumbnail.php @@ -9,6 +9,8 @@ use Magento\Framework\View\Element\UiComponent\ContextInterface; /** + * Class Thumbnail + * * @api * @since 100.0.2 */ @@ -67,6 +69,8 @@ public function prepareDataSource(array $dataSource) } /** + * Get Alt + * * @param array $row * * @return null|string diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php index 352948b8338bc..a048c216139e3 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/ObjectRegistry.php @@ -5,6 +5,9 @@ */ namespace Magento\CatalogUrlRewrite\Model; +/** + * Class ObjectRegistry + */ class ObjectRegistry { /** diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php index 38732803aae63..5eeacca4c73a5 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Tab/View/Sales.php @@ -151,6 +151,8 @@ public function getWebsiteCount($websiteId) } /** + * Returns Grouped Collection Rows + * * @return array */ public function getRows() @@ -159,6 +161,8 @@ public function getRows() } /** + * Return totals data + * * @return \Magento\Framework\DataObject */ public function getTotals() diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 2c0c7812ca669..caa2761a3dc3d 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -271,7 +271,8 @@ public function setStreet($street) * Enforce format of the street field or other multiline custom attributes * * @param array|string $key - * @param null $value + * @param array|string|null $value + * * @return \Magento\Framework\DataObject */ public function setData($key, $value = null) @@ -286,6 +287,7 @@ public function setData($key, $value = null) /** * Check that address can have multiline attribute by this code (as street or some custom attribute) + * * @param string $code * @return bool */ @@ -403,6 +405,8 @@ public function getRegionCode() } /** + * Return Region ID + * * @return int */ public function getRegionId() @@ -425,6 +429,8 @@ public function getRegionId() } /** + * Return Country + * * @return int */ public function getCountry() @@ -502,6 +508,8 @@ public function getConfig() } /** + * Processing object before save data + * * @return $this */ public function beforeSave() @@ -516,10 +524,12 @@ public function beforeSave() * * @param int|null $defaultBillingAddressId * @param int|null $defaultShippingAddressId + * * @return AddressInterface * Use Api/Data/AddressInterface as a result of service operations. Don't rely on the model to provide * the instance of Api/Data/AddressInterface * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Magento\Framework\Exception\LocalizedException */ public function getDataModel($defaultBillingAddressId = null, $defaultShippingAddressId = null) { @@ -591,6 +601,8 @@ public function validate() } /** + * Create Region Instance + * * @return \Magento\Directory\Model\Region */ protected function _createRegionInstance() @@ -599,6 +611,8 @@ protected function _createRegionInstance() } /** + * Create Country Instance + * * @return \Magento\Directory\Model\Country */ protected function _createCountryInstance() @@ -608,6 +622,7 @@ protected function _createCountryInstance() /** * Unset Region from address + * * @return $this * @since 100.2.0 */ @@ -617,8 +632,11 @@ public function unsRegion() } /** + * Is Company Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isCompanyRequired() { @@ -626,8 +644,11 @@ protected function isCompanyRequired() } /** + * Is Telephone Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isTelephoneRequired() { @@ -635,8 +656,11 @@ protected function isTelephoneRequired() } /** + * Is Fax Required + * * @return bool * @since 100.2.0 + * @throws \Magento\Framework\Exception\LocalizedException */ protected function isFaxRequired() { diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 5a869d44b075d..955345851e67a 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -1439,6 +1439,8 @@ protected function _doShipmentRequest(\Magento\Framework\DataObject $request) } /** + * Return Tracking Number + * * @param array|object $trackingIds * @return string */ @@ -1453,10 +1455,10 @@ function ($val) { } /** - * For multi package shipments. Delete requested shipments if the current shipment - * request is failed + * For multi package shipments. Delete requested shipments if the current shipment request is failed * * @param array $data + * * @return bool */ public function rollBack($data) @@ -1476,6 +1478,7 @@ public function rollBack($data) * Return container types of carrier * * @param \Magento\Framework\DataObject|null $params + * * @return array|bool * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ @@ -1543,6 +1546,7 @@ public function getContainerTypesFilter() * Return delivery confirmation types of carrier * * @param \Magento\Framework\DataObject|null $params + * * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -1553,6 +1557,7 @@ public function getDeliveryConfirmationTypes(\Magento\Framework\DataObject $para /** * Recursive replace sensitive fields in debug data by the mask + * * @param string $data * @return string */ @@ -1570,6 +1575,7 @@ protected function filterDebugData($data) /** * Parse track details response from Fedex + * * @param \stdClass $trackInfo * @return array * @SuppressWarnings(PHPMD.CyclomaticComplexity) @@ -1640,6 +1646,7 @@ private function processTrackingDetails(\stdClass $trackInfo) /** * Parse delivery datetime from tracking details + * * @param \stdClass $trackInfo * @return \Datetime|null */ @@ -1656,8 +1663,7 @@ private function getDeliveryDateTime(\stdClass $trackInfo) } /** - * Get delivery address details in string representation - * Return City, State, Country Code + * Get delivery address details in string representation Return City, State, Country Code * * @param \stdClass $address * @return \Magento\Framework\Phrase|string @@ -1719,6 +1725,7 @@ private function processTrackDetailsEvents(array $events) /** * Append error message to rate result instance + * * @param string $trackingValue * @param string $errorMessage */ @@ -1760,8 +1767,7 @@ private function parseDate($timestamp) } /** - * Defines payment type by request. - * Two values are available: RECIPIENT or SENDER. + * Defines payment type by request. Two values are available: RECIPIENT or SENDER. * * @param DataObject $request * @return string diff --git a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php index dbcb62907736c..0b698afea1de3 100644 --- a/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php +++ b/app/code/Magento/InstantPurchase/PaymentMethodIntegration/IntegrationFactory.php @@ -65,7 +65,7 @@ public function create(VaultPaymentInterface $paymentMethod, int $storeId): Inte /** * Reads value from config. * - * @param $config + * @param array $config * @param string $field * @param string $default * @return string diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 68090f12e99be..5cd5bf7f02bd8 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -82,7 +82,9 @@ public function __construct( } /** - * {@inheritdoc} + * Get data + * + * @return mixed */ public function getData() { @@ -95,7 +97,10 @@ public function getData() } /** - * {@inheritdoc} + * Get Meta + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException */ public function getMeta() { @@ -107,7 +112,9 @@ public function getMeta() } /** - * {@inheritdoc} + * Get Data Provider name + * + * @return string */ public function getName() { @@ -115,7 +122,9 @@ public function getName() } /** - * {@inheritdoc} + * Get config data + * + * @return mixed */ public function getConfigData() { @@ -123,7 +132,11 @@ public function getConfigData() } /** - * {@inheritdoc} + * Set config data + * + * @param mixed $config + * + * @return bool */ public function setConfigData($config) { @@ -133,7 +146,12 @@ public function setConfigData($config) } /** - * {@inheritdoc} + * Get Field Meta Info + * + * @param string $fieldSetName + * @param string $fieldName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldMetaInfo($fieldSetName, $fieldName) @@ -142,7 +160,11 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * {@inheritdoc} + * Get Field Set Meta Info + * + * @param string $fieldSetName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldSetMetaInfo($fieldSetName) @@ -151,7 +173,11 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * {@inheritdoc} + * Get Fields Meta Info + * + * @param string $fieldSetName + * + * @return array * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldsMetaInfo($fieldSetName) @@ -160,7 +186,9 @@ public function getFieldsMetaInfo($fieldSetName) } /** - * {@inheritdoc} + * Get Primary Field Name + * + * @return string */ public function getPrimaryFieldName() { @@ -168,7 +196,9 @@ public function getPrimaryFieldName() } /** - * {@inheritdoc} + * Get Request Field Name + * + * @return string */ public function getRequestFieldName() { @@ -176,7 +206,11 @@ public function getRequestFieldName() } /** - * {@inheritdoc} + * Add Filter + * + * @param \Magento\Framework\Api\Filter $filter + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function addFilter(\Magento\Framework\Api\Filter $filter) @@ -184,7 +218,12 @@ public function addFilter(\Magento\Framework\Api\Filter $filter) } /** - * {@inheritdoc} + * Add Order + * + * @param string $field + * @param string $direction + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function addOrder($field, $direction) @@ -192,7 +231,12 @@ public function addOrder($field, $direction) } /** - * {@inheritdoc} + * Set Limit + * + * @param int $offset + * @param int $size + * + * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function setLimit($offset, $size) @@ -200,7 +244,9 @@ public function setLimit($offset, $size) } /** - * {@inheritdoc} + * Get Search Criteria + * + * @return SearchCriteriaInterface */ public function getSearchCriteria() { @@ -208,7 +254,9 @@ public function getSearchCriteria() } /** - * {@inheritdoc} + * Get Search Result + * + * @return SearchResultInterface */ public function getSearchResult() { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index eab671fdb85da..a525d62662d03 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -173,7 +173,7 @@ protected function implodeStreetValue($value) * Enforce format of the street field * * @param array|string $key - * @param null $value + * @param array|string $value * @return \Magento\Framework\DataObject */ public function setData($key, $value = null) @@ -508,7 +508,11 @@ public function getVatRequestSuccess() } /** - * {@inheritdoc} + * Set Parent ID + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setParentId($id) { @@ -516,7 +520,11 @@ public function setParentId($id) } /** - * {@inheritdoc} + * Sets the country address ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setCustomerAddressId($id) { @@ -524,7 +532,11 @@ public function setCustomerAddressId($id) } /** - * {@inheritdoc} + * Sets the region ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setRegionId($id) { @@ -532,7 +544,11 @@ public function setRegionId($id) } /** - * {@inheritdoc} + * Sets the customer ID for the order address. + * + * @param int $id + * + * @return \Magento\Framework\DataObject|Address */ public function setStreet($street) { @@ -540,7 +556,11 @@ public function setStreet($street) } /** - * {@inheritdoc} + * Sets the fax number for the order address. + * + * @param string $fax + * + * @return \Magento\Framework\DataObject|Address */ public function setCustomerId($id) { @@ -548,7 +568,11 @@ public function setCustomerId($id) } /** - * {@inheritdoc} + * Sets the region for the order address. + * + * @param string $region + * + * @return \Magento\Framework\DataObject|Address */ public function setFax($fax) { @@ -556,7 +580,11 @@ public function setFax($fax) } /** - * {@inheritdoc} + * Sets the postal code for the order address. + * + * @param string $postcode + * + * @return \Magento\Framework\DataObject|Address */ public function setRegion($region) { @@ -564,7 +592,11 @@ public function setRegion($region) } /** - * {@inheritdoc} + * Sets the last name for the order address. + * + * @param string $lastname + * + * @return \Magento\Framework\DataObject|Address */ public function setPostcode($postcode) { @@ -572,7 +604,11 @@ public function setPostcode($postcode) } /** - * {@inheritdoc} + * Sets the street values, if any, for the order address. + * + * @param string|string[] $street + * + * @return \Magento\Framework\DataObject|Address */ public function setLastname($lastname) { @@ -580,7 +616,11 @@ public function setLastname($lastname) } /** - * {@inheritdoc} + * Sets the city for the order address. + * + * @param string $city + * + * @return \Magento\Framework\DataObject|Address */ public function setCity($city) { @@ -588,7 +628,11 @@ public function setCity($city) } /** - * {@inheritdoc} + * Sets the email address for the order address. + * + * @param string $email + * + * @return \Magento\Framework\DataObject|Address */ public function setEmail($email) { @@ -596,7 +640,11 @@ public function setEmail($email) } /** - * {@inheritdoc} + * Sets the telephone number for the order address. + * + * @param string $telephone + * + * @return \Magento\Framework\DataObject|Address */ public function setTelephone($telephone) { @@ -604,7 +652,11 @@ public function setTelephone($telephone) } /** - * {@inheritdoc} + * Sets the country ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setCountryId($id) { @@ -612,7 +664,11 @@ public function setCountryId($id) } /** - * {@inheritdoc} + * Sets the first name for the order address. + * + * @param string $firstname + * + * @return \Magento\Framework\DataObject|Address */ public function setFirstname($firstname) { @@ -620,7 +676,11 @@ public function setFirstname($firstname) } /** - * {@inheritdoc} + * Sets the address type for the order address. + * + * @param string $addressType + * + * @return \Magento\Framework\DataObject|Address */ public function setAddressType($addressType) { @@ -628,7 +688,11 @@ public function setAddressType($addressType) } /** - * {@inheritdoc} + * Sets the prefix for the order address. + * + * @param string $prefix + * + * @return \Magento\Framework\DataObject|Address */ public function setPrefix($prefix) { @@ -636,7 +700,11 @@ public function setPrefix($prefix) } /** - * {@inheritdoc} + * Sets the middle name for the order address. + * + * @param string $middlename + * + * @return \Magento\Framework\DataObject|Address */ public function setMiddlename($middlename) { @@ -644,7 +712,11 @@ public function setMiddlename($middlename) } /** - * {@inheritdoc} + * Sets the suffix for the order address. + * + * @param string $suffix + * + * @return \Magento\Framework\DataObject|Address */ public function setSuffix($suffix) { @@ -652,7 +724,11 @@ public function setSuffix($suffix) } /** - * {@inheritdoc} + * Sets the company for the order address. + * + * @param string $company + * + * @return \Magento\Framework\DataObject|Address */ public function setCompany($company) { @@ -660,7 +736,11 @@ public function setCompany($company) } /** - * {@inheritdoc} + * Sets the VAT ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setVatId($id) { @@ -668,7 +748,11 @@ public function setVatId($id) } /** - * {@inheritdoc} + * Sets the VAT-is-valid flag value for the order address. + * + * @param int $vatIsValid + * + * @return \Magento\Framework\DataObject|Address */ public function setVatIsValid($vatIsValid) { @@ -676,7 +760,11 @@ public function setVatIsValid($vatIsValid) } /** - * {@inheritdoc} + * Sets the VAT request ID for the order address. + * + * @param string $id + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestId($id) { @@ -684,7 +772,11 @@ public function setVatRequestId($id) } /** - * {@inheritdoc} + * Set region code + * + * @param string $regionCode + * + * @return \Magento\Framework\DataObject|Address */ public function setRegionCode($regionCode) { @@ -692,7 +784,11 @@ public function setRegionCode($regionCode) } /** - * {@inheritdoc} + * Sets the VAT request date for the order address. + * + * @param string $vatRequestDate + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestDate($vatRequestDate) { @@ -700,7 +796,11 @@ public function setVatRequestDate($vatRequestDate) } /** - * {@inheritdoc} + * Sets the VAT-request-success flag value for the order address. + * + * @param int $vatRequestSuccess + * + * @return \Magento\Framework\DataObject|Address */ public function setVatRequestSuccess($vatRequestSuccess) { @@ -708,7 +808,7 @@ public function setVatRequestSuccess($vatRequestSuccess) } /** - * {@inheritdoc} + * Retrieve existing extension attributes object or create a new one. * * @return \Magento\Sales\Api\Data\OrderAddressExtensionInterface|null */ @@ -718,7 +818,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * Set an extension attributes object. * * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes * @return $this diff --git a/app/code/Magento/Sales/Model/Order/Payment/Info.php b/app/code/Magento/Sales/Model/Order/Payment/Info.php index 0a6b257846bfa..fee846fe6a62c 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Info.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Info.php @@ -11,8 +11,8 @@ use Magento\Payment\Model\InfoInterface; /** - * * Payment information model + * * @api * @since 100.0.2 */ @@ -41,7 +41,7 @@ class Info extends AbstractModel implements InfoInterface * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory - * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory, + * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory * @param \Magento\Payment\Helper\Data $paymentData * @param \Magento\Framework\Encryption\EncryptorInterface $encryptor * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource @@ -219,8 +219,7 @@ public function hasAdditionalInformation($key = null) } /** - * Initialize additional information container with data from model - * if property empty + * Initialize additional information container with data from model if property empty * * @return void */ diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 96312e7e0192b..07d9dfc851cf6 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -132,10 +132,12 @@ class Transaction extends AbstractModel implements TransactionInterface * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory * @param AttributeValueFactory $customAttributeFactory * @param \Magento\Sales\Model\OrderFactory $orderFactory + * @param \Magento\Sales\Api\OrderPaymentRepositoryInterface $orderPaymentRepository + * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository * @param \Magento\Framework\Stdlib\DateTime\DateTimeFactory $dateFactory * @param TransactionFactory $transactionFactory - * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource - * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource + * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -193,8 +195,7 @@ public function setTxnId($txnId) } /** - * Parent transaction ID setter - * Can set the transaction id as well + * Parent transaction ID setter Can set the transaction id as well * * @param string $parentTxnId * @param string $txnId @@ -229,8 +230,7 @@ public function setTxnType($txnType) } /** - * Parent transaction getter - * May attempt to load it. + * Parent transaction getter. May attempt to load it. * * @param bool $shouldLoad * @return bool|\Magento\Sales\Model\Order\Payment\Transaction @@ -366,8 +366,7 @@ public function closeAuthorization($shouldSave = true, $dryRun = false) } /** - * Close a capture transaction - * Logic is similar to closeAuthorization(), but for a capture transaction + * Close a capture transaction. Logic is similar to closeAuthorization(), but for a capture transaction * * @param bool $shouldSave * @return bool|\Magento\Sales\Model\Order\Payment\Transaction @@ -395,6 +394,7 @@ public function closeCapture($shouldSave = true) /** * Check whether authorization in current hierarchy can be voided completely + * * Basically checks whether the authorization exists and it is not affected by a capture or void * * @return bool @@ -536,6 +536,7 @@ public function close($shouldSave = true) /** * Order ID getter + * * Attempts to get ID from set order payment object, if any, or from data by key 'order_id' * * @return int|null @@ -572,6 +573,7 @@ public function getOrder() /** * Set order instance for transaction depends on transaction behavior + * * If $order equals to true, method isn't loading new order instance. * * @param \Magento\Sales\Model\Order|null|boolean $order @@ -695,7 +697,6 @@ protected function _loadChildren() /** * Check whether this transaction is voided * - * TODO: implement that there should be only one void per authorization * @return bool */ protected function _isVoided() @@ -805,7 +806,6 @@ protected function _verifyTxnId($txnId) /** * Make sure this object is a valid transaction - * TODO for more restriction we can check for data consistency * * @return void * @throws \Magento\Framework\Exception\LocalizedException @@ -833,7 +833,11 @@ public function getTransactionId() } /** - * {@inheritdoc} + * Set Transaction ID + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setTransactionId($id) { @@ -942,7 +946,11 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * Gets an array of child transactions for the transaction. + * + * @param string $createdAt + * + * @return TransactionInterface|Transaction */ public function setCreatedAt($createdAt) { @@ -950,7 +958,11 @@ public function setCreatedAt($createdAt) } /** - * {@inheritdoc} + * Sets the parent ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setParentId($id) { @@ -958,7 +970,11 @@ public function setParentId($id) } /** - * {@inheritdoc} + * Sets the order ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setOrderId($id) { @@ -966,7 +982,11 @@ public function setOrderId($id) } /** - * {@inheritdoc} + * Sets the payment ID for the transaction. + * + * @param int $id + * + * @return TransactionInterface|Transaction */ public function setPaymentId($id) { @@ -974,7 +994,11 @@ public function setPaymentId($id) } /** - * {@inheritdoc} + * Sets the parent transaction business ID for the transaction. + * + * @param string $id + * + * @return TransactionInterface|Transaction */ public function setIsClosed($isClosed) { @@ -982,7 +1006,7 @@ public function setIsClosed($isClosed) } /** - * {@inheritdoc} + * Retrieve existing extension attributes object or create a new one. * * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null */ @@ -992,7 +1016,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * Set an extension attributes object. * * @param \Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes * @return $this diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php index 844258f80a284..27047ae46bf1f 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrierOnline.php @@ -216,6 +216,7 @@ public function getTrackingInfo($tracking) /** * Check if carrier has shipping tracking option available + * * All \Magento\Usa carriers have shipping tracking option available * * @return boolean @@ -399,8 +400,8 @@ protected function _getQuotesCacheKey($requestParams) /** * Checks whether some request to rates have already been done, so we have cache for it - * Used to reduce number of same requests done to carrier service during one session * + * Used to reduce number of same requests done to carrier service during one session * Returns cached response or null * * @param string|array $requestParams @@ -443,8 +444,7 @@ protected function _prepareServiceName($name) } /** - * Prepare shipment request. - * Validate and correct request information + * Prepare shipment request. Validate and correct request information * * @param \Magento\Framework\DataObject $request * @return void @@ -558,8 +558,7 @@ public function returnOfShipment($request) } /** - * For multi package shipments. Delete requested shipments if the current shipment - * request is failed + * For multi package shipments. Delete requested shipments if the current shipment. Request is failed * * @param array $data * @return bool @@ -625,6 +624,8 @@ public function isGirthAllowed($countyDest = null, $carrierMethodCode = null) } /** + * Set Raw Request + * * @param \Magento\Framework\DataObject|null $request * @return $this * @api @@ -680,6 +681,7 @@ public function parseXml($xmlContent, $customSimplexml = 'SimpleXMLElement') /** * Checks if shipping method can collect rates + * * @return bool */ public function canCollectRates() @@ -689,6 +691,7 @@ public function canCollectRates() /** * Debug errors if showmethod is unset + * * @param Error $errors * * @return void diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index d55bf0b5e1cd0..e64f5f21bd5eb 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -412,6 +412,8 @@ public function __construct( } /** + * Magic method called during class serialization + * * @return string[] */ public function __sleep() @@ -792,6 +794,8 @@ public function isFrontUrlSecure() } /** + * Return is URL should be secure + * * @return bool */ public function isUrlSecure() @@ -1363,6 +1367,8 @@ public function getIdentities() } /** + * Return Store Path + * * @return string */ public function getStorePath() @@ -1372,6 +1378,8 @@ public function getStorePath() } /** + * Get scope type + * * {@inheritdoc} * @since 100.1.0 */ @@ -1381,6 +1389,8 @@ public function getScopeType() } /** + * Get Scope Type Name + * * {@inheritdoc} * @since 100.1.0 */ @@ -1390,6 +1400,8 @@ public function getScopeTypeName() } /** + * Retrieve existing extension attributes object or create a new one. + * * {@inheritdoc} */ public function getExtensionAttributes() @@ -1398,6 +1410,8 @@ public function getExtensionAttributes() } /** + * Set an extension attributes object. + * * @param \Magento\Store\Api\Data\StoreExtensionInterface $extensionAttributes * @return $this */ diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index 8817a947f835e..4333b2cf4fe60 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -48,9 +48,9 @@ protected function _construct() /** * Retrieve layout updates by handle * - * @param string $handle + * @param string $handle * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface $store + * @param \Magento\Framework\App\ScopeInterface store * * @return string * @throws \Magento\Framework\Exception\LocalizedException From 7aeb3be0530da6e3641b432ec2a5a5d99d43635c Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi Date: Sun, 23 Sep 2018 12:24:03 +0300 Subject: [PATCH 008/216] fix tests --- .../DataProvider/NotificationDataProvider.php | 2 +- .../Magento/Sales/Model/Order/Address.php | 24 +++++++++---------- .../Sales/Model/Order/Payment/Transaction.php | 4 ++-- app/code/Magento/Store/Model/Store.php | 6 ++--- .../Model/ResourceModel/Layout/Update.php | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 5cd5bf7f02bd8..26e698b67545b 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -147,7 +147,7 @@ public function setConfigData($config) /** * Get Field Meta Info - * + * * @param string $fieldSetName * @param string $fieldName * diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index a525d62662d03..8a4406e17a7e6 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -544,9 +544,9 @@ public function setRegionId($id) } /** - * Sets the customer ID for the order address. + * Sets the street values, if any, for the order address. * - * @param int $id + * @param string|string[] $street * * @return \Magento\Framework\DataObject|Address */ @@ -556,9 +556,9 @@ public function setStreet($street) } /** - * Sets the fax number for the order address. + * Sets the customer ID for the order address. * - * @param string $fax + * @param int $id * * @return \Magento\Framework\DataObject|Address */ @@ -568,9 +568,9 @@ public function setCustomerId($id) } /** - * Sets the region for the order address. + * Sets the fax number for the order address. * - * @param string $region + * @param string $fax * * @return \Magento\Framework\DataObject|Address */ @@ -580,9 +580,9 @@ public function setFax($fax) } /** - * Sets the postal code for the order address. + * Sets the region for the order address. * - * @param string $postcode + * @param string $region * * @return \Magento\Framework\DataObject|Address */ @@ -592,9 +592,9 @@ public function setRegion($region) } /** - * Sets the last name for the order address. + * Sets the postal code for the order address. * - * @param string $lastname + * @param string $postcode * * @return \Magento\Framework\DataObject|Address */ @@ -604,9 +604,9 @@ public function setPostcode($postcode) } /** - * Sets the street values, if any, for the order address. + * Sets the last name for the order address. * - * @param string|string[] $street + * @param string $lastname * * @return \Magento\Framework\DataObject|Address */ diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 07d9dfc851cf6..d1a8e99a98027 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -994,9 +994,9 @@ public function setPaymentId($id) } /** - * Sets the parent transaction business ID for the transaction. + * Sets the value of the is-closed flag for the transaction. * - * @param string $id + * @param int $isClosed * * @return TransactionInterface|Transaction */ diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index e64f5f21bd5eb..31d2b7bf30327 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1380,7 +1380,7 @@ public function getStorePath() /** * Get scope type * - * {@inheritdoc} + * @return string * @since 100.1.0 */ public function getScopeType() @@ -1391,7 +1391,7 @@ public function getScopeType() /** * Get Scope Type Name * - * {@inheritdoc} + * @return string * @since 100.1.0 */ public function getScopeTypeName() @@ -1402,7 +1402,7 @@ public function getScopeTypeName() /** * Retrieve existing extension attributes object or create a new one. * - * {@inheritdoc} + * @return \Magento\Store\Api\Data\StoreExtensionInterface|null */ public function getExtensionAttributes() { diff --git a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php index 4333b2cf4fe60..6c0aef9e67186 100644 --- a/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php +++ b/app/code/Magento/Widget/Model/ResourceModel/Layout/Update.php @@ -50,7 +50,7 @@ protected function _construct() * * @param string $handle * @param \Magento\Framework\View\Design\ThemeInterface $theme - * @param \Magento\Framework\App\ScopeInterface store + * @param \Magento\Framework\App\ScopeInterface $store * * @return string * @throws \Magento\Framework\Exception\LocalizedException From cdd19a602f03b0da45bf36e6ea634ec2bae5be29 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi Date: Tue, 25 Sep 2018 12:55:32 +0300 Subject: [PATCH 009/216] Update Comments --- app/code/Magento/Sales/Model/Order/Address.php | 6 +----- app/code/Magento/Sales/Model/Order/Payment/Transaction.php | 6 +----- app/code/Magento/Store/Model/Store.php | 5 +---- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 8a4406e17a7e6..98433899cca26 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -508,11 +508,7 @@ public function getVatRequestSuccess() } /** - * Set Parent ID - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setParentId($id) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index d1a8e99a98027..8f9f275de1658 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -833,11 +833,7 @@ public function getTransactionId() } /** - * Set Transaction ID - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setTransactionId($id) { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 31d2b7bf30327..c212ebfec845f 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1378,10 +1378,7 @@ public function getStorePath() } /** - * Get scope type - * - * @return string - * @since 100.1.0 + * @inheritdoc */ public function getScopeType() { From b2ef6286c38f7de0fd4646e5de9226f7ca03e8de Mon Sep 17 00:00:00 2001 From: Stsiapan Korf Date: Tue, 25 Sep 2018 15:37:55 +0300 Subject: [PATCH 010/216] MAGETWO-91639: Tax is added despite customer group changes - Fix utf symbol --- app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php index af6599879de50..303c95b965b98 100644 --- a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -1,6 +1,6 @@ Date: Wed, 26 Sep 2018 15:27:51 +0400 Subject: [PATCH 011/216] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Add automated test --- .../Section/AdminProductFormActionSection.xml | 1 + .../Section/AdminCreditMemoTotalSection.xml | 2 + .../Mftf/ActionGroup/AdminTaxActionGroup.xml | 7 + .../Mftf/Section/AdminConfigureTaxSection.xml | 5 + .../Section/AdminProductTaxClassSection.xml | 18 +++ .../Mftf/Test/CheckCreditMemoTotalsTest.xml | 144 ++++++++++++++++++ 6 files changed, 177 insertions(+) create mode 100644 app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml index afbaba41a9bb7..81ca8e1cd27f5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml @@ -15,5 +15,6 @@ + diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml index 00eb93452edd5..84fcc8fc47dfb 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml @@ -19,5 +19,7 @@ + + \ No newline at end of file diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml index 6c535e3004e69..429c7dea4baa4 100644 --- a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminTaxActionGroup.xml @@ -80,6 +80,13 @@ + + + + + + + diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml index 896d719a436ca..f3f0b7c25eef2 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminConfigureTaxSection.xml @@ -51,5 +51,10 @@ + + + + + diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml new file mode 100644 index 0000000000000..f32caf88f2133 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminProductTaxClassSection.xml @@ -0,0 +1,18 @@ + + + + +
+ + + + + +
+
diff --git a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml new file mode 100644 index 0000000000000..1063f2aa5bf5b --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml @@ -0,0 +1,144 @@ + + + + + + + + + + <description value="Checking Credit memo Totals"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95175"/> + <group value="creditMemo"/> + <group value="tax"/> + </annotations> + <before> + <!--Create category and product--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!--Create customer--> + <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> + <!--Login as admin--> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + <!--Create tax rule and tax rate--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulePage"/> + <waitForPageLoad stepKey="waitForTaxRatePage"/> + <click stepKey="addNewTaxRate" selector="{{AdminGridMainControls.add}}"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="SampleRule"/> + <actionGroup ref="addCustomTaxRate" stepKey="addCustomTaxRate"> + <argument name="taxCode" value="SimpleTaxNY"/> + </actionGroup> + <click stepKey="expandAdditionalSettings" selector="{{AdminProductTaxClassSection.additionalSettings}}"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <click selector="{{AdminProductTaxClassSection.productTaxClass}}" stepKey="ClickToAddTaxClass"/> + <fillField selector="{{AdminProductTaxClassSection.TaxClassName}}" userInput="NewTaxClass" stepKey="setName"/> + <click selector="{{AdminProductTaxClassSection.confirm}}" stepKey="ClickToDone"/> + <click stepKey="clickSave" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForTaxRatePage1"/> + <see userInput="You saved the tax rule." stepKey="VerifyRuleSaved"/> + <!--Search and edit product to add new created tax rule--> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="OpenEditProductOnBackend"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <selectOption selector="{{AdminProductFormActionSection.selectTaxClass}}" userInput="NewTaxClass" stepKey="SetNewTaxClass" /> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + <!--Set configs--> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> + <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> + <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> + <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="NewTaxClass" stepKey="selectClass"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <!--flash cache--> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + </before> + <after> + <!--Delete category and product--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <!--Delete customer--> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <!--Roll Back configuration--> + <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> + <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> + <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="Taxable Goods" stepKey="selectClass"/> + <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> + <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> + <!-- Go to the tax rule page and delete the row we created--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="SampleRule"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <!-- Go to the tax rate page --> + <amOnPage url="{{AdminTaxRateGridPage.url}}" stepKey="goToTaxRatesPage"/> + <waitForPageLoad stepKey="waitForRatesPage"/> + <!-- Delete tax rate that were created --> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteNYRate"> + <argument name="name" value="{{SimpleTaxNY.state}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + <actionGroup ref="deleteProductTaxClass" stepKey="deleteFirstProductTaxClass"> + <argument name="taxClassName" value="NewTaxClass"/> + </actionGroup> + <!--logout--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Create new order--> + <actionGroup stepKey="CreateNewOrder" ref="navigateToNewOrderPageExistingCustomer"> + <argument name="customer" value="Simple_US_Customer_NY"/> + </actionGroup> + <!--Add product to order--> + <click stepKey="clickToAddProduct" selector="{{AdminOrderFormItemsSection.addProducts}}"/> + <waitForPageLoad stepKey="waitForProductsOpened"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <!--Set shipping method--> + <actionGroup stepKey="orderSelectFlatRateShipping" ref="orderSelectFlatRateShipping"/> + <!--Submit order--> + <click stepKey="SubmitOrder" selector="{{AdminOrderFormActionSection.SubmitOrder}}"/> + <waitForPageLoad stepKey="waitForPageLoad4"/> + <grabTextFrom stepKey="getOrderId" selector="|Order # (\d+)|"/> + <!--Open new created order--> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="goToOrders"/> + <waitForPageLoad stepKey="waitForPageLoad5"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$getOrderId"/> + </actionGroup> + <!--Create order invoice--> + <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceAction"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> + <see selector="{{AdminInvoiceOrderInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderProcessing"/> + <!--Create Credit Memo--> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreditMemoAction"/> + <fillField selector="{{AdminCreditMemoTotalSection.refundShipping}}" userInput="0" stepKey="setRefundShipping"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccess"/> + <click selector="{{AdminCreditMemoTotalSection.creditMemoItem}}" stepKey="goToCreatedCreditMemo"/> + <waitForPageLoad stepKey="waitForPageLoad6"/> + <!--View created memo and verify tax for product--> + <click selector="{{AdminCreditMemoTotalSection.viewMemo}}" stepKey="ViewMemo"/> + <waitForPageLoad stepKey="waitForPageLoad7"/> + <grabTextFrom selector="{{AdminCreditMemoTotalSection.grandTotal}}" stepKey="getGrandTotal"/> + <assertEquals expected='$123.00' expectedType="string" actual="($getGrandTotal)" stepKey="assertGrandTotalValue"/> + + </test> +</tests> From 02094f2ef0891f14d2b5e6a5e024379817dd3f7e Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Fri, 28 Sep 2018 11:33:24 +0400 Subject: [PATCH 012/216] MAGETWO-91639: Tax is added despite customer group changes - Add automated test --- ...AdminConfigCreateNewAccountActionGroup.xml | 25 +++ .../AdminStoresCustomerConfigurationPage.xml | 12 ++ ...dminStoresCustomerConfigurationSection.xml | 14 ++ .../AdminCreateCustomerGroupActionGroup.xml | 25 +++ .../AdminDeleteCustomerGroupActionGroup.xml | 31 ++++ ...SignUpNewUserFromStorefrontActionGroup.xml | 5 + .../Customer/Test/Mftf/Data/AddressData.xml | 7 + .../Mftf/Data/CustomerConfigurationData.xml | 40 +++++ .../customer_create_new_account-meta.xml | 28 ++++ .../Test/Mftf/Page/AdminCustomerGroupPage.xml | 14 ++ .../Mftf/Page/AdminNewCustomerGroupPage.xml | 14 ++ .../Section/AdminCustomerGroupMainSection.xml | 19 +++ .../Section/AdminNewCustomerGroupSection.xml | 18 +++ ...StorefrontCheckTaxAddingValidVATIdTest.xml | 147 ++++++++++++++++++ .../AdminCustomerTaxClassActionGroup.xml | 42 +++++ .../Tax/Test/Mftf/Data/TaxCodeData.xml | 12 ++ .../Tax/Test/Mftf/Data/TaxRuleData.xml | 6 + .../Mftf/Section/AdminTaxRulesSection.xml | 4 + 18 files changed, 463 insertions(+) create mode 100644 app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml create mode 100644 app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml create mode 100644 app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml create mode 100644 app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml new file mode 100644 index 0000000000000..084f4ce92f0f8 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/AdminConfigCreateNewAccountActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SetGroupForValidVATIdIntraUnionActionGroup"> + <arguments> + <argument name="value" type="string"/> + </arguments> + <amOnPage url="{{AdminStoresCustomerConfigurationPage.url}}" stepKey="navigateToCustomerConfigurationPage" /> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick stepKey="expandCreateNewAccountOptionsTab" selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" dependentSelector="{{AdminStoresCustomerConfigurationSection.enableAutoAssignCustomerGroup}}" visible="false"/> + <waitForElementVisible selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" stepKey="waitForElementsAppeared"/> + <selectOption selector="{{AdminStoresCustomerConfigurationSection.groupForValidVATIdIntraUnion}}" userInput="{{value}}" stepKey="selectValue"/> + <click selector="{{AdminStoresCustomerConfigurationSection.createNewAccOpt}}" stepKey="collapseTab" /> + <click selector="{{ContentManagementSection.Save}}" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForConfigSaved"/> + <see userInput="You saved the configuration." stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml b/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml new file mode 100644 index 0000000000000..6a4efb6b9e152 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Page/AdminStoresCustomerConfigurationPage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminStoresCustomerConfigurationPage" url="admin/system_config/edit/section/customer/" area="admin" module="Magento_Config"> + <section name="AdminStoresCustomerConfigurationSection"/> + </page> +</pages> diff --git a/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml b/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml new file mode 100644 index 0000000000000..823be383ce123 --- /dev/null +++ b/app/code/Magento/Config/Test/Mftf/Section/AdminStoresCustomerConfigurationSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminStoresCustomerConfigurationSection"> + <element name="createNewAccOpt" type="button" selector="#customer_create_account-head"/> + <element name="enableAutoAssignCustomerGroup" type="button" selector="#customer_create_account_auto_group_assign"/> + <element name="groupForValidVATIdIntraUnion" type="select" selector="#customer_create_account_viv_intra_union_group"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..ba984a4d82562 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCreateCustomerGroupActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateCustomerGroupActionGroup"> + <arguments> + <argument name="groupName" type="string"/> + <argument name="taxClass" type="string"/> + </arguments> + <amOnPage url="{{AdminNewCustomerGroupPage.url}}" stepKey="goToNewCustomerGroupPage"/> + <waitForPageLoad stepKey="waitForNewCustomerGroupPageLoad"/> + + <!--Set tax class for customer group--> + <fillField stepKey="fillGroupName" selector="{{AdminNewCustomerGroupSection.groupName}}" userInput="{{groupName}}"/> + <selectOption selector="{{AdminNewCustomerGroupSection.taxClass}}" userInput="{{taxClass}}" stepKey="selectTaxClassOption"/> + <click selector="{{AdminNewCustomerGroupSection.saveCustomerGroup}}" stepKey="clickToSaveCustomerGroup"/> + <waitForPageLoad stepKey="waitForCustomerGroupSaved"/> + <see stepKey="seeCustomerGroupSaveMessage" userInput="You saved the customer group."/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml new file mode 100644 index 0000000000000..9d5b0ea56cd75 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteCustomerGroupActionGroup"> + <arguments> + <argument name="groupName" type="string"/> + </arguments> + <amOnPage url="{{AdminCustomerGroupPage.url}}" stepKey="navigateToCustomersGroupPage"/> + <waitForPageLoad stepKey="waitForPageOpened"/> + <click stepKey="clickFiltersBtn" selector="{{AdminCustomerGroupMainSection.filterBtn}}"/> + <fillField selector="{{AdminCustomerGroupMainSection.groupField}}" userInput="{{groupName}}" stepKey="fillFieldGroupName"/> + <click stepKey="clickApplyBtn" selector="{{AdminCustomerGroupMainSection.applyFiltersBtn}}"/> + <!--Here we need to use Implicit wait.--> + <wait stepKey="waitForFilteringFinished" time="2"/> + <click stepKey="clickSelectBtn" selector="{{AdminCustomerGroupMainSection.selectFirstRow}}"/> + <wait stepKey="waitForDropDownOpened" time="2"/> + <click stepKey="clickDeleteBtn" selector="{{AdminCustomerGroupMainSection.deleteBtn}}"/> + <waitForPageLoad stepKey="waitForConfirmationAlert"/> + <click stepKey="accept" selector="{{AdminCustomerGridMainActionsSection.ok}}"/> + <see stepKey="seeSuccessMessage" userInput="You deleted the customer group."/> + <wait stepKey="waitForClearAllBtnVisible" time="2"/> + <click stepKey="clearAllBtn" selector="{{AdminCustomerGroupMainSection.clearAllBtn}}"/> + <waitForElementNotVisible selector="{{AdminCustomerGroupMainSection.clearAllBtn}}" stepKey="waitForElementNotVisible"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml index 79cc00d4474b1..227085fce9de4 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml @@ -46,4 +46,9 @@ <click stepKey="saveAddress" selector="{{StorefrontCustomerAddressSection.saveAddress}}"/> </actionGroup> + + <actionGroup name="SignUpNewCustomerStorefrontActionGroup" extends="SignUpNewUserFromStorefrontActionGroup"> + <waitForPageLoad stepKey="waitForRegistered" after="clickCreateAccountButton"/> + <remove keyForRemoval="seeThankYouMessage" after="waitForRegistered"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index d090620145105..2cdddd48ed0e7 100755 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -106,4 +106,11 @@ <data key="country_id">GB</data> <data key="telephone">444-44-444-44</data> </entity> + <entity name="UK_Simple_Address" extends="UK_Not_Default_Address"> + <array key="street"> + <item>172, Westminster Bridge Rd</item> + <item>7700 xyz street</item> + </array> + <data key="state">California</data> + </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml new file mode 100644 index 0000000000000..60d8b13887ec9 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerConfigurationData.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SetCustomerCreateNewAccountOptionsConfig" type="customer_create_new_account_config"> + <requiredEntity type="auto_group_assign">EnableAutomaticAssignmentCustomerGroup</requiredEntity> + <requiredEntity type="viv_on_each_transaction">EnableValidateEachTransaction</requiredEntity> + <requiredEntity type="vat_frontend_visibility">EnableShowVATNumberStorefront</requiredEntity> + </entity> + <entity name="EnableAutomaticAssignmentCustomerGroup" type="auto_group_assign"> + <data key="value">1</data> + </entity> + <entity name="EnableValidateEachTransaction" type="viv_on_each_transaction"> + <data key="value">1</data> + </entity> + <entity name="EnableShowVATNumberStorefront" type="vat_frontend_visibility"> + <data key="value">1</data> + </entity> + + <entity name="SetCustomerCreateNewAccountOptionsDefaultConfig" type="customer_create_new_account_config"> + <requiredEntity type="auto_group_assign">DefaultAutomaticAssignmentCustomerGroup</requiredEntity> + <requiredEntity type="viv_on_each_transaction">DefaultValidateEachTransaction</requiredEntity> + <requiredEntity type="vat_frontend_visibility">DefaultShowVATNumberStorefront</requiredEntity> + </entity> + <entity name="DefaultAutomaticAssignmentCustomerGroup" type="auto_group_assign"> + <data key="value">0</data> + </entity> + <entity name="DefaultValidateEachTransaction" type="viv_on_each_transaction"> + <data key="value">0</data> + </entity> + <entity name="DefaultShowVATNumberStorefront" type="vat_frontend_visibility"> + <data key="value">0</data> + </entity> +</entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml new file mode 100644 index 0000000000000..89ed477cb32d1 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Metadata/customer_create_new_account-meta.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CustomerCreateNewAccountOptionsConfigState" dataType="customer_create_new_account_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/customer/" method="POST"> + <object key="groups" dataType="customer_create_new_account_config"> + <object key="create_account" dataType="customer_create_new_account_config"> + <object key="fields" dataType="customer_create_new_account_config"> + <object key="auto_group_assign" dataType="auto_group_assign"> + <field key="value">string</field> + </object> + <object key="viv_on_each_transaction" dataType="viv_on_each_transaction"> + <field key="value">string</field> + </object> + <object key="vat_frontend_visibility" dataType="vat_frontend_visibility"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml new file mode 100644 index 0000000000000..9adda6a74ba99 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminCustomerGroupPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminCustomerGroupPage" url="/customer/group/" area="admin" module="Magento_Customer"> + <section name="AdminCustomerGroupMainSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml new file mode 100644 index 0000000000000..2c52b3ec05c2e --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerGroupPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminNewCustomerGroupPage" url="/customer/group/new/" area="admin" module="Magento_Customer"> + <section name="AdminNewCustomerGroupSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml new file mode 100644 index 0000000000000..1fdb15f189ace --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGroupMainSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCustomerGroupMainSection"> + <element name="filterBtn" type="button" selector="//button[text()='Filters']"/> + <element name="groupField" type="input" selector="//*[@name='customer_group_code']"/> + <element name="applyFiltersBtn" type="button" selector="//*[text()='Apply Filters']"/> + <element name="selectFirstRow" type="button" selector="//button[@class='action-select']"/> + <element name="deleteBtn" type="button" selector="//*[text()='Delete']"/> + <element name="clearAllBtn" type="button" selector="//button[text()='Clear all']"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml new file mode 100644 index 0000000000000..ec4a64b01467b --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminNewCustomerGroupSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminNewCustomerGroupSection"> + <element name="groupName" type="input" selector="#customer_group_code"/> + <element name="taxClass" type="select" selector="#tax_class_id"/> + <element name="saveCustomerGroup" type="button" selector="#save"/> + <element name="resetBtn" type="button" selector="#reset"/> + <element name="backBtn" type="button" selector="#back"/> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml new file mode 100644 index 0000000000000..d38aa9dfdd6c9 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontCheckTaxAddingValidVATIdTest.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCheckTaxAddingValidVATIdTest"> + <annotations> + <features value="Customer"/> + <stories value="MAGETWO-91639: Tax is added despite customer group changes"/> + <title value="Check tax adding when it's changed to 'Valid VAT ID - Intra-Union'"/> + <description value="Tax should be applied"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95028"/> + <group value="customer"/> + </annotations> + <before> + <!--Log In--> + <actionGroup ref="LoginAsAdmin" stepKey="logIn"/> + <!--Create category--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <!--Create product--> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + + <!--Add new tax rates. Go to tax rule page --> + <actionGroup ref="addNewTaxRuleActionGroup" stepKey="addFirstTaxRuleActionGroup"/> + <fillField stepKey="fillRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="{{TaxRule.name}}"/> + + <!-- Add NY and CA tax rules --> + <actionGroup ref="addNewTaxRateNoZip" stepKey="addSimpleTaxUK"> + <argument name="taxCode" value="SimpleTaxUK"/> + </actionGroup> + <click stepKey="clickSave" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForNewTaxRuleCreated"/> + + <!-- Go to tax rule page to create second Tax Rule--> + <actionGroup ref="addNewTaxRuleActionGroup" stepKey="addSecondTaxRuleActionGroup"/> + <fillField stepKey="fillSecondRuleName" selector="{{AdminTaxRulesSection.ruleName}}" userInput="{{TaxRuleZeroRate.name}}"/> + <actionGroup ref="addNewTaxRateNoZip" stepKey="addSimpleTaxUKZeroRate"> + <argument name="taxCode" value="SimpleTaxUKZeroRate"/> + </actionGroup> + <actionGroup ref="addCustomerTaxClass" stepKey="addCustomerTaxClass"> + <argument name="customerTaxClassName" value="UK_zero"/> + </actionGroup> + <click stepKey="disableDefaultProdTaxClass" selector="{{AdminTaxRulesSection.defaultCustomerTaxClass}}"/> + <click stepKey="clickSaveBtn" selector="{{AdminStoresMainActionsSection.saveButton}}"/> + <waitForPageLoad stepKey="waitForSecondTaxRuleCreated"/> + + <!--Create a Customer Group (CUSTOMERS > Customer Groups)--> + <actionGroup ref="AdminCreateCustomerGroupActionGroup" stepKey="createCustomerGroup"> + <argument name="groupName" value="test_UK"/> + <argument name="taxClass" value="UK_zero"/> + </actionGroup> + + <!--Set Customer Create New Account Options Config--> + <createData entity="SetCustomerCreateNewAccountOptionsConfig" stepKey="setCustomerCreateNewAccountOptionsConfig"/> + <actionGroup ref="SetGroupForValidVATIdIntraUnionActionGroup" stepKey="setGroupForValidVATIdIntraUnionActionGroup" after="setCustomerCreateNewAccountOptionsConfig"> + <argument name="value" value="test_UK"/> + </actionGroup> + + <!--Register customer on storefront--> + <actionGroup ref="SignUpNewCustomerStorefrontActionGroup" stepKey="createAnAccount"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> + + <!--Go to My account > Address book--> + <actionGroup ref="EnterCustomerAddressInfo" stepKey="enterAddressInfo"> + <argument name="Address" value="UK_Simple_Address"/> + </actionGroup> + + <!-- Go to product visible --> + <amOnPage url="$$createProduct.name$$.html" stepKey="navigateToProductPageOnDefaultStore"/> + <see userInput="$$createProduct.name$$" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertFirstProductNameTitle"/> + + <!--Add a product to the cart--> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForAddProductToCart"/> + <!--Proceed to checkout--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="GoToCheckoutFromMinicartActionGroup"/> + <!-- Click next button to open payment section --> + <click selector="{{CheckoutShippingGuestInfoSection.next}}" stepKey="clickNext"/> + <waitForPageLoad stepKey="waitForShipmentPageLoad"/> + + <!-- Check order summary in checkout --> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <!--Verify that Tax 50% is applied --> + <see userInput="$123.00" selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" stepKey="assertSubtotal"/> + <see userInput="$5.00" selector="{{CheckoutPaymentSection.orderSummaryShippingTotal}}" stepKey="assertShipping"/> + <see userInput="Flat Rate - Fixed" selector="{{CheckoutPaymentSection.orderSummaryShippingMethod}}" stepKey="assertShippingMethod"/> + <see userInput="$61.50" selector="{{CheckoutPaymentSection.tax}}" stepKey="assertTax"/> + <see userInput="$189.50" selector="{{CheckoutPaymentSection.orderSummaryTotal}}" stepKey="assertTotal"/> + + <after> + <!-- Go to the tax rule page and delete the row we created--> + <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> + <waitForPageLoad stepKey="waitForRulesPage"/> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteRule"> + <argument name="name" value="{{TaxRule.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteSecondRule"> + <argument name="name" value="{{TaxRuleZeroRate.name}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <!-- Go to the tax rate page --> + <amOnPage url="{{AdminTaxRateGridPage.url}}" stepKey="goToTaxRatesPage"/> + <waitForPageLoad stepKey="waitForRatesPage"/> + + <!-- Delete the two tax rates that were created --> + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteNYRate"> + <argument name="name" value="{{SimpleTaxUK.state}}-{{SimpleTaxUK.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <actionGroup ref="deleteEntitySecondaryGrid" stepKey="deleteCARate"> + <argument name="name" value="{{SimpleTaxUKZeroRate.state}}-{{SimpleTaxUKZeroRate.rate}}"/> + <argument name="searchInput" value="{{AdminSecondaryGridSection.taxIdentifierSearch}}"/> + </actionGroup> + + <!--Delete created customer group--> + <actionGroup ref="AdminDeleteCustomerGroupActionGroup" stepKey="deleteCustomerGroup"> + <argument name="groupName" value="test_UK"/> + </actionGroup> + + <createData entity="SetCustomerCreateNewAccountOptionsDefaultConfig" stepKey="setCustomerCreateNewAccountOptionsDefaultConfig"/> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategoryFirst"/> + + <actionGroup ref="deleteProductTaxClass" stepKey="deleteFirstProductTaxClass"> + <argument name="taxClassName" value="UK_zero"/> + </actionGroup> + + <!--Log Out--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + </test> +</tests> diff --git a/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml new file mode 100644 index 0000000000000..04d497b4b5246 --- /dev/null +++ b/app/code/Magento/Tax/Test/Mftf/ActionGroup/AdminCustomerTaxClassActionGroup.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!--Add Customer Tax Class--> + <actionGroup name="addCustomerTaxClass"> + <arguments> + <argument name="customerTaxClassName" type="string"/> + </arguments> + <!--Click Additional Settings--> + <click stepKey="clickAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <!--Click Product Add New Tax Class Button--> + <click stepKey="clickCustomerAddNewTaxClassBtn" selector="{{AdminTaxRulesSection.customerAddNewTaxClass}}"/> + <!--Fill field--> + <fillField stepKey="fillCustomerNewTaxClass" selector="{{AdminTaxRulesSection.fieldCustomerNewTaxClass}}" userInput="{{customerTaxClassName}}"/> + <!-- Save Product tax rate --> + <click stepKey="saveProdTaxRate" selector="{{AdminTaxRulesSection.saveCustomerNewTaxClass}}"/> + </actionGroup> + + <!--Delete Product Tax Class--> + <actionGroup name="deleteCustomerTaxClass"> + <arguments> + <argument name="taxClassName" type="string"/> + </arguments> + <!-- Go to tax rule page --> + <amOnPage url="{{AdminNewTaxRulePage.url}}" stepKey="goToNewTaxRulePage"/> + <waitForPageLoad stepKey="waitForTaxRatePage"/> + <click stepKey="clickAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <scrollTo stepKey="scrollToAdditionalSettings" selector="{{AdminTaxRulesSection.additionalSettings}}"/> + <moveMouseOver stepKey="hoverDeleteElement" selector="{{AdminTaxRulesSection.deleteTaxClassName(taxClassName)}}"/> + <click stepKey="deleteFirstTaxClass" selector="{{AdminTaxRulesSection.deleteTaxClass(taxClassName)}}"/> + <waitForElementVisible selector="{{AdminTaxRulesSection.popUpDialogOK}}" stepKey="waitForElementBecomeVisible"/> + <click stepKey="acceptPopUpDialog" selector="{{AdminTaxRulesSection.popUpDialogOK}}"/> + <waitForPageLoad stepKey="waitForProductTaxClassDeleted"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml index 42fd01357375e..7d954bd5e1ac2 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxCodeData.xml @@ -8,6 +8,18 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SimpleTaxUK" type="tax"> + <data key="state">California</data> + <data key="country">United Kingdom</data> + <data key="zip">*</data> + <data key="rate">50</data> + </entity> + <entity name="SimpleTaxUKZeroRate" type="tax"> + <data key="state">California</data> + <data key="country">United Kingdom</data> + <data key="zip">*</data> + <data key="rate">0</data> + </entity> <entity name="SimpleTaxNY" type="tax"> <data key="state">New York</data> <data key="country">United States</data> diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml index b3f341b687ba7..e11f856c5f57c 100644 --- a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml +++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml @@ -23,4 +23,10 @@ </array> <data key="calculate_subtotal">true</data> </entity> + <entity name="TaxRule" type="taxRule"> + <data key="name" unique="suffix">TaxName</data> + </entity> + <entity name="TaxRuleZeroRate" type="taxRule"> + <data key="name" unique="suffix">TaxNameZeroRate</data> + </entity> </entities> diff --git a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml index 9727c649d7e66..539ec4eae11b6 100644 --- a/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml +++ b/app/code/Magento/Tax/Test/Mftf/Section/AdminTaxRulesSection.xml @@ -10,6 +10,10 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminTaxRulesSection"> <!-- on page /admin/tax/rule/new/ --> + <element name="customerAddNewTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//*[contains(text(),'Add New Tax Class')]"/> + <element name="fieldCustomerNewTaxClass" type="input" selector="//*[@id='tax_customer_class']/following-sibling::section//input[@class='mselect-input']"/> + <element name="saveCustomerNewTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//span[@class='mselect-save']"/> + <element name="defaultCustomerTaxClass" type="button" selector="//*[@id='tax_customer_class']/following-sibling::section//div[@class='mselect-items-wrapper']/div[1]"/> <element name="ruleName" type="input" selector="#anchor-content #code"/> <element name="addNewTaxRate" type="block" selector="//*[text()='Add New Tax Rate']" timeout="30"/> <element name="taxIdentifier" type="input" selector="aside #code"/> From 9dc3345ae68c6a90d1a19d58d0ec29bc07d15198 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Thu, 4 Oct 2018 22:20:21 +0300 Subject: [PATCH 013/216] Fix pr --- .../DataProvider/NotificationDataProvider.php | 84 ++-------- .../Magento/Sales/Model/Order/Address.php | 153 +++--------------- .../Sales/Model/Order/Payment/Transaction.php | 39 +---- app/code/Magento/Store/Model/Store.php | 9 +- 4 files changed, 50 insertions(+), 235 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 26e698b67545b..8418b4f9a753d 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -82,9 +82,7 @@ public function __construct( } /** - * Get data - * - * @return mixed + * @inheritdoc */ public function getData() { @@ -97,10 +95,7 @@ public function getData() } /** - * Get Meta - * - * @return array - * @throws \Magento\Framework\Exception\LocalizedException + * @inheritdoc */ public function getMeta() { @@ -112,9 +107,7 @@ public function getMeta() } /** - * Get Data Provider name - * - * @return string + * @inheritdoc */ public function getName() { @@ -122,9 +115,7 @@ public function getName() } /** - * Get config data - * - * @return mixed + * @inheritdoc */ public function getConfigData() { @@ -132,11 +123,7 @@ public function getConfigData() } /** - * Set config data - * - * @param mixed $config - * - * @return bool + * @inheritdoc */ public function setConfigData($config) { @@ -146,13 +133,7 @@ public function setConfigData($config) } /** - * Get Field Meta Info - * - * @param string $fieldSetName - * @param string $fieldName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -160,12 +141,7 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * Get Field Set Meta Info - * - * @param string $fieldSetName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldSetMetaInfo($fieldSetName) { @@ -173,12 +149,7 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * Get Fields Meta Info - * - * @param string $fieldSetName - * - * @return array - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function getFieldsMetaInfo($fieldSetName) { @@ -186,9 +157,7 @@ public function getFieldsMetaInfo($fieldSetName) } /** - * Get Primary Field Name - * - * @return string + * @inheritdoc */ public function getPrimaryFieldName() { @@ -196,9 +165,7 @@ public function getPrimaryFieldName() } /** - * Get Request Field Name - * - * @return string + * @inheritdoc */ public function getRequestFieldName() { @@ -206,47 +173,28 @@ public function getRequestFieldName() } /** - * Add Filter - * - * @param \Magento\Framework\Api\Filter $filter - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function addFilter(\Magento\Framework\Api\Filter $filter) { } /** - * Add Order - * - * @param string $field - * @param string $direction - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function addOrder($field, $direction) { } /** - * Set Limit - * - * @param int $offset - * @param int $size - * - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @inheritdoc */ public function setLimit($offset, $size) { } /** - * Get Search Criteria - * - * @return SearchCriteriaInterface + * @inheritdoc */ public function getSearchCriteria() { @@ -254,9 +202,7 @@ public function getSearchCriteria() } /** - * Get Search Result - * - * @return SearchResultInterface + * @inheritdoc */ public function getSearchResult() { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index 98433899cca26..a19c587216b1c 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -516,11 +516,7 @@ public function setParentId($id) } /** - * Sets the country address ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCustomerAddressId($id) { @@ -528,11 +524,7 @@ public function setCustomerAddressId($id) } /** - * Sets the region ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegionId($id) { @@ -540,11 +532,7 @@ public function setRegionId($id) } /** - * Sets the street values, if any, for the order address. - * - * @param string|string[] $street - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setStreet($street) { @@ -552,11 +540,7 @@ public function setStreet($street) } /** - * Sets the customer ID for the order address. - * - * @param int $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCustomerId($id) { @@ -564,11 +548,7 @@ public function setCustomerId($id) } /** - * Sets the fax number for the order address. - * - * @param string $fax - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setFax($fax) { @@ -576,11 +556,7 @@ public function setFax($fax) } /** - * Sets the region for the order address. - * - * @param string $region - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegion($region) { @@ -588,11 +564,7 @@ public function setRegion($region) } /** - * Sets the postal code for the order address. - * - * @param string $postcode - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setPostcode($postcode) { @@ -600,11 +572,7 @@ public function setPostcode($postcode) } /** - * Sets the last name for the order address. - * - * @param string $lastname - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setLastname($lastname) { @@ -612,11 +580,7 @@ public function setLastname($lastname) } /** - * Sets the city for the order address. - * - * @param string $city - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCity($city) { @@ -624,11 +588,7 @@ public function setCity($city) } /** - * Sets the email address for the order address. - * - * @param string $email - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setEmail($email) { @@ -636,11 +596,7 @@ public function setEmail($email) } /** - * Sets the telephone number for the order address. - * - * @param string $telephone - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setTelephone($telephone) { @@ -648,11 +604,7 @@ public function setTelephone($telephone) } /** - * Sets the country ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCountryId($id) { @@ -660,11 +612,7 @@ public function setCountryId($id) } /** - * Sets the first name for the order address. - * - * @param string $firstname - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setFirstname($firstname) { @@ -672,11 +620,7 @@ public function setFirstname($firstname) } /** - * Sets the address type for the order address. - * - * @param string $addressType - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setAddressType($addressType) { @@ -684,11 +628,7 @@ public function setAddressType($addressType) } /** - * Sets the prefix for the order address. - * - * @param string $prefix - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setPrefix($prefix) { @@ -696,11 +636,7 @@ public function setPrefix($prefix) } /** - * Sets the middle name for the order address. - * - * @param string $middlename - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setMiddlename($middlename) { @@ -708,11 +644,7 @@ public function setMiddlename($middlename) } /** - * Sets the suffix for the order address. - * - * @param string $suffix - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setSuffix($suffix) { @@ -720,11 +652,7 @@ public function setSuffix($suffix) } /** - * Sets the company for the order address. - * - * @param string $company - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setCompany($company) { @@ -732,11 +660,7 @@ public function setCompany($company) } /** - * Sets the VAT ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatId($id) { @@ -744,11 +668,7 @@ public function setVatId($id) } /** - * Sets the VAT-is-valid flag value for the order address. - * - * @param int $vatIsValid - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatIsValid($vatIsValid) { @@ -756,11 +676,7 @@ public function setVatIsValid($vatIsValid) } /** - * Sets the VAT request ID for the order address. - * - * @param string $id - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestId($id) { @@ -768,11 +684,7 @@ public function setVatRequestId($id) } /** - * Set region code - * - * @param string $regionCode - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setRegionCode($regionCode) { @@ -780,11 +692,7 @@ public function setRegionCode($regionCode) } /** - * Sets the VAT request date for the order address. - * - * @param string $vatRequestDate - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestDate($vatRequestDate) { @@ -792,11 +700,7 @@ public function setVatRequestDate($vatRequestDate) } /** - * Sets the VAT-request-success flag value for the order address. - * - * @param int $vatRequestSuccess - * - * @return \Magento\Framework\DataObject|Address + * @inheritdoc */ public function setVatRequestSuccess($vatRequestSuccess) { @@ -804,9 +708,7 @@ public function setVatRequestSuccess($vatRequestSuccess) } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Sales\Api\Data\OrderAddressExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -814,10 +716,7 @@ public function getExtensionAttributes() } /** - * Set an extension attributes object. - * - * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 8f9f275de1658..69e79d71db98b 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -942,11 +942,7 @@ public function getCreatedAt() } /** - * Gets an array of child transactions for the transaction. - * - * @param string $createdAt - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -954,11 +950,7 @@ public function setCreatedAt($createdAt) } /** - * Sets the parent ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setParentId($id) { @@ -966,11 +958,7 @@ public function setParentId($id) } /** - * Sets the order ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setOrderId($id) { @@ -978,11 +966,7 @@ public function setOrderId($id) } /** - * Sets the payment ID for the transaction. - * - * @param int $id - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setPaymentId($id) { @@ -990,11 +974,7 @@ public function setPaymentId($id) } /** - * Sets the value of the is-closed flag for the transaction. - * - * @param int $isClosed - * - * @return TransactionInterface|Transaction + * @inheritdoc */ public function setIsClosed($isClosed) { @@ -1002,9 +982,7 @@ public function setIsClosed($isClosed) } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -1012,10 +990,7 @@ public function getExtensionAttributes() } /** - * Set an extension attributes object. - * - * @param \Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Sales\Api\Data\TransactionExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index c212ebfec845f..ab9b356e7a748 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1386,10 +1386,7 @@ public function getScopeType() } /** - * Get Scope Type Name - * - * @return string - * @since 100.1.0 + * @inheritdoc */ public function getScopeTypeName() { @@ -1397,9 +1394,7 @@ public function getScopeTypeName() } /** - * Retrieve existing extension attributes object or create a new one. - * - * @return \Magento\Store\Api\Data\StoreExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { From 21c32ebe67d3d02a3b2333ab4c925a31bead45cf Mon Sep 17 00:00:00 2001 From: David Grigoryan <david_grigoryan@epam.com> Date: Wed, 3 Oct 2018 10:57:29 +0400 Subject: [PATCH 014/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Add automated test --- .../Test/Mftf/Data/AuthorizenetData.xml | 95 +++++++++++++++++++ .../Mftf/Metadata/authorize-config-meta.xml | 79 +++++++++++++++ .../AuthorizenetConfiguraionSection.xml | 19 ++++ .../AuthorizenetCreditCardInformationTest.xml | 81 ++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml create mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml new file mode 100644 index 0000000000000..c4f59ba03bf22 --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="AuthorizenetConfig" type="authorize_net_config"> + <requiredEntity type="active">Active</requiredEntity> + <requiredEntity type="login">LoginId</requiredEntity> + <requiredEntity type="trans_key">TransactionKey</requiredEntity> + <requiredEntity type="trans_md5">TransMD5</requiredEntity> + <requiredEntity type="test">TestMode</requiredEntity> + <requiredEntity type="useccv">CVVVerification</requiredEntity> + <requiredEntity type="cgi_url">CGI_UTL</requiredEntity> + <requiredEntity type="cgi_url_td">CGI_URL_TD</requiredEntity> + <requiredEntity type="debug">Debug</requiredEntity> + </entity> + <entity name="Active" type="active"> + <data key="value">1</data> + </entity> + <entity name="LoginId" type="login"> + <data key="value">4By5Q8m6</data> + </entity> + <entity name="TransactionKey" type="trans_key"> + <data key="value">9pygB4X4n783TJbw</data> + </entity> + <entity name="TransMD5" type="trans_md5"> + <data key="value">Md5Hash</data> + </entity> + <entity name="TestMode" type="test"> + <data key="value">0</data> + </entity> + <entity name="CVVVerification" type="useccv"> + <data key="value">1</data> + </entity> + <entity name="CGI_UTL" type="cgi_url"> + <data key="value">https://test.authorize.net/gateway/transact.dll</data> + </entity> + <entity name="CGI_URL_TD" type="cgi_url_td"> + <data key="value">https://apitest.authorize.net/xml/v1/request.api</data> + </entity> + <entity name="Debug" type="debug"> + <data key="value">1</data> + </entity> + + <entity name="AuthorizenetDefaultConfig" type="authorize_net_config"> + <requiredEntity type="active">DefaultActive</requiredEntity> + <requiredEntity type="trans_key">DefaultTransactionKey</requiredEntity> + <requiredEntity type="trans_md5">DefaultTransMD5</requiredEntity> + <requiredEntity type="test">DefaultTestMode</requiredEntity> + <requiredEntity type="useccv">DefaultCVVVerification</requiredEntity> + <requiredEntity type="cgi_url">DefaultCGI_UTL</requiredEntity> + <requiredEntity type="cgi_url_td">DefaultCGI_URL_TD</requiredEntity> + <requiredEntity type="debug">DefaultDebugMode</requiredEntity> + </entity> + <entity name="DefaultDebug" type="debug"> + <data key="value">0</data> + </entity> + <entity name="DefaultActive" type="active"> + <data key="value">0</data> + </entity> + <entity name="DefaultLoginId" type="login"> + <data key="value"></data> + </entity> + <entity name="DefaultTransactionKey" type="trans_key"> + <data key="value"></data> + </entity> + <entity name="DefaultTransMD5" type="trans_md5"> + <data key="value"></data> + </entity> + <entity name="DefaultTestMode" type="test"> + <data key="value">1</data> + </entity> + <entity name="DefaultCVVVerification" type="useccv"> + <data key="value">0</data> + </entity> + <entity name="DefaultCGI_UTL" type="cgi_url"> + <data key="value">https://secure.authorize.net/gateway/transact.dll</data> + </entity> + <entity name="DefaultCGI_URL_TD" type="cgi_url_td"> + <data key="value">https://api2.authorize.net/xml/v1/request.api</data> + </entity> + + <entity name="DisableAuthorizenetConfig" type="authorize_net_config"> + <requiredEntity type="disableConfig">DisableConfig</requiredEntity> + </entity> + + <entity name="DisableConfig" type="disableConfig"> + <data key="value">0</data> + </entity> +</entities> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml new file mode 100644 index 0000000000000..ca9bbdad00870 --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="AuthorizeNetConfig" dataType="authorize_net_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> + <object key="groups" dataType="authorize_net_config"> + <object key="authorizenet_directpost" dataType="authorize_net_config"> + <object key="fields" dataType="authorize_net_config"> + <object key="active" dataType="active"> + <field key="value">integer</field> + </object> + <object key="login" dataType="login"> + <field key="value">string</field> + </object> + <object key="trans_key" dataType="trans_key"> + <field key="value">string</field> + </object> + <object key="trans_md5" dataType="trans_md5"> + <field key="value">string</field> + </object> + <object key="test" dataType="test"> + <field key="value">string</field> + </object> + <object key="useccv" dataType="useccv"> + <field key="value">string</field> + </object> + <object key="cgi_url" dataType="cgi_url"> + <field key="value">string</field> + </object> + <object key="cgi_url_td" dataType="cgi_url_td"> + <field key="value">string</field> + </object> + <object key="debug" dataType="debug"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> + + <operation name="AuthorizeNetDefaultConfig" dataType="authorize_net_default_config" type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> + <object key="groups" dataType="authorize_net_default_config"> + <object key="authorizenet_directpost" dataType="authorize_net_default_config"> + <object key="fields" dataType="authorize_net_default_config"> + <object key="active" dataType="authorize_net_default_config"> + <object key="inherit" dataType="disableActive"> + <field key="value">integer</field> + </object> + </object> + <object key="test" dataType="authorize_net_default_config"> + <object key="inherit" dataType="disableConfig"> + <field key="value">integer</field> + </object> + </object> + <object key="cgi_url" dataType="authorize_net_default_config"> + <object key="inherit" dataType="disableConfig"> + <field key="value">integer</field> + </object> + </object> + <object key="cgi_url_td" dataType="authorize_net_default_config"> + <object key="inherit" dataType="disableConfig"> + <field key="value">integer</field> + </object> + </object> + <object key="debug" dataType="authorize_net_default_config"> + <object key="inherit" dataType="disableConfig"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml new file mode 100644 index 0000000000000..5d4f6c3f9819a --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AuthorizenetConfigurationSection"> + <element name="paymentMethod" type="input" selector="#p_method_authorizenet_directpost"/> + <element name="cardType" type="select" selector="#authorizenet_directpost_cc_type"/> + <element name="cardNumber" type="input" selector="#authorizenet_directpost_cc_number"/> + <element name="month" type="select" selector="#authorizenet_directpost_expiration"/> + <element name="year" type="select" selector="#authorizenet_directpost_expiration_yr"/> + <element name="afterTwoYear" type="select" selector="//*[@id='authorizenet_directpost_expiration_yr']/option[4]"/> + <element name="verificationNumber" type="input" selector="#authorizenet_directpost_cc_cid"/> + </section> +</sections> diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml new file mode 100644 index 0000000000000..b5d0b6079bb8b --- /dev/null +++ b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AuthorizenetCreditCardInformationTest"> + <annotations> + <features value="Authorizenet"/> + <stories value="MAGETWO-91526 - Authorize.net Direct Post does not show credit card information"/> + <title value="Checking credit card information of Authorize.net Direct Post"/> + <description value="Checking credit card information of Authorize.net Direct Post"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-91526"/> + <group value="Authorizenet"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> + <createData stepKey="setConfig" entity="AuthorizenetConfig"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createCategory" stepKey="deleteProduct"/> + <deleteData createDataKey="createProduct" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <createData stepKey="setDefaultConfig" entity="AuthorizenetDefaultConfig"/> + <createData stepKey="DisableConfigValues" entity="DisableAuthorizenetConfig"/> + </after> + <!--Create new order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="CreateNewOrder"> + <argument name="customer" value="Simple_US_Customer_NY"/> + </actionGroup> + <!--Add product to order--> + <click selector="{{OrdersGridSection.addProducts}}" stepKey="clickToAddProduct"/> + <waitForPageLoad stepKey="waitForProductsOpened"/> + <click selector="{{OrdersGridSection.selectProduct($$createProduct.name$$)}}" stepKey="selectProduct"/> + <click stepKey="addProductsToOrder" selector="{{OrdersGridSection.addProductsToOrder}}"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <!--Select shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShipping"/> + <!--Fill Card data and submit order--> + <click selector="{{AuthorizenetConfigurationSection.paymentMethod}}" stepKey="clickToSetPaymentMethod"/> + <selectOption selector="{{AuthorizenetConfigurationSection.cardType}}" userInput="Visa" stepKey="SelectCreditCard"/> + <fillField selector="{{AuthorizenetConfigurationSection.cardNumber}}" userInput="4111111111111111" stepKey="fillCardNumber"/> + <selectOption selector="{{AuthorizenetConfigurationSection.month}}" userInput="01 - January" stepKey="SelectMonth"/> + <click selector="{{AuthorizenetConfigurationSection.year}}" stepKey="clickYear"/> + <waitForElementVisible selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="waitForDropDownMenuAppeared"/> + <click selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="selectYear"/> + <fillField selector="{{AuthorizenetConfigurationSection.verificationNumber}}" userInput="123" stepKey="fillVerificationNumber"/> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="SubmitOrder"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <!--Get order ID and open order page--> + <see userinput="You created the order." stepKey="verifyOrderCreated"/> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$getOrderId"/> + </actionGroup> + <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <!--Verify required data--> + <see userinput="Credit Card Direct Post (Authorize.net)" stepKey="checkPaymentMethod"/> + <see userinput="Credit Card Type: MasterCard" stepKey="checkCardType"/> + <see userinput="Credit Card Number: XXXX1111" stepKey="checkCardCode"/> + <see userinput="AVS Response Code:" stepKey="checkAVSResponseCode"/> + <see userinput="Processor Authentication Code:" stepKey="checkProcessorAuthorizationCode"/> + <see userinput="Processor Response Text:" stepKey="checkProcessorResponseText"/> + <see userinput="CVV2 Response Code:" stepKey="checkCVVResponseCode"/> + <see userinput="The order was placed using USD." stepKey="checkCurrency"/> + </test> +</tests> From 1ce85bb8d637310849b2487a035952bf3d23dd20 Mon Sep 17 00:00:00 2001 From: Volodymyr Hryvinskyi <volodymyr@hryvinskyi.com> Date: Wed, 10 Oct 2018 13:34:29 +0300 Subject: [PATCH 015/216] update comments --- .../Ui/DataProvider/NotificationDataProvider.php | 9 ++++++--- app/code/Magento/Sales/Model/Order/Address.php | 6 +++++- .../Magento/Sales/Model/Order/Payment/Transaction.php | 4 +++- app/code/Magento/Store/Model/Store.php | 6 ++++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php index 8418b4f9a753d..737ec1caa7fb1 100644 --- a/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php +++ b/app/code/Magento/ReleaseNotification/Ui/DataProvider/NotificationDataProvider.php @@ -133,7 +133,8 @@ public function setConfigData($config) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldMetaInfo($fieldSetName, $fieldName) { @@ -141,7 +142,8 @@ public function getFieldMetaInfo($fieldSetName, $fieldName) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldSetMetaInfo($fieldSetName) { @@ -149,7 +151,8 @@ public function getFieldSetMetaInfo($fieldSetName) } /** - * @inheritdoc + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function getFieldsMetaInfo($fieldSetName) { diff --git a/app/code/Magento/Sales/Model/Order/Address.php b/app/code/Magento/Sales/Model/Order/Address.php index a19c587216b1c..fcaffb0407b4c 100644 --- a/app/code/Magento/Sales/Model/Order/Address.php +++ b/app/code/Magento/Sales/Model/Order/Address.php @@ -716,7 +716,11 @@ public function getExtensionAttributes() } /** - * @inheritdoc + * {@inheritdoc} + * + * @param \Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes + * + * @return $this */ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderAddressExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php index 69e79d71db98b..8b8865bab2b71 100644 --- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php +++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php @@ -982,7 +982,9 @@ public function setIsClosed($isClosed) } /** - * @inheritdoc + * {@inheritdoc} + * + * @return \Magento\Sales\Api\Data\TransactionExtensionInterface|null */ public function getExtensionAttributes() { diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index ab9b356e7a748..b078942b9e932 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -1378,7 +1378,8 @@ public function getStorePath() } /** - * @inheritdoc + * {@inheritdoc} + * @since 100.1.0 */ public function getScopeType() { @@ -1386,7 +1387,8 @@ public function getScopeType() } /** - * @inheritdoc + * {@inheritdoc} + * @since 100.1.0 */ public function getScopeTypeName() { From 14b3eaf131298ab8e70bdd529789c91821fbe4a2 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen <michiel@controlaltdelete.nl> Date: Sat, 2 Jun 2018 11:20:25 +0200 Subject: [PATCH 016/216] Added checks to see if the payment is available --- .../Observer/SalesOrderBeforeSaveObserver.php | 2 +- .../SalesOrderBeforeSaveObserverTest.php | 28 ++++++++++++++++--- .../Magento/Paypal/Plugin/OrderCanInvoice.php | 4 +++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php index ed8185e6dedeb..465c4916d8abb 100644 --- a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php +++ b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php @@ -21,7 +21,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getOrder(); - if ($order->getPayment()->getMethodInstance()->getCode() != 'free') { + if ($order->getPayment() && $order->getPayment()->getMethodInstance()->getCode() != 'free') { return $this; } diff --git a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php index b86fbc6b18263..47af32d554b68 100644 --- a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php +++ b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php @@ -61,7 +61,7 @@ public function testSalesOrderBeforeSaveCantUnhold() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -86,7 +86,7 @@ public function testSalesOrderBeforeSaveIsCanceled() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -114,7 +114,7 @@ public function testSalesOrderBeforeSaveIsClosed() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -156,6 +156,26 @@ public function testSalesOrderBeforeSaveSetForced() $this->salesOrderBeforeSaveObserver->execute($this->observerMock); } + /** + * The method should check that the payment is available, as this is not always the case. + */ + public function testDoesNothingWhenNoPaymentIsAvailable() + { + $this->_prepareEventMockWithMethods(['getOrder']); + + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class)->disableOriginalConstructor()->setMethods( + array_merge(['__wakeup', 'getPayment']) + )->getMock(); + + $this->eventMock->expects($this->once())->method('getOrder')->will( + $this->returnValue($order) + ); + + $order->expects($this->exactly(1))->method('getPayment')->willReturn(null); + + $this->salesOrderBeforeSaveObserver->execute($this->observerMock); + } + /** * Prepares EventMock with set of methods * @@ -184,7 +204,7 @@ private function _getPreparedOrderMethod($methodCode, $orderMethods = []) $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); diff --git a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php index 87abdf8264503..edb50acc5ee76 100644 --- a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php +++ b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php @@ -40,6 +40,10 @@ public function __construct(Express $express) */ public function afterCanInvoice(Order $order, bool $result): bool { + if (!$order->getPayment()) { + return false; + } + if ($this->express->isOrderAuthorizationAllowed($order->getPayment())) { return false; } From 3eb6c3e70e65fdadc92f30d4faba77751863580c Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Mon, 8 Oct 2018 10:56:15 +0300 Subject: [PATCH 017/216] ENGCOM-2629: Added checks to see if the payment is available #15683 --- .../Payment/Observer/SalesOrderBeforeSaveObserver.php | 9 ++++++++- .../Unit/Observer/SalesOrderBeforeSaveObserverTest.php | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php index 465c4916d8abb..3d520db833164 100644 --- a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php +++ b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php @@ -15,13 +15,20 @@ class SalesOrderBeforeSaveObserver implements ObserverInterface * * @param \Magento\Framework\Event\Observer $observer * @return $this + * @throws \Magento\Framework\Exception\LocalizedException in case order has no payment specified. */ public function execute(\Magento\Framework\Event\Observer $observer) { /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getOrder(); - if ($order->getPayment() && $order->getPayment()->getMethodInstance()->getCode() != 'free') { + if (!$order->getPayment()) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Please provide payment for the order.') + ); + } + + if ($order->getPayment()->getMethodInstance()->getCode() != 'free') { return $this; } diff --git a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php index 47af32d554b68..63ca1b47dc08c 100644 --- a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php +++ b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php @@ -158,6 +158,9 @@ public function testSalesOrderBeforeSaveSetForced() /** * The method should check that the payment is available, as this is not always the case. + * + * @expectedException \Magento\Framework\Exception\LocalizedException + * @exceptedExceptionMessage Please provide payment for the order. */ public function testDoesNothingWhenNoPaymentIsAvailable() { From ff40c182383a75842e915db1c3aeb6ef8476c596 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Tue, 16 Oct 2018 12:47:30 +0300 Subject: [PATCH 018/216] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- .../StorefrontProductCartActionGroup.xml | 14 ++++ ...ProductWithZeroPriceToShoppingCartTest.xml | 77 +++++++++++++++++++ ...ctWithCustomOptionsWithLongValuesTitle.xml | 3 + .../Mftf/ActionGroup/CheckoutActionGroup.xml | 17 +++- .../Mftf/Section/AdminOrdersGridSection.xml | 2 +- 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml index f28ffbdc40acc..e36730a87b41a 100644 --- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StorefrontProductCartActionGroup.xml @@ -24,4 +24,18 @@ <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> <waitForText userInput="{{quantity}}" selector="{{StorefrontMinicartSection.productCount}}" time="30" stepKey="assertProductCount"/> </actionGroup> + + <!-- Add Bundle Product to Cart from the category page --> + <actionGroup name="StorefrontAddBundleProductFromCategoryToCartActionGroup"> + <arguments> + <argument name="productName" type="string"/> + </arguments> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductTitleByName(productName)}}" stepKey="moveMouseOverProduct"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName(productName)}}" stepKey="openProductPage"/> + <waitForPageLoad time="30" stepKey="waitForBundleProductPageLoad"/> + <click selector="{{StorefrontBundledSection.addToCart}}" stepKey="clickCustomizeAndAddToCart"/> + <click selector="{{StorefrontBundledSection.addToCartConfigured}}" stepKey="clickAddBundleProductToCart"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.productCount}}" stepKey="waitProductCount"/> + <see userInput="You added {{productName}} to your shopping cart." selector="{{StorefrontMessagesSection.success}}" stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml new file mode 100644 index 0000000000000..71aaf76c42e84 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontAddBundleProductWithZeroPriceToShoppingCartTest"> + <annotations> + <features value="Bundle"/> + <stories value="Add Bundle product with zero price to shopping cart"/> + <title value="Add Bundle product with zero price to shopping cart"/> + <description value="Add Bundle product with zero price to shopping cart"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-95167"/> + <group value="bundle"/> + </annotations> + <before> + <!--Enable freeShipping--> + <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> + <!--Create category--> + <createData entity="SimpleSubCategory" stepKey="createSubCategory"/> + <!--Create simple with zero price product--> + <createData entity="ApiProductWithDescription" stepKey="apiSimple"> + <field key="price">0</field> + </createData> + <!--Create Bundle product--> + <createData entity="ApiBundleProductPriceViewRange" stepKey="apiBundleProduct"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <!--Create Attribute--> + <createData entity="DropDownBundleOption" stepKey="bundleOption"> + <requiredEntity createDataKey="apiBundleProduct"/> + </createData> + <createData entity="ApiBundleLink" stepKey="createBundleLink"> + <requiredEntity createDataKey="apiBundleProduct"/> + <requiredEntity createDataKey="bundleOption"/> + <requiredEntity createDataKey="apiSimple"/> + </createData> + <magentoCLI command="indexer:reindex" stepKey="reindex"/> + </before> + <after> + <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShipping"/> + <deleteData createDataKey="apiSimple" stepKey="deleteSimple"/> + <deleteData createDataKey="apiBundleProduct" stepKey="deleteBundleProduct"/> + <deleteData createDataKey="createSubCategory" stepKey="deleteCategory"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Open category page--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSubCategory.custom_attributes[url_key]$$)}}" stepKey="amOnCategoryPage"/> + <!--Add bundle product to cart--> + <actionGroup ref="StorefrontAddBundleProductFromCategoryToCartActionGroup" stepKey="addBundleProductToCart"> + <argument name="productName" value="$$apiBundleProduct.name$$"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + + <!--Place order--> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"> + <argument name="shippingMethod" value="Free Shipping"/> + </actionGroup> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="checkoutPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + + <!--Check subtotal in created order--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <scrollTo selector="{{AdminOrderTotalSection.subTotal}}" stepKey="scrollToOrderTotalSection"/> + <see selector="{{AdminOrderTotalSection.subTotal}}" userInput="$0.00" stepKey="checkSubtotal"/> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml index a03636e52ee97..32d141d7e533e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml @@ -33,6 +33,8 @@ <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + <actionGroup ref="logout" stepKey="logout"/> </after> <!-- Login Customer Storefront --> @@ -86,6 +88,7 @@ <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearFilters"/> <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 32d6ad8667029..d3dbf34c010c8 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -19,8 +19,10 @@ <!-- Guest checkout filling shipping section --> <actionGroup name="GuestCheckoutFillingShippingSectionActionGroup"> <arguments> - <argument name="customerVar"/> - <argument name="customerAddressVar"/> + <argument name="customerVar" defaultValue="CustomerEntityOne"/> + <argument name="customerAddressVar" defaultValue="CustomerAddressSimple"/> + <!--First available shipping method will be selected if value is not passed for shippingMethod--> + <argument name="shippingMethod" defaultValue="" type="string"/> </arguments> <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{customerVar.email}}" stepKey="enterEmail"/> <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> @@ -31,7 +33,7 @@ <fillField selector="{{CheckoutShippingSection.postcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> - <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <click selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('shippingMethod')}}" stepKey="selectShippingMethod"/> <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> @@ -154,6 +156,7 @@ <conditionalClick selector="{{CheckoutCartSummarySection.shippingHeading}}" dependentSelector="{{CheckoutCartSummarySection.country}}" visible="false" stepKey="openShippingDetails"/> <see selector="{{CheckoutCartSummarySection.countryParameterized('placeNumber')}}" userInput="{{country}}" stepKey="seeCountry"/> </actionGroup> + <actionGroup name="StorefrontSignOutActionGroup"> <click selector="{{StoreFrontSignOutSection.customerAccount}}" stepKey="clickCustomerButton"/> <click selector="{{StoreFrontSignOutSection.signOut}}" stepKey="clickToSignOut"/> @@ -161,4 +164,10 @@ <see userInput="You are signed out" stepKey="signOut"/> </actionGroup> -</actionGroups> \ No newline at end of file + <!--Click Place Order button--> + <actionGroup name="ClickPlaceOrderActionGroup"> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <see selector="{{CheckoutSuccessMainSection.successTitle}}" userInput="Thank you for your purchase!" stepKey="waitForLoadSuccessPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 7ece18fb863b7..5e36a8f776628 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -22,7 +22,7 @@ <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> <element name="createNewOrder" type="button" selector=".page-actions-buttons button#add" timeout="30"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)" timeout="30"/> <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="viewBookmarkDropdown" type="button" selector="div.admin__data-grid-action-bookmarks button" timeout="30"/> From d225cef871e16937df45f3ea138debed41aadf8b Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 18 Oct 2018 10:45:49 +0300 Subject: [PATCH 019/216] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- .../Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 5e36a8f776628..7ece18fb863b7 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -22,7 +22,7 @@ <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> <element name="createNewOrder" type="button" selector=".page-actions-buttons button#add" timeout="30"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)" timeout="30"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="viewBookmarkDropdown" type="button" selector="div.admin__data-grid-action-bookmarks button" timeout="30"/> From 690dd08208b8bbb98f747e31356a72334d1f7f8c Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Thu, 18 Oct 2018 15:01:37 +0300 Subject: [PATCH 020/216] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- ...rontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml | 2 +- .../Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml index 32d141d7e533e..f263ff85dd737 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductWithCustomOptionsWithLongValuesTitle.xml @@ -72,7 +72,7 @@ <conditionalClick selector="{{CheckoutPaymentSection.ProductOptionsByProductItemName($$createProduct.name$$)}}" dependentSelector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($$createProduct.name$$)}}" visible="false" stepKey="exposeProductOptions"/> <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName($$createProduct.name$$)}}" userInput="{{ProductOptionValueDropdownLongTitle1.title}}" stepKey="seeProductOptionValueDropdown1Input1"/> - + <click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <!-- Place Order --> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml index 9dd2127fa28b2..99ba9cf3fcb67 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminCreateCustomerTest.xml @@ -19,6 +19,9 @@ <group value="customer"/> <group value="create"/> </annotations> + <before> + <magentoCLI command="indexer:reindex customer_grid" stepKey="reindexCustomerGrid"/> + </before> <after> <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> </after> From f672382b8e18a40163b53b2db60589ed388538b3 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Fri, 19 Oct 2018 12:24:28 +0300 Subject: [PATCH 021/216] MAGETWO-95169: Add Bundle product with zero price to shopping cart --- ...StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml index 71aaf76c42e84..33181d6e920eb 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -71,6 +71,7 @@ <argument name="orderId" value="$grabOrderNumber"/> </actionGroup> <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <waitForPageLoad stepKey="waitForAdminOrderPageLoad"/> <scrollTo selector="{{AdminOrderTotalSection.subTotal}}" stepKey="scrollToOrderTotalSection"/> <see selector="{{AdminOrderTotalSection.subTotal}}" userInput="$0.00" stepKey="checkSubtotal"/> </test> From 7bc9c31cdba8a4c4aca2c7fe3276688124b9b75a Mon Sep 17 00:00:00 2001 From: Patrick McLain <pat@pmclain.com> Date: Tue, 23 Oct 2018 08:23:45 -0400 Subject: [PATCH 022/216] Collect totals in placeOrder when no paymentMethod provided Quote item values such as `base_original_price` are only populated during total collection. Currently in `QuoteManagement::placeOrder` if `$paymentMethod` is passed `Payment::importData` collects the quote totals to populate these values. Payment methods like Auth.net DirectPost do pass a value for `$paymentMethod` during order placement which causes order items to be converted with zero values for the `original_price` attributes. Fixes #16050 --- app/code/Magento/Quote/Model/QuoteManagement.php | 2 ++ app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 451ad08d425f5..9084ca8066301 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -349,6 +349,8 @@ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) $data = $paymentMethod->getData(); $quote->getPayment()->importData($data); + } else { + $quote->collectTotals(); } if ($quote->getCheckoutMethod() === self::METHOD_GUEST) { diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php index 107445bb18d2a..72e516e35cd6e 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php @@ -188,6 +188,7 @@ protected function setUp() 'setCustomerGroupId', 'assignCustomer', 'getPayment', + 'collectTotals' ]); $this->quoteAddressFactory = $this->createPartialMock( @@ -687,6 +688,7 @@ public function testPlaceOrderIfCustomerIsGuest() $service->expects($this->once())->method('submit')->willReturn($orderMock); $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId); + $this->quoteMock->expects($this->once())->method('collectTotals')->willReturnSelf(); $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId); $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId); From 389a16b3b2c6cf308c130b09cd08ab75c54dd88c Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Wed, 24 Oct 2018 09:49:01 -0500 Subject: [PATCH 023/216] ENGCOM-3257: Collect totals in placeOrder when no paymentMethod provided #18768 --- app/code/Magento/Quote/Model/QuoteManagement.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php index 9084ca8066301..6ed8393f80658 100644 --- a/app/code/Magento/Quote/Model/QuoteManagement.php +++ b/app/code/Magento/Quote/Model/QuoteManagement.php @@ -159,7 +159,7 @@ class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository * @param \Magento\Customer\Model\CustomerFactory $customerModelFactory - * @param \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory, + * @param \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper * @param StoreManagerInterface $storeManager * @param \Magento\Checkout\Model\Session $checkoutSession @@ -221,7 +221,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function createEmptyCart() { @@ -241,7 +241,7 @@ public function createEmptyCart() } /** - * {@inheritdoc} + * @inheritdoc */ public function createEmptyCartForCustomer($customerId) { @@ -257,7 +257,7 @@ public function createEmptyCartForCustomer($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function assignCustomer($cartId, $customerId, $storeId) { @@ -332,7 +332,7 @@ protected function createCustomerCart($customerId, $storeId) } /** - * {@inheritdoc} + * @inheritdoc */ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) { @@ -381,7 +381,7 @@ public function placeOrder($cartId, PaymentInterface $paymentMethod = null) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCartForCustomer($customerId) { @@ -408,6 +408,8 @@ public function submit(QuoteEntity $quote, $orderData = []) } /** + * Convert quote items to order items for quote + * * @param Quote $quote * @return array */ From b25c01f70567e86ab3d2a6ed63faa37362b8ab00 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Fri, 26 Oct 2018 16:12:59 +0300 Subject: [PATCH 024/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page --- .../Adminhtml/Edit/Address/CancelButton.php | 41 + .../Adminhtml/Edit/Address/DeleteButton.php | 52 + .../Adminhtml/Edit/Address/GenericButton.php | 110 ++ .../Adminhtml/Edit/Address/SaveButton.php | 33 + .../Address/AbstractDefaultAddress.php | 99 ++ .../Address/DefaultBillingAddress.php | 39 + .../Address/DefaultShippingAddress.php | 39 + .../Controller/Adminhtml/Address/Delete.php | 65 + .../Adminhtml/Address/MassDelete.php | 87 ++ .../Controller/Adminhtml/Address/Save.php | 149 +++ .../Controller/Adminhtml/Address/Validate.php | 97 ++ .../Adminhtml/File/Address/Upload.php | 28 +- .../Controller/Adminhtml/Index/Save.php | 21 +- .../Controller/Adminhtml/Index/Validate.php | 39 +- .../Customer/Model/Address/DataProvider.php | 574 +++++++++ .../DataProviderWithDefaultAddresses.php | 585 +++++++++ .../Customer/Model/Metadata/Form/File.php | 2 +- .../ResourceModel/Address/Grid/Collection.php | 171 +++ .../Model/ResourceModel/Address/Relation.php | 15 +- .../ResourceModel/CustomerRepository.php | 54 +- .../Test/Unit/Controller/Address/SaveTest.php | 205 ++++ .../Unit/Controller/Address/ValidateTest.php | 118 ++ .../Controller/Adminhtml/Index/SaveTest.php | 226 +--- .../Adminhtml/Index/ValidateTest.php | 28 - .../Unit/Model/Address/DataProviderTest.php | 233 ++++ .../DataProviderWithDefaultAddressesTest.php | 1065 +++++++++++++++++ .../ResourceModel/CustomerRepositoryTest.php | 126 -- .../Ui/Component/Form/AddressFieldsetTest.php | 69 ++ .../Ui/Component/Form/AddressFieldset.php | 45 + .../Listing/Address/Column/Actions.php | 134 +++ .../Listing/Address/Column/Countries.php | 37 + app/code/Magento/Customer/etc/db_schema.xml | 9 + app/code/Magento/Customer/etc/di.xml | 9 + .../layout/customer_address_edit.xml | 15 + .../ui_component/customer_address_form.xml | 230 ++++ .../ui_component/customer_address_listing.xml | 171 +++ .../web/js/address/default-address-block.js | 17 + .../web/js/address/default-address.js | 44 + .../view/adminhtml/web/js/address/modal.js | 203 ++++ .../web/js/form/components/insert-form.js | 164 +++ .../web/template/default-address.html | 42 + .../view/base/ui_component/customer_form.xml | 357 +++--- .../Component/Form/Element/DataType/Media.php | 1 + .../Magento/Ui/Component/Form/Fieldset.php | 14 +- app/code/Magento/Ui/Component/Layout/Tabs.php | 4 + .../Test/Unit/Component/Form/FieldsetTest.php | 69 ++ .../base/web/js/form/components/collection.js | 7 +- .../web/js/form/components/collection/item.js | 5 +- .../view/base/web/templates/form/insert.html | 3 - .../web/css/source/_module.less | 72 +- .../Controller/Adminhtml/Address/SaveTest.php | 222 ++++ .../Test/Php/_files/blacklist/strict_type.txt | 2 +- .../config/customerConfig.xml | 2 +- 53 files changed, 5529 insertions(+), 719 deletions(-) create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php create mode 100644 app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php create mode 100644 app/code/Magento/Customer/Model/Address/DataProvider.php create mode 100644 app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php create mode 100644 app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php create mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php create mode 100644 app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php create mode 100644 app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php create mode 100644 app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/template/default-address.html create mode 100644 app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php new file mode 100644 index 0000000000000..80d9780f819d0 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Block\Adminhtml\Edit\GenericButton; + +/** + * Class CancelButton + */ +class CancelButton extends GenericButton implements ButtonProviderInterface +{ + /** + * {@inheritdoc} + * + * @return array + */ + public function getButtonData() + { + return [ + 'label' => __('Cancel'), + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', + 'actionName' => 'closeModal' + ], + ], + ], + ], + ], + 'sort_order' => 20 + ]; + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php new file mode 100644 index 0000000000000..8375aa13fdeff --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -0,0 +1,52 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Ui\Component\Listing\Address\Column\Actions; + +/** + * Delete button on edit customer address form + */ +class DeleteButton extends GenericButton implements ButtonProviderInterface +{ + /** + * Get delete button data. + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getButtonData() + { + $data = []; + if ($this->getAddressId()) { + $data = [ + 'label' => __('Delete'), + 'class' => 'delete', + 'on_click' => 'deleteConfirm(\'' . __( + 'Are you sure you want to delete this address?' + ) . '\', \'' . $this->getDeleteUrl() . '\')', + 'sort_order' => 15, + ]; + } + return $data; + } + + /** + * Get delete button url. + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getDeleteUrl(): string + { + return $this->getUrl( + Actions::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $this->getCustomerId(), 'id' => $this->getAddressId()] + ); + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php new file mode 100644 index 0000000000000..ae09ee6896891 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/GenericButton.php @@ -0,0 +1,110 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Customer\Model\AddressFactory; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\UrlInterface; +use Magento\Customer\Model\ResourceModel\Address; +use Magento\Customer\Model\ResourceModel\AddressRepository; + +/** + * Class for common code for buttons on the create/edit address form + */ +class GenericButton +{ + /** + * @var AddressFactory + */ + private $addressFactory; + + /** + * @var UrlInterface + */ + private $urlBuilder; + + /** + * @var Address + */ + private $addressResourceModel; + + /** + * @var RequestInterface + */ + private $request; + + /** + * @var AddressRepository + */ + private $addressRepository; + + /** + * @param AddressFactory $addressFactory + * @param UrlInterface $urlBuilder + * @param Address $addressResourceModel + * @param RequestInterface $request + * @param AddressRepository $addressRepository + */ + public function __construct( + AddressFactory $addressFactory, + UrlInterface $urlBuilder, + Address $addressResourceModel, + RequestInterface $request, + AddressRepository $addressRepository + ) { + $this->addressFactory = $addressFactory; + $this->urlBuilder = $urlBuilder; + $this->addressResourceModel = $addressResourceModel; + $this->request = $request; + $this->addressRepository = $addressRepository; + } + + /** + * Return address Id. + * + * @return int|null + */ + public function getAddressId() + { + $address = $this->addressFactory->create(); + + $entityId = $this->request->getParam('entity_id'); + $this->addressResourceModel->load( + $address, + $entityId + ); + + return $address->getEntityId() ?: null; + } + + /** + * Get customer id. + * + * @return int|null + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getCustomerId() + { + $addressId = $this->request->getParam('entity_id'); + + $address = $this->addressRepository->getById($addressId); + + return $address->getCustomerId() ?: null; + } + + /** + * Generate url by route and parameters + * + * @param string $route + * @param array $params + * @return string + */ + public function getUrl($route = '', array $params = []): string + { + return $this->urlBuilder->getUrl($route, $params); + } +} diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php new file mode 100644 index 0000000000000..706ef32c9e5a5 --- /dev/null +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Block\Adminhtml\Edit\Address; + +use Magento\Framework\View\Element\UiComponent\Control\ButtonProviderInterface; +use Magento\Customer\Block\Adminhtml\Edit\GenericButton; + +/** + * Class SaveButton + */ +class SaveButton extends GenericButton implements ButtonProviderInterface +{ + /** + * {@inheritdoc} + * + * @return array + */ + public function getButtonData() + { + return [ + 'label' => __('Save'), + 'class' => 'save primary', + 'data_attribute' => [ + 'mage-init' => ['button' => ['event' => 'save']], + 'form-role' => 'save', + ], + 'sort_order' => 10 + ]; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php new file mode 100644 index 0000000000000..a2f9d12282188 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -0,0 +1,99 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\Phrase; +use Psr\Log\LoggerInterface; + +/** + * Abstract class for customer default addresses changing + */ +abstract class AbstractDefaultAddress extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param LoggerInterface $logger + */ + public function __construct( + Action\Context $context, + \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, + LoggerInterface $logger + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + $this->logger = $logger; + } + + /** + * Execute action to change customer default address + * + * @return \Magento\Framework\Controller\Result\Redirect + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('id', false); + if ($addressId) { + try { + $address = $this->addressRepository->getById($addressId)->setCustomerId($customerId); + $this->setAddressAsDefault($address); + $this->addressRepository->save($address); + + $this->messageManager->addSuccessMessage($this->getSuccessMessage()); + } catch (\Exception $other) { + $this->logger->critical($other); + $this->messageManager->addExceptionMessage($other, $this->getExceptionMessage()); + } + } + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } + + /** + * Set passed address as customer's default address + * + * @param \Magento\Customer\Api\Data\AddressInterface $address + * @return $this + */ + abstract protected function setAddressAsDefault($address); + + /** + * Get success message about default address changed + * + * @return \Magento\Framework\Phrase + */ + abstract protected function getSuccessMessage(): Phrase; + + /** + * Get error message about unsuccessful attempt to change default address + * + * @return \Magento\Framework\Phrase + */ + abstract protected function getExceptionMessage(): Phrase; +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php new file mode 100644 index 0000000000000..bd921a5a6642e --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultBillingAddress.php @@ -0,0 +1,39 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Phrase; + +/** + * Class to process default billing address setting + */ +class DefaultBillingAddress extends AbstractDefaultAddress +{ + /** + * @inheritdoc + */ + protected function setAddressAsDefault($address) + { + $address->setIsDefaultBilling(true); + } + + /** + * @inheritdoc + */ + protected function getSuccessMessage(): Phrase + { + return __('Default billing address has been changed.'); + } + + /** + * @inheritdoc + */ + protected function getExceptionMessage(): Phrase + { + return __('We can\'t change default billing address right now.'); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php new file mode 100644 index 0000000000000..7d5bef9ab5be9 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/DefaultShippingAddress.php @@ -0,0 +1,39 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Phrase; + +/** + * Class to process default shipping address setting + */ +class DefaultShippingAddress extends AbstractDefaultAddress +{ + /** + * @inheritdoc + */ + protected function setAddressAsDefault($address) + { + $address->setIsDefaultShipping(true); + } + + /** + * @inheritdoc + */ + protected function getSuccessMessage(): Phrase + { + return __('Default shipping address has been changed.'); + } + + /** + * @inheritdoc + */ + protected function getExceptionMessage(): Phrase + { + return __('We can\'t change default shipping address right now.'); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php new file mode 100644 index 0000000000000..8443c777546f6 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -0,0 +1,65 @@ +<?php +/** + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; + +/** + * Button for deletion of customer address in admin * + */ +class Delete extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + */ + public function __construct( + Action\Context $context, + AddressRepositoryInterface $addressRepository + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + } + + /** + * Delete action + * + * @return \Magento\Framework\Controller\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('id', false); + if ($addressId && $this->addressRepository->getById($addressId)->getCustomerId() === $customerId) { + try { + $this->addressRepository->deleteById($addressId); + $this->messageManager->addSuccessMessage(__('You deleted the address.')); + } catch (\Exception $other) { + $this->messageManager->addExceptionMessage($other, __('We can\'t delete the address right now.')); + } + } + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php new file mode 100644 index 0000000000000..f022ea36f420d --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Framework\Controller\ResultFactory; +use Magento\Backend\App\Action\Context; +use Magento\Ui\Component\MassAction\Filter; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; + +/** + * Class to delete selected customer addresses through massaction + */ +class MassDelete extends \Magento\Backend\App\Action +{ + /** + * Authorization level of a basic admin session + * + * @see MassDelete::_isAllowed() + */ + const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var Filter + */ + protected $filter; + + /** + * @var CollectionFactory + */ + protected $collectionFactory; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @param Context $context + * @param Filter $filter + * @param CollectionFactory $collectionFactory + * @param AddressRepositoryInterface $addressRepository + */ + public function __construct( + Context $context, + Filter $filter, + CollectionFactory $collectionFactory, + AddressRepositoryInterface $addressRepository + ) { + $this->filter = $filter; + $this->collectionFactory = $collectionFactory; + $this->addressRepository = $addressRepository; + parent::__construct($context); + } + + /** + * Execute action + * + * @return \Magento\Backend\Model\View\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException|\Exception + */ + public function execute() + { + /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ + $collection = $this->filter->getCollection($this->collectionFactory->create()); + $collectionSize = $collection->getSize(); + + // Get id of the first item from addresses collection for providing it to the ResultRedirect and build a + // proper redirect URL + $customerId = $collection->getFirstItem()->getParentId(); + + /** @var \Magento\Customer\Model\Address $address */ + foreach ($collection as $address) { + $this->addressRepository->deleteById($address->getId()); + } + $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been deleted.', $collectionSize)); + + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + + return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php new file mode 100644 index 0000000000000..df041ac4e1202 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -0,0 +1,149 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\Controller\Result\Redirect; +use Psr\Log\LoggerInterface; + +/** + * Class for saving of customer address + */ +class Save extends Action +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface + */ + private $addressRepository; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory + */ + private $formFactory; + + /** + * @var \Magento\Customer\Api\CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var \Magento\Framework\Api\DataObjectHelper + */ + private $dataObjectHelper; + + /** + * @var \Magento\Customer\Api\Data\AddressInterfaceFactory + */ + private $addressDataFactory; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @param Action\Context $context + * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository + * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper + * @param \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory + * @param LoggerInterface $logger + */ + public function __construct( + Action\Context $context, + \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, + \Magento\Customer\Model\Metadata\FormFactory $formFactory, + \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, + \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, + \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory, + LoggerInterface $logger + ) { + parent::__construct($context); + $this->addressRepository = $addressRepository; + $this->formFactory = $formFactory; + $this->customerRepository = $customerRepository; + $this->dataObjectHelper = $dataObjectHelper; + $this->addressDataFactory = $addressDataFactory; + $this->logger = $logger; + } + + /** + * Execute action to save customer address + * + * @return \Magento\Framework\Controller\Result\Redirect + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function execute(): Redirect + { + $customerId = $this->getRequest()->getParam('parent_id', false); + $addressId = $this->getRequest()->getParam('entity_id', false); + /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ + $customer = $this->customerRepository->getById($customerId); + + try { + $addressForm = $this->formFactory->create( + 'customer_address', + 'adminhtml_customer_address', + [], + false, + false + ); + $addressData = $addressForm->extractData($this->getRequest()); + $addressData = $addressForm->compactData($addressData); + + $addressData['region'] = [ + 'region' => $addressData['region'] ?? null, + 'region_id' => $addressData['region_id'] ?? null, + ]; + $addressToSave = $this->addressDataFactory->create(); + $this->dataObjectHelper->populateWithArray( + $addressToSave, + $addressData, + \Magento\Customer\Api\Data\AddressInterface::class + ); + $addressToSave->setCustomerId($customer->getId()); + $addressToSave->setIsDefaultBilling( + (bool)$this->getRequest()->getParam('default_billing', false) + ); + $addressToSave->setIsDefaultShipping( + (bool)$this->getRequest()->getParam('default_shipping', false) + ); + if ($addressId) { + $addressToSave->setId($addressId); + $saveMessage = __('Customer address has been updated.'); + } else { + $addressToSave->setId(null); + $saveMessage = __('New customer address has been added.'); + } + + $this->addressRepository->save($addressToSave); + $this->messageManager->addSuccessMessage($saveMessage); + } catch (\Magento\Framework\Exception\LocalizedException $e) { + $this->messageManager->addErrorMessage($e->getMessage()); + $this->logger->critical($e); + } catch (\Exception $e) { + $this->messageManager->addExceptionMessage( + $e, __('We can\'t change customer address right now.') + ); + } + + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath( + 'customer/index/edit', + ['id' => $customerId, '_current' => true] + ); + return $resultRedirect; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php new file mode 100644 index 0000000000000..01ce720a20e63 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface; + +/** + * Class for validation of customer address form on admin. + */ +class Validate extends \Magento\Backend\App\Action implements HttpPostActionInterface, HttpGetActionInterface +{ + /** + * Authorization level of a basic admin session + * + * @see _isAllowed() + */ + public const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var \Magento\Framework\Controller\Result\JsonFactory + */ + private $resultJsonFactory; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory + */ + private $formFactory; + + /** + * @param Action\Context $context + * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + */ + public function __construct( + Action\Context $context, + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Customer\Model\Metadata\FormFactory $formFactory + ) { + parent::__construct($context); + $this->resultJsonFactory = $resultJsonFactory; + $this->formFactory = $formFactory; + } + + /** + * AJAX customer validation action + * + * @return \Magento\Framework\Controller\Result\Json + */ + public function execute() + { + /** @var \Magento\Framework\DataObject $response */ + $response = new \Magento\Framework\DataObject(); + $response->setError(0); + + /** @var \Magento\Framework\DataObject $validatedResponse */ + $validatedResponse = $this->validateCustomerAddress($response); + $resultJson = $this->resultJsonFactory->create(); + if ($validatedResponse->getError()) { + $validatedResponse->setError(true); + $validatedResponse->setMessages($response->getMessages()); + } + + $resultJson->setData($validatedResponse); + + return $resultJson; + } + + /** + * Customer address validation. + * + * @param \Magento\Framework\DataObject $response + * @return \Magento\Framework\DataObject + */ + private function validateCustomerAddress(\Magento\Framework\DataObject $response) + { + $addressForm = $this->formFactory->create('customer_address', 'adminhtml_customer_address'); + $formData = $addressForm->extractData($this->getRequest()); + + $errors = $addressForm->validateData($formData); + if ($errors !== true) { + $messages = $response->hasMessages() ? $response->getMessages() : []; + foreach ($errors as $error) { + $messages[] = $error; + } + $response->setMessages($messages); + $response->setError(1); + } + + return $response; + } +} diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index 506eac3230200..be1b1aec7b3a3 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -14,6 +14,9 @@ use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; +/** + * Uploads files for customer address + */ class Upload extends Action { /** @@ -38,21 +41,29 @@ class Upload extends Action */ private $logger; + /** + * @var string + */ + private $scope; + /** * @param Context $context * @param FileUploaderFactory $fileUploaderFactory * @param AddressMetadataInterface $addressMetadataService * @param LoggerInterface $logger + * @param string $scope */ public function __construct( Context $context, FileUploaderFactory $fileUploaderFactory, AddressMetadataInterface $addressMetadataService, - LoggerInterface $logger + LoggerInterface $logger, + string $scope = 'address' ) { $this->fileUploaderFactory = $fileUploaderFactory; $this->addressMetadataService = $addressMetadataService; $this->logger = $logger; + $this->scope = $scope; parent::__construct($context); } @@ -69,14 +80,14 @@ public function execute() // Must be executed before any operations with $_FILES! $this->convertFilesArray(); - $attributeCode = key($_FILES['address']['name']); + $attributeCode = key($_FILES[$this->scope]['name']); $attributeMetadata = $this->addressMetadataService->getAttributeMetadata($attributeCode); /** @var FileUploader $fileUploader */ $fileUploader = $this->fileUploaderFactory->create([ 'attributeMetadata' => $attributeMetadata, 'entityTypeCode' => AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'scope' => 'address', + 'scope' => $this->scope, ]); $errors = $fileUploader->validate(); @@ -114,14 +125,11 @@ public function execute() */ private function convertFilesArray() { - foreach ($_FILES['address'] as $itemKey => $item) { - foreach ($item as $value) { - if (is_array($value)) { - $_FILES['address'][$itemKey] = [ - key($value) => current($value), - ]; - } + foreach ($_FILES as $itemKey => $item) { + foreach ($item as $fieldName => $value) { + $_FILES[$this->scope][$fieldName] = [$itemKey => $value]; } + unset($_FILES[$itemKey]); } } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index 45a7c0182d41c..aed7908337ee1 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -108,6 +108,7 @@ protected function _extractData( /** * Saves default_billing and default_shipping flags for customer address * + * @deprecated must be removed because addresses are save separately for now * @param array $addressIdList * @param array $extractedCustomerData * @return array @@ -150,6 +151,7 @@ protected function saveDefaultFlags(array $addressIdList, array & $extractedCust /** * Reformat customer addresses data to be compatible with customer service interface * + * @deprecated must be removed because addresses are save separately for now * @param array $extractedCustomerData * @return array */ @@ -188,7 +190,6 @@ public function execute() try { // optional fields might be set in request for future processing by observers in other modules $customerData = $this->_extractCustomerData(); - $addressesData = $this->_extractCustomerAddressData($customerData); if ($customerId) { $currentCustomer = $this->_customerRepository->getById($customerId); @@ -206,28 +207,12 @@ public function execute() $customerData, \Magento\Customer\Api\Data\CustomerInterface::class ); - $addresses = []; - foreach ($addressesData as $addressData) { - $region = isset($addressData['region']) ? $addressData['region'] : null; - $regionId = isset($addressData['region_id']) ? $addressData['region_id'] : null; - $addressData['region'] = [ - 'region' => $region, - 'region_id' => $regionId, - ]; - $addressDataObject = $this->addressDataFactory->create(); - $this->dataObjectHelper->populateWithArray( - $addressDataObject, - $addressData, - \Magento\Customer\Api\Data\AddressInterface::class - ); - $addresses[] = $addressDataObject; - } $this->_eventManager->dispatch( 'adminhtml_customer_prepare_save', ['customer' => $customer, 'request' => $this->getRequest()] ); - $customer->setAddresses($addresses); + if (isset($customerData['sendemail_store_id'])) { $customer->setStoreId($customerData['sendemail_store_id']); } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php index be09eb7daff76..67adf98d6c718 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php @@ -72,40 +72,6 @@ protected function _validateCustomer($response) return $customer; } - /** - * Customer address validation. - * - * @param \Magento\Framework\DataObject $response - * @return void - */ - protected function _validateCustomerAddress($response) - { - $addresses = $this->getRequest()->getPost('address'); - if (!is_array($addresses)) { - return; - } - foreach (array_keys($addresses) as $index) { - if ($index == '_template_') { - continue; - } - - $addressForm = $this->_formFactory->create('customer_address', 'adminhtml_customer_address'); - - $requestScope = sprintf('address/%s', $index); - $formData = $addressForm->extractData($this->getRequest(), $requestScope); - - $errors = $addressForm->validateData($formData); - if ($errors !== true) { - $messages = $response->hasMessages() ? $response->getMessages() : []; - foreach ($errors as $error) { - $messages[] = $error; - } - $response->setMessages($messages); - $response->setError(1); - } - } - } - /** * AJAX customer validation action * @@ -116,10 +82,7 @@ public function execute() $response = new \Magento\Framework\DataObject(); $response->setError(0); - $customer = $this->_validateCustomer($response); - if ($customer) { - $this->_validateCustomerAddress($response); - } + $this->_validateCustomer($response); $resultJson = $this->resultJsonFactory->create(); if ($response->getError()) { $response->setError(true); diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php new file mode 100644 index 0000000000000..34f4b8b4eca89 --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -0,0 +1,574 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Model\Address; + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Ui\Component\Form\Field; +use Magento\Eav\Api\Data\AttributeInterface; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\Attribute; +use Magento\Framework\App\ObjectManager; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Customer\Model\Address; +use Magento\Customer\Model\FileProcessor; +use Magento\Customer\Model\FileProcessorFactory; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * + * Dataprovider for customer address grid. + */ +class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider +{ + /** + * Maximum file size allowed for file_uploader UI component + */ + const MAX_FILE_SIZE = 2097152; + + /** + * @var \Magento\Customer\Model\ResourceModel\Address\Collection + */ + protected $collection; + + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + + /** + * @var array + */ + private $loadedData; + + /** + * @var Config + */ + private $eavConfig; + + /** + * EAV attribute properties to fetch from meta storage + * @var array + */ + private $metaProperties = [ + 'dataType' => 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * Allow to manage attributes, even they are hidden on storefront + * + * @var bool + */ + private $allowToShowHiddenAttributes; + + /* + * @var ContextInterface + */ + private $context; + + /** + * File types allowed for file_uploader UI component + * + * @var array + */ + private $fileUploaderTypes = [ + 'image', + 'file', + ]; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfig; + + /** + * @var FileProcessorFactory + */ + private $fileProcessorFactory; + + /** + * @var array + */ + private $bannedInputTypes = ['media_image']; + + /** + * @var array + */ + private $attributesToEliminate = [ + 'region', + 'vat_is_valid', + 'vat_request_date', + 'vat_request_id', + 'vat_request_success' + ]; + + /** + * DataProvider constructor. + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName + * @param CollectionFactory $addressCollectionFactory + * @param CustomerRepositoryInterface $customerRepository + * @param Config $eavConfig + * @param EavValidationRules $eavValidationRules + * @param ContextInterface $context + * @param FileProcessorFactory $fileProcessorFactory + * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param array $meta + * @param array $data + * @param bool $allowToShowHiddenAttributes + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function __construct( + $name, + $primaryFieldName, + $requestFieldName, + CollectionFactory $addressCollectionFactory, + CustomerRepositoryInterface $customerRepository, + Config $eavConfig, + EavValidationRules $eavValidationRules, + ContextInterface $context, + FileProcessorFactory $fileProcessorFactory, + \Magento\Customer\Model\Config\Share $shareConfig, + array $meta = [], + array $data = [], + $allowToShowHiddenAttributes = true + ) { + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->collection = $addressCollectionFactory->create(); + $this->collection->addAttributeToSelect('*'); + $this->customerRepository = $customerRepository; + $this->eavValidationRules = $eavValidationRules; + $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; + $this->context = $context; + $this->fileProcessorFactory = $fileProcessorFactory; + $this->shareConfig = $shareConfig; + $this->meta['general']['children'] = $this->getAttributesMeta( + $eavConfig->getEntityType('customer_address') + ); + } + + /** + * Get Addresses data and process customer default billing & shipping addresses + * + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getData() + { + if (null !== $this->loadedData) { + return $this->loadedData; + } + $items = $this->collection->getItems(); + /** @var Address $item */ + foreach ($items as $item) { + $addressId = $item->getEntityId(); + $item->load($addressId); + $this->loadedData[$addressId] = $item->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->overrideFileUploaderData($item, $this->loadedData[$addressId]); + } + + if (null === $this->loadedData) { + $this->loadedData[''] = $this->getDefaultData(); + } + + return $this->loadedData; + } + + /** + * Prepare address data + * + * @param int $addressId + * @param array $addresses + * @param string|null $defaultBilling + * @param string|null $defaultShipping + * @return void + */ + private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping) + { + if (null !== $defaultBilling && $addressId == $defaultBilling) { + $addresses[$addressId]['default_billing'] = '1'; + } + if (null !== $defaultShipping && $addressId == $defaultShipping) { + $addresses[$addressId]['default_shipping'] = '1'; + } + if (null !== $addresses[$addressId]['street'] && !is_array($addresses[$addressId]['street'])) { + $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); + } + } + + /** + * Get default customer data for adding new address + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @return array + */ + private function getDefaultData() + { + $parentId = $this->context->getRequestParam('parent_id'); + $customer = $this->customerRepository->getById($parentId); + $data = [ + 'parent_id' => $parentId, + 'firstname' => $customer->getFirstname(), + 'lastname' => $customer->getLastname() + ]; + + return $data; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Address $entity + * @param array $entityData + * @return void + */ + private function overrideFileUploaderData($entity, array &$entityData) + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Get attributes meta + * + * @param Type $entityType + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getAttributesMeta(Type $entityType): array + { + $meta = []; + $attributes = $entityType->getAttributeCollection(); + /* @var AbstractAttribute $attribute */ + foreach ($attributes as $attribute) { + $this->processFrontendInput($attribute, $meta); + + $code = $attribute->getAttributeCode(); + + if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) { + continue; + } + if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) { + continue; + } + + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach ($this->metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($code == AddressInterface::COUNTRY_ID) { + $meta[$code]['arguments']['data']['config']['options'] = $this->getCountryWithWebsiteSource() + ->getAllOptions(); + } else { + $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); + if (!empty($rules)) { + $meta[$code]['arguments']['data']['config']['validation'] = $rules; + } + + $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; + $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); + + $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + } + + $this->processWebsiteMeta($meta); + return $meta; + } + + /** + * Process attributes by frontend input type + * + * @param AttributeInterface $attribute + * @param array $meta + * @return void + */ + private function processFrontendInput(AttributeInterface $attribute, array &$meta) + { + $code = $attribute->getAttributeCode(); + if ($attribute->getFrontendInput() === 'boolean') { + $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; + $meta[$code]['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + } + + /** + * Retrieve Country With Websites Source + * + * @return CountryWithWebsites + * @deprecated 100.2.0 + */ + private function getCountryWithWebsiteSource(): CountryWithWebsites + { + if (!$this->countryWithWebsiteSource) { + $this->countryWithWebsiteSource = ObjectManager::getInstance()->get(CountryWithWebsites::class); + } + + return $this->countryWithWebsiteSource; + } + + /** + * Detect can we show attribute on specific form or not + * + * @param Attribute $customerAttribute + * @return bool + */ + private function canShowAttribute(AbstractAttribute $customerAttribute): bool + { + $userDefined = (bool) $customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); + + return ($this->allowToShowHiddenAttributes && $canShowOnForm) || + (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param Attribute $customerAttribute + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool + { + $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return is_array($customerAttribute->getUsedInForms()) && + ( + (in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || + (in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) + ); + } + return is_array($customerAttribute->getUsedInForms()) && + in_array('customer_address_edit', $customerAttribute->getUsedInForms()); + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + private function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ) { + if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + private function processWebsiteMeta(&$meta) + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->fileProcessorFactory->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } +} diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php new file mode 100644 index 0000000000000..d52c94fb034c6 --- /dev/null +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -0,0 +1,585 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model\Customer; + +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Api\Data\AddressInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Address; +use Magento\Customer\Model\Attribute; +use Magento\Customer\Model\Customer; +use Magento\Customer\Model\FileProcessor; +use Magento\Customer\Model\FileProcessorFactory; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory; +use Magento\Eav\Api\Data\AttributeInterface; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Ui\Component\Form\Field; +use Magento\Ui\DataProvider\EavValidationRules; + +/** + * Refactored version of Magento\Customer\Model\Customer\DataProvider with eliminated usage of addresses collection. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\AbstractDataProvider +{ + /** + * Maximum file size allowed for file_uploader UI component + */ + const MAX_FILE_SIZE = 2097152; + + /** + * @var array + */ + private $loadedData; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfig; + + /** + * EAV attribute properties to fetch from meta storage + * @var array + */ + private $metaProperties = [ + 'dataType' => 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var SessionManagerInterface + * @since 100.1.0 + */ + private $session; + + /** + * @var FileProcessorFactory + */ + private $fileProcessorFactory; + + /** + * File types allowed for file_uploader UI component + * + * @var array + */ + private $fileUploaderTypes = [ + 'image', + 'file', + ]; + + /** + * Customer fields that must be removed + * + * @var array + */ + private $forbiddenCustomerFields = [ + 'password_hash', + 'rp_token', + 'confirmation', + ]; + + /* + * @var ContextInterface + */ + private $context; + + /** + * Allow to manage attributes, even they are hidden on storefront + * + * @var bool + */ + private $allowToShowHiddenAttributes; + + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryFactory; + + /** + * DataProviderWithDefaultAddresses constructor. + * + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName + * @param EavValidationRules $eavValidationRules + * @param CustomerCollectionFactory $customerCollectionFactory + * @param Config $eavConfig + * @param FileProcessorFactory $fileProcessorFactory + * @param ContextInterface $context + * @param \Magento\Directory\Model\CountryFactory $countryFactory + * @param SessionManagerInterface $session + * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param CountryWithWebsites $countryWithWebsites + * @param bool $allowToShowHiddenAttributes + * @param array $meta + * @param array $data + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function __construct( + string $name, + string $primaryFieldName, + string $requestFieldName, + EavValidationRules $eavValidationRules, + CustomerCollectionFactory $customerCollectionFactory, + Config $eavConfig, + FileProcessorFactory $fileProcessorFactory, + ContextInterface $context, + \Magento\Directory\Model\CountryFactory $countryFactory, + \Magento\Framework\Session\SessionManagerInterface $session, + \Magento\Customer\Model\Config\Share $shareConfig, + CountryWithWebsites $countryWithWebsites, + $allowToShowHiddenAttributes = true, + array $meta = [], + array $data = [] + ) { + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->eavValidationRules = $eavValidationRules; + $this->collection = $customerCollectionFactory->create(); + $this->collection->addAttributeToSelect('*'); + $this->fileProcessorFactory = $fileProcessorFactory; + $this->context = $context ?: ObjectManager::getInstance()->get(ContextInterface::class); + $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; + $this->session = $session; + $this->countryWithWebsiteSource = $countryWithWebsites; + $this->shareConfig = $shareConfig; + $this->countryFactory = $countryFactory; + $this->meta['customer']['children'] = $this->getAttributesMeta( + $eavConfig->getEntityType('customer') + ); +// $this->meta['address']['children'] = $this->getAttributesMeta( +// $eavConfig->getEntityType('customer_address') +// ); + } + + /** + * Get data + * + * @return array + */ + public function getData() + { + if (null !== $this->loadedData) { + return $this->loadedData; + } + $items = $this->collection->getItems(); + /** @var Customer $customer */ + foreach ($items as $customer) { + $result['customer'] = $customer->getData(); + + $this->overrideFileUploaderData($customer, $result['customer']); + + $result['customer'] = array_diff_key( + $result['customer'], + array_flip($this->forbiddenCustomerFields) + ); + unset($result['address']); + + $result['default_billing_address'] = $this->prepareDefaultAddress( + $customer->getDefaultBillingAddress() + ); + $result['default_shipping_address'] = $this->prepareDefaultAddress( + $customer->getDefaultShippingAddress() + ); + $result['customer_id'] = $customer->getId(); + + $this->loadedData[$customer->getId()] = $result; + } + + $data = $this->session->getCustomerFormData(); + if (!empty($data)) { + $customerId = $data['customer']['entity_id'] ?? null; + $this->loadedData[$customerId] = $data; + $this->session->unsCustomerFormData(); + } + + return $this->loadedData; + } + + /** + * Prepare default address data. + * + * @param Address|false $address + * @return array + */ + private function prepareDefaultAddress($address): array + { + $addressData = []; + + if (!empty($address)) { + $addressData = $address->getData(); + if (isset($addressData['street']) && !\is_array($address['street'])) { + $addressData['street'] = explode("\n", $addressData['street']); + } + $addressData['country'] = $this->countryFactory->create() + ->loadByCode($addressData['country_id'])->getName(); + } + + return $addressData; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Customer|Address $entity + * @param array $entityData + * @return void + */ + private function overrideFileUploaderData($entity, array &$entityData) + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->getFileProcessorFactory()->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } + + /** + * Get attributes meta + * + * @param Type $entityType + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + protected function getAttributesMeta(Type $entityType): array + { + $meta = []; + $attributes = $entityType->getAttributeCollection(); + /* @var AbstractAttribute $attribute */ + foreach ($attributes as $attribute) { + $this->processFrontendInput($attribute, $meta); + + $code = $attribute->getAttributeCode(); + + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach ($this->metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($code == AddressInterface::COUNTRY_ID) { + $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource + ->getAllOptions(); + } else { + $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); + if (!empty($rules)) { + $meta[$code]['arguments']['data']['config']['validation'] = $rules; + } + + $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; + $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); + + $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + } + + $this->processWebsiteMeta($meta); + return $meta; + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param AbstractAttribute $customerAttribute + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute) + { + $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return \is_array($customerAttribute->getUsedInForms()) && + ( + (\in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) + ); + } + return \is_array($customerAttribute->getUsedInForms()) && + \in_array('customer_address_edit', $customerAttribute->getUsedInForms()); + } + + /** + * Detect can we show attribute on specific form or not + * + * @param AbstractAttribute $customerAttribute + * @return bool + */ + private function canShowAttribute(AbstractAttribute $customerAttribute) + { + $userDefined = (bool) $customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); + + return ($this->allowToShowHiddenAttributes && $canShowOnForm) || + (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + private function processWebsiteMeta(&$meta) + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + private function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ) { + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } + + /** + * Process attributes by frontend input type + * + * @param AttributeInterface $attribute + * @param array $meta + * @return void + */ + private function processFrontendInput(AttributeInterface $attribute, array &$meta) + { + $code = $attribute->getAttributeCode(); + if ($attribute->getFrontendInput() === 'boolean') { + $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; + $meta[$code]['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + } + + /** + * Prepare address data + * + * @param int $addressId + * @param array $addresses + * @param array $customer + * @return void + */ + protected function prepareAddressData($addressId, array &$addresses, array $customer) + { + if (isset($customer['default_billing']) + && $addressId == $customer['default_billing'] + ) { + $addresses[$addressId]['default_billing'] = $customer['default_billing']; + } + if (isset($customer['default_shipping']) + && $addressId == $customer['default_shipping'] + ) { + $addresses[$addressId]['default_shipping'] = $customer['default_shipping']; + } + if (isset($addresses[$addressId]['street']) && !\is_array($addresses[$addressId]['street'])) { + $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); + } + } + + /** + * Get FileProcessorFactory instance + * + * @return FileProcessorFactory + * @deprecated 100.1.3 + */ + private function getFileProcessorFactory(): FileProcessorFactory + { + if ($this->fileProcessorFactory === null) { + $this->fileProcessorFactory = ObjectManager::getInstance() + ->get(\Magento\Customer\Model\FileProcessorFactory::class); + } + return $this->fileProcessorFactory; + } +} diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index e6e9c2b50c068..aca5b277186ca 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -109,7 +109,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) $extend = $this->_getRequestValue($request); $attrCode = $this->getAttribute()->getAttributeCode(); - if ($this->_requestScope) { + if ($this->_requestScope || !isset($_FILES[$attrCode])) { $value = []; if (strpos($this->_requestScope, '/') !== false) { $scopes = explode('/', $this->_requestScope); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php new file mode 100644 index 0000000000000..83129fee9b59b --- /dev/null +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Model\ResourceModel\Address\Grid; + +use Magento\Framework\Api\Search\SearchResultInterface; +use Magento\Framework\Api\Search\AggregationInterface; +use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; +use Magento\Framework\View\Element\UiComponent\Context; + +/** + * Class getting collection of addresses assigned to customer + */ +class Collection extends AbstractCollection implements SearchResultInterface +{ + /** + * @var string + */ + protected $_idFieldName = 'entity_id'; + + /** + * @var Context + */ + private $context; + + /** + * @var AggregationInterface + */ + protected $aggregations; + + /** + * @param Context $context + * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory + * @param \Psr\Log\LoggerInterface $logger + * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy + * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param string $mainTable + * @param string $eventPrefix + * @param string $eventObject + * @param string $resourceModel + * @param string $model + * @param \Magento\Framework\DB\Adapter\AdapterInterface|string|null $connection + * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + Context $context, + \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory, + \Psr\Log\LoggerInterface $logger, + \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy, + \Magento\Framework\Event\ManagerInterface $eventManager, + $mainTable, + $eventPrefix, + $eventObject, + $resourceModel, + $model = \Magento\Framework\View\Element\UiComponent\DataProvider\Document::class, + $connection = null, + \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource = null + ) { + $this->context = $context; + $this->_eventPrefix = $eventPrefix; + $this->_eventObject = $eventObject; + $this->_init($model, $resourceModel); + $this->setMainTable($mainTable); + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $connection, + $resource + ); + } + + /** + * Resource initialization + * + * @return $this + */ + protected function _initSelect() + { + parent::_initSelect(); + $parentId = $this->context->getRequestParam('parent_id'); + if ($parentId !== null) { + $this->getSelect()->where('parent_id=?', $parentId); + } + + return $this; + } + + /** + * {@inheritdoc} + * + * @return AggregationInterface + */ + public function getAggregations() + { + return $this->aggregations; + } + + /** + * {@inheritdoc} + * + * @param AggregationInterface $aggregations + * @return $this + */ + public function setAggregations($aggregations) + { + $this->aggregations = $aggregations; + return $this; + } + + /** + * Get search criteria. + * + * @return \Magento\Framework\Api\SearchCriteriaInterface|null + */ + public function getSearchCriteria() + { + return null; + } + + /** + * Set search criteria. + * + * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setSearchCriteria(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null) + { + return $this; + } + + /** + * Get total count. + * + * @return int + */ + public function getTotalCount() + { + return $this->getSize(); + } + + /** + * Set total count. + * + * @param int $totalCount + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setTotalCount($totalCount) + { + return $this; + } + + /** + * Set items list. + * + * @param \Magento\Framework\Api\ExtensibleDataInterface[] $items + * @return $this + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function setItems(array $items = null) + { + return $this; + } +} diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index d473a4dc01891..cbfebe87812bc 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -38,16 +38,26 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * @var $object \Magento\Customer\Model\Address */ - if (!$object->getIsCustomerSaveTransaction() && $this->isAddressDefault($object)) { + if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); $changedAddresses = []; if ($object->getIsDefaultBilling()) { $changedAddresses['default_billing'] = $object->getId(); + } elseif ($customer->getDefaultBillingAddress() + && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() + && !$object->getIsDefaultBilling() + ) { + $changedAddresses['default_billing'] = null; } if ($object->getIsDefaultShipping()) { $changedAddresses['default_shipping'] = $object->getId(); + } elseif ($customer->getDefaultShippingAddress() + && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() + && !$object->getIsDefaultShipping() + ) { + $changedAddresses['default_shipping'] = null; } if ($changedAddresses) { @@ -63,6 +73,9 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * Checks if address has chosen as default and has had an id * + * @deprecated Is not used anymore due to changes in logic of save of address. + * If address was default and becomes not default than default address id for customer must be + * set to null * @param \Magento\Framework\Model\AbstractModel $object * @return bool */ diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 43ae2db0c2163..5d88cd92c1730 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -170,22 +170,18 @@ public function save(CustomerInterface $customer, $passwordHash = null) /** @var NewOperation|null $delegatedNewOperation */ $delegatedNewOperation = !$customer->getId() ? $this->delegatedStorage->consumeNewOperation() : null; $prevCustomerData = null; - $prevCustomerDataArr = null; if ($customer->getId()) { $prevCustomerData = $this->getById($customer->getId()); - $prevCustomerDataArr = $prevCustomerData->__toArray(); } - /** @var $customer \Magento\Customer\Model\Data\Customer */ - $customerArr = $customer->__toArray(); + $customer = $this->imageProcessor->save( $customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $prevCustomerData ); - $origAddresses = $customer->getAddresses(); - $customer->setAddresses([]); + + /** @var array $customerData */ $customerData = $this->extensibleDataObjectConverter->toNestedArray($customer, [], CustomerInterface::class); - $customer->setAddresses($origAddresses); /** @var Customer $customerModel */ $customerModel = $this->customerFactory->create(['data' => $customerData]); //Model's actual ID field maybe different than "id" so "id" field from $customerData may be ignored. @@ -200,51 +196,10 @@ public function save(CustomerInterface $customer, $passwordHash = null) $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } - if (!array_key_exists('default_billing', $customerArr) - && null !== $prevCustomerDataArr - && array_key_exists('default_billing', $prevCustomerDataArr) - ) { - $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); - } - if (!array_key_exists('default_shipping', $customerArr) - && null !== $prevCustomerDataArr - && array_key_exists('default_shipping', $prevCustomerDataArr) - ) { - $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); - } $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); - if (!$customer->getAddresses() - && $delegatedNewOperation - && $delegatedNewOperation->getCustomer()->getAddresses() - ) { - $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); - } - if ($customer->getAddresses() !== null) { - if ($customer->getId()) { - $existingAddresses = $this->getById($customer->getId())->getAddresses(); - $getIdFunc = function ($address) { - return $address->getId(); - }; - $existingAddressIds = array_map($getIdFunc, $existingAddresses); - } else { - $existingAddressIds = []; - } - $savedAddressIds = []; - foreach ($customer->getAddresses() as $address) { - $address->setCustomerId($customerId) - ->setRegion($address->getRegion()); - $this->addressRepository->save($address); - if ($address->getId()) { - $savedAddressIds[] = $address->getId(); - } - } - $addressIdsToDelete = array_diff($existingAddressIds, $savedAddressIds); - foreach ($addressIdsToDelete as $addressId) { - $this->addressRepository->deleteById($addressId); - } - } + $this->customerRegistry->remove($customerId); $savedCustomer = $this->get($customer->getEmail(), $customer->getWebsiteId()); $this->eventManager->dispatch( @@ -374,7 +329,6 @@ public function deleteById($customerId) * @param \Magento\Framework\Api\Search\FilterGroup $filterGroup * @param \Magento\Customer\Model\ResourceModel\Customer\Collection $collection * @return void - * @throws \Magento\Framework\Exception\InputException */ protected function addFilterGroupToCollection( \Magento\Framework\Api\Search\FilterGroup $filterGroup, diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php new file mode 100644 index 0000000000000..47088eece23ed --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php @@ -0,0 +1,205 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Controller\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class SaveTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Controller\Adminhtml\Address\Save + */ + private $model; + + /** + * @var \Magento\Customer\Api\AddressRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressRepositoryMock; + + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $formFactoryMock; + + /** + * @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customerRepositoryMock; + + /** + * @var \Magento\Framework\Api\DataObjectHelper|\PHPUnit_Framework_MockObject_MockObject + */ + private $dataObjectHelperMock; + + /** + * @var \Magento\Customer\Api\Data\AddressInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressDataFactoryMock; + + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $loggerMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultRedirectFactoryMock; + + /** + * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageManagerMock; + + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->addressRepositoryMock = $this->createMock(\Magento\Customer\Api\AddressRepositoryInterface::class); + $this->formFactoryMock = $this->createMock(\Magento\Customer\Model\Metadata\FormFactory::class); + $this->customerRepositoryMock = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $this->dataObjectHelperMock = $this->createMock(\Magento\Framework\Api\DataObjectHelper ::class); + $this->addressDataFactoryMock = $this->createMock(\Magento\Customer\Api\Data\AddressInterfaceFactory::class); + $this->loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultRedirectFactoryMock = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); + $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\ManagerInterface::class); + + $objectManager = new ObjectManagerHelper($this); + + $this->model = $objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Address\Save::class, + [ + 'addressRepository' => $this->addressRepositoryMock, + 'formFactory' => $this->formFactoryMock, + 'customerRepository' => $this->customerRepositoryMock, + 'dataObjectHelper' => $this->dataObjectHelperMock, + 'addressDataFactory' => $this->addressDataFactoryMock, + 'loggerMock' => $this->loggerMock, + 'request' => $this->requestMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock, + 'messageManager' => $this->messageManagerMock, + ] + ); + } + + /** + * Test method \Magento\Customer\Controller\Adminhtml\Address\Save::execute + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecute() + { + $addressId = 11; + $customerId = 22; + + $addressExtractedData = [ + 'entity_id' => $addressId, + 'code' => 'value', + 'coolness' => false, + 'region' => 'region', + 'region_id' => 'region_id', + ]; + + $addressCompactedData = [ + 'entity_id' => $addressId, + 'default_billing' => 'true', + 'default_shipping' => 'true', + 'code' => 'value', + 'coolness' => false, + 'region' => 'region', + 'region_id' => 'region_id', + ]; + + $mergedAddressData = [ + 'entity_id' => $addressId, + 'default_billing' => true, + 'default_shipping' => true, + 'code' => 'value', + 'region' => [ + 'region' => 'region', + 'region_id' => 'region_id', + ], + 'region_id' => 'region_id', + 'id' => $addressId, + ]; + + $this->requestMock->method('getParam') + ->withConsecutive(['parent_id'], ['entity_id']) + ->willReturnOnConsecutiveCalls(22, 1); + + $customerMock = $this->getMockBuilder( + \Magento\Customer\Api\Data\CustomerInterface::class + )->disableOriginalConstructor()->getMock(); + + $this->customerRepositoryMock->expects($this->atLeastOnce()) + ->method('getById') + ->with($customerId) + ->willReturn($customerMock); + + $customerAddressFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class); + + $customerAddressFormMock->expects($this->atLeastOnce()) + ->method('extractData') + ->with($this->requestMock) + ->willReturn($addressExtractedData); + $customerAddressFormMock->expects($this->once()) + ->method('compactData') + ->with($addressExtractedData) + ->willReturn($addressCompactedData); + + $this->formFactoryMock->expects($this->exactly(1)) + ->method('create') + ->willReturn($customerAddressFormMock); + + $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->addressDataFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($addressMock); + + $this->dataObjectHelperMock->expects($this->atLeastOnce()) + ->method('populateWithArray') + ->willReturn( + [ + $addressMock, + $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, + $this->dataObjectHelperMock, + ] + ); + + $this->messageManagerMock->expects($this->once()) + ->method('addSuccessMessage') + ->with(__('Customer address has been updated.')) + ->willReturnSelf(); + + $resultRedirect = $this->createMock(\Magento\Framework\Controller\Result\Redirect::class); + $resultRedirect->expects($this->atLeastOnce()) + ->method('setPath') + ->with('customer/index/edit', ['id' => $customerId, '_current' => true]) + ->willReturnSelf(); + $this->resultRedirectFactoryMock->method('create') + ->willReturn($resultRedirect); + + $this->assertEquals($resultRedirect, $this->model->execute()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php new file mode 100644 index 0000000000000..a724bdd24959b --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/ValidateTest.php @@ -0,0 +1,118 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Controller\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ValidateTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Controller\Adminhtml\Address\Validate + */ + private $model; + + /** + * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $formFactoryMock; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $requestMock; + + /** + * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultRedirectFactoryMock; + + /** + * @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultJsonFactoryMock; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->formFactoryMock = $this->createMock(\Magento\Customer\Model\Metadata\FormFactory::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultJsonFactoryMock = $this->createMock(\Magento\Framework\Controller\Result\JsonFactory::class); + $this->resultRedirectFactoryMock = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); + + $objectManager = new ObjectManagerHelper($this); + + $this->model = $objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Address\Validate::class, + [ + 'formFactory' => $this->formFactoryMock, + 'request' => $this->requestMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + ] + ); + } + + /** + * Test method \Magento\Customer\Controller\Adminhtml\Address\Save::execute + * + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testExecute() + { + $addressId = 11; + $errors = ['Error Message 1', 'Error Message 2']; + + $addressExtractedData = [ + 'entity_id' => $addressId, + 'default_billing' => true, + 'default_shipping' => true, + 'code' => 'value', + 'region' => [ + 'region' => 'region', + 'region_id' => 'region_id', + ], + 'region_id' => 'region_id', + 'id' => $addressId, + ]; + + $customerAddressFormMock = $this->createMock(\Magento\Customer\Model\Metadata\Form::class); + + $customerAddressFormMock->expects($this->atLeastOnce()) + ->method('extractData') + ->with($this->requestMock) + ->willReturn($addressExtractedData); + $customerAddressFormMock->expects($this->once()) + ->method('validateData') + ->with($addressExtractedData) + ->willReturn($errors); + + $this->formFactoryMock->expects($this->exactly(1)) + ->method('create') + ->willReturn($customerAddressFormMock); + + $resultJson = $this->createMock(\Magento\Framework\Controller\Result\Json::class); + $this->resultJsonFactoryMock->method('create') + ->willReturn($resultJson); + + $validateResponseMock = $this->createPartialMock( + \Magento\Framework\DataObject::class, + ['getError', 'setMessages'] + ); + $validateResponseMock->method('setMessages')->willReturnSelf(); + $validateResponseMock->method('getError')->willReturn(1); + + $resultJson->method('setData')->willReturnSelf(); + + $this->assertEquals($resultJson, $this->model->execute()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php index 5372bb11a89b5..c52d5b2fb370f 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/SaveTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Customer\Test\Unit\Controller\Adminhtml\Index; -use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Api\CustomerMetadataInterface; use Magento\Customer\Api\Data\AttributeMetadataInterface; use Magento\Customer\Api\Data\CustomerInterface; @@ -281,7 +280,6 @@ protected function setUp() public function testExecuteWithExistentCustomer() { $customerId = 22; - $addressId = 11; $subscription = 'true'; $postValue = [ 'customer' => [ @@ -290,18 +288,6 @@ public function testExecuteWithExistentCustomer() 'coolness' => false, 'disable_auto_group_change' => 'false', ], - 'address' => [ - '_template_' => '_template_', - $addressId => [ - 'entity_id' => $addressId, - 'default_billing' => 'true', - 'default_shipping' => 'true', - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ], - ], 'subscription' => $subscription, ]; $extractedData = [ @@ -318,22 +304,6 @@ public function testExecuteWithExistentCustomer() CustomerInterface::DEFAULT_BILLING => 2, CustomerInterface::DEFAULT_SHIPPING => 2 ]; - $addressExtractedData = [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; - $addressCompactedData = [ - 'entity_id' => $addressId, - 'default_billing' => 'true', - 'default_shipping' => 'true', - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; $savedData = [ 'entity_id' => $customerId, 'darkness' => true, @@ -341,61 +311,40 @@ public function testExecuteWithExistentCustomer() CustomerInterface::DEFAULT_BILLING => false, CustomerInterface::DEFAULT_SHIPPING => false, ]; - $savedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => true, - 'default_shipping' => true, - ]; $mergedData = [ 'entity_id' => $customerId, 'darkness' => true, 'name' => 'Name', 'code' => 'value', 'disable_auto_group_change' => 0, - CustomerInterface::DEFAULT_BILLING => $addressId, - CustomerInterface::DEFAULT_SHIPPING => $addressId, 'confirmation' => false, 'sendemail_store_id' => '1', 'id' => $customerId, ]; - $mergedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => true, - 'default_shipping' => true, - 'code' => 'value', - 'region' => [ - 'region' => 'region', - 'region_id' => 'region_id', - ], - 'region_id' => 'region_id', - 'id' => $addressId, - ]; /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( \Magento\Customer\Api\Data\AttributeMetadataInterface::class )->disableOriginalConstructor()->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; - $this->requestMock->expects($this->any()) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPostValue') ->willReturnMap([ [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ]); - $this->requestMock->expects($this->exactly(3)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, $postValue['address']], ['subscription', null, $subscription], ] ); @@ -404,16 +353,15 @@ public function testExecuteWithExistentCustomer() $objectMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->atLeastOnce()) ->method('getData') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ] ); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->exactly(1)) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -432,23 +380,7 @@ public function testExecuteWithExistentCustomer() $customerFormMock->expects($this->once()) ->method('getAttributes') ->willReturn($attributes); - - $customerAddressFormMock = $this->getMockBuilder( - \Magento\Customer\Model\Metadata\Form::class - )->disableOriginalConstructor()->getMock(); - $customerAddressFormMock->expects($this->once()) - ->method('extractData') - ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('compactData') - ->with($addressExtractedData) - ->willReturn($addressCompactedData); - $customerAddressFormMock->expects($this->once()) - ->method('getAttributes') - ->willReturn($attributes); - - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->exactly(1)) ->method('create') ->willReturnMap( [ @@ -461,15 +393,6 @@ public function testExecuteWithExistentCustomer() [], $customerFormMock ], - [ - AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'adminhtml_customer_address', - $savedAddressData, - false, - Form::DONT_IGNORE_INVISIBLE, - [], - $customerAddressFormMock - ], ] ); @@ -492,25 +415,7 @@ public function testExecuteWithExistentCustomer() ->with($customerMock) ->willReturn($savedData); - $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customerAddressRepositoryMock->expects($this->once()) - ->method('getById') - ->with($addressId) - ->willReturn($addressMock); - - $this->customerAddressMapperMock->expects($this->once()) - ->method('toFlatArray') - ->with($addressMock) - ->willReturn($savedAddressData); - - $this->addressDataFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($addressMock); - - $this->dataHelperMock->expects($this->exactly(2)) + $this->dataHelperMock->expects($this->atLeastOnce()) ->method('populateWithArray') ->willReturnMap( [ @@ -519,19 +424,9 @@ public function testExecuteWithExistentCustomer() $mergedData, \Magento\Customer\Api\Data\CustomerInterface::class, $this->dataHelperMock ], - [ - $addressMock, - $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, - $this->dataHelperMock - ], ] ); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with([$addressMock]) - ->willReturnSelf(); - $this->customerRepositoryMock->expects($this->once()) ->method('save') ->with($customerMock) @@ -608,63 +503,33 @@ public function testExecuteWithExistentCustomer() public function testExecuteWithNewCustomer() { $customerId = 22; - $addressId = 11; + $subscription = '0'; $postValue = [ 'customer' => [ 'coolness' => false, 'disable_auto_group_change' => 'false', ], - 'address' => [ - '_template_' => '_template_', - $addressId => [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ], - ], 'subscription' => $subscription, ]; $extractedData = [ 'coolness' => false, 'disable_auto_group_change' => 'false', ]; - $addressExtractedData = [ - 'entity_id' => $addressId, - 'code' => 'value', - 'coolness' => false, - 'region' => 'region', - 'region_id' => 'region_id', - ]; $mergedData = [ 'disable_auto_group_change' => 0, CustomerInterface::DEFAULT_BILLING => null, CustomerInterface::DEFAULT_SHIPPING => null, 'confirmation' => false, ]; - $mergedAddressData = [ - 'entity_id' => $addressId, - 'default_billing' => false, - 'default_shipping' => false, - 'code' => 'value', - 'region' => [ - 'region' => 'region', - 'region_id' => 'region_id', - ], - 'region_id' => 'region_id', - 'id' => $addressId, - ]; - /** @var AttributeMetadataInterface|\PHPUnit_Framework_MockObject_MockObject $customerFormMock */ $attributeMock = $this->getMockBuilder( \Magento\Customer\Api\Data\AttributeMetadataInterface::class )->disableOriginalConstructor()->getMock(); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getAttributeCode') ->willReturn('coolness'); - $attributeMock->expects($this->exactly(2)) + $attributeMock->expects($this->atLeastOnce()) ->method('getFrontendInput') ->willReturn('int'); $attributes = [$attributeMock]; @@ -674,14 +539,12 @@ public function testExecuteWithNewCustomer() ->willReturnMap([ [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ]); - $this->requestMock->expects($this->exactly(3)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, $postValue['address']], ['subscription', null, $subscription], ] ); @@ -690,16 +553,15 @@ public function testExecuteWithNewCustomer() $objectMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->disableOriginalConstructor() ->getMock(); - $objectMock->expects($this->exactly(2)) + $objectMock->expects($this->atLeastOnce()) ->method('getData') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address/' . $addressId, null, $postValue['address'][$addressId]], ] ); - $this->objectFactoryMock->expects($this->exactly(2)) + $this->objectFactoryMock->expects($this->atLeastOnce()) ->method('create') ->with(['data' => $postValue]) ->willReturn($objectMock); @@ -719,22 +581,7 @@ public function testExecuteWithNewCustomer() ->method('getAttributes') ->willReturn($attributes); - $customerAddressFormMock = $this->getMockBuilder( - \Magento\Customer\Model\Metadata\Form::class - )->disableOriginalConstructor()->getMock(); - $customerAddressFormMock->expects($this->once()) - ->method('extractData') - ->with($this->requestMock, 'address/' . $addressId) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('compactData') - ->with($addressExtractedData) - ->willReturn($addressExtractedData); - $customerAddressFormMock->expects($this->once()) - ->method('getAttributes') - ->willReturn($attributes); - - $this->formFactoryMock->expects($this->exactly(2)) + $this->formFactoryMock->expects($this->exactly(1)) ->method('create') ->willReturnMap( [ @@ -747,15 +594,6 @@ public function testExecuteWithNewCustomer() [], $customerFormMock ], - [ - AddressMetadataInterface::ENTITY_TYPE_ADDRESS, - 'adminhtml_customer_address', - [], - false, - Form::DONT_IGNORE_INVISIBLE, - [], - $customerAddressFormMock - ], ] ); @@ -768,25 +606,7 @@ public function testExecuteWithNewCustomer() ->method('create') ->willReturn($customerMock); - $addressMock = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->addressDataFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($addressMock); - - $this->customerAddressRepositoryMock->expects($this->once()) - ->method('getById') - ->with($addressId) - ->willReturn($addressMock); - - $this->customerAddressMapperMock->expects($this->once()) - ->method('toFlatArray') - ->with($addressMock) - ->willReturn([]); - - $this->dataHelperMock->expects($this->exactly(2)) + $this->dataHelperMock->expects($this->atLeastOnce()) ->method('populateWithArray') ->willReturnMap( [ @@ -795,11 +615,6 @@ public function testExecuteWithNewCustomer() $mergedData, \Magento\Customer\Api\Data\CustomerInterface::class, $this->dataHelperMock ], - [ - $addressMock, - $mergedAddressData, \Magento\Customer\Api\Data\AddressInterface::class, - $this->dataHelperMock - ], ] ); @@ -904,12 +719,11 @@ public function testExecuteWithNewCustomerAndValidationException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); @@ -1047,12 +861,11 @@ public function testExecuteWithNewCustomerAndLocalizedException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); @@ -1190,12 +1003,11 @@ public function testExecuteWithNewCustomerAndException() [null, null, $postValue], [CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, null, $postValue['customer']], ]); - $this->requestMock->expects($this->exactly(2)) + $this->requestMock->expects($this->atLeastOnce()) ->method('getPost') ->willReturnMap( [ ['customer', null, $postValue['customer']], - ['address', null, null], ] ); diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php index 7209ac9fd24b0..5adb902601630 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ValidateTest.php @@ -141,12 +141,6 @@ protected function setUp() public function testExecute() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn([ - '_template_' => null, - 'address_index' => null - ]); $customerEntityId = 2; $this->request->expects($this->once()) ->method('getParam') @@ -162,11 +156,6 @@ public function testExecute() $this->form->expects($this->once())->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce())->method('extractData')->willReturn([]); - $error = $this->createMock(\Magento\Framework\Message\Error::class); - $this->form->expects($this->once()) - ->method('validateData') - ->willReturn([$error]); - $validationResult = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\ValidationResultsInterface::class, [], @@ -188,9 +177,6 @@ public function testExecute() public function testExecuteWithoutAddresses() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn(null); $this->form->expects($this->once()) ->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce()) @@ -223,9 +209,6 @@ public function testExecuteWithoutAddresses() public function testExecuteWithException() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn(null); $this->form->expects($this->once()) ->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce()) @@ -265,12 +248,6 @@ public function testExecuteWithException() public function testExecuteWithNewCustomerAndNoEntityId() { - $this->request->expects($this->once()) - ->method('getPost') - ->willReturn([ - '_template_' => null, - 'address_index' => null - ]); $this->request->expects($this->once()) ->method('getParam') ->with('customer') @@ -282,11 +259,6 @@ public function testExecuteWithNewCustomerAndNoEntityId() $this->form->expects($this->once())->method('setInvisibleIgnored'); $this->form->expects($this->atLeastOnce())->method('extractData')->willReturn([]); - $error = $this->createMock(\Magento\Framework\Message\Error::class); - $this->form->expects($this->once()) - ->method('validateData') - ->willReturn([$error]); - $validationResult = $this->getMockForAbstractClass( \Magento\Customer\Api\Data\ValidationResultsInterface::class, [], diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php new file mode 100644 index 0000000000000..815a47288e370 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -0,0 +1,233 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Customer\Test\Unit\Model\Address; + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Customer\Model\ResourceModel\Address\Collection as AddressCollection; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Customer\Model\Attribute as AttributeModel; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Customer\Model\Address as AddressModel; +use Magento\Customer\Model\FileProcessorFactory; + +class DataProviderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressCollectionFactory; + + /** + * @var AddressCollection|\PHPUnit_Framework_MockObject_MockObject + */ + private $collection; + + /** + * @var CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customerRepository; + + /** + * @var CustomerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $customer; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavConfig; + + /** + * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject + */ + private $eavValidationRules; + + /* + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $context; + + /** + * @var \Magento\Customer\Model\Config\Share|\PHPUnit_Framework_MockObject_MockObject + */ + private $shareConfig; + + /** + * @var FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileProcessorFactory; + + /** + * @var Type|\PHPUnit_Framework_MockObject_MockObject + */ + private $entityType; + + /** + * @var AddressModel|\PHPUnit_Framework_MockObject_MockObject + */ + private $address; + + /** + * @var AttributeModel|\PHPUnit_Framework_MockObject_MockObject + */ + private $attribute; + + /** + * @var \Magento\Customer\Model\Address\DataProvider + */ + private $model; + + protected function setUp() + { + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->addressCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->collection = $this->getMockBuilder(AddressCollection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerRepository = $this->getMockForAbstractClass(CustomerRepositoryInterface::class); + $this->eavValidationRules = $this->createMock(EavValidationRules::class); + $this->context = $this->getMockForAbstractClass(ContextInterface::class); + $this->fileProcessorFactory = $this->getMockBuilder(FileProcessorFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->shareConfig = $this->createMock(\Magento\Customer\Model\Config\Share::class); + $this->addressCollectionFactory->expects($this->once()) + ->method('create') + ->willReturn($this->collection); + $this->eavConfig = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->entityType = $this->getMockBuilder(Type::class) + ->disableOriginalConstructor() + ->getMock(); + $this->entityType->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn([]); + $this->eavConfig->expects($this->once()) + ->method('getEntityType') + ->willReturn($this->entityType); + $this->customer = $this->getMockForAbstractClass(CustomerInterface::class); + $this->address = $this->getMockBuilder(AddressModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attribute = $this->getMockBuilder(AttributeModel::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = $objectManagerHelper->getObject( + \Magento\Customer\Model\Address\DataProvider::class, + [ + '', + '', + '', + 'addressCollectionFactory' => $this->addressCollectionFactory, + 'customerRepository' => $this->customerRepository, + 'eavConfig' => $this->eavConfig, + 'eavValidationRules' => $this->eavValidationRules, + 'context' => $this->context, + 'fileProcessorFactory' => $this->fileProcessorFactory, + 'shareConfig' => $this->shareConfig, + [], + [], + true + ] + ); + } + + public function testGetDefaultData() + { + $expectedData = [ + '' => [ + 'parent_id' => 1, + 'firstname' => 'John', + 'lastname' => 'Doe' + ] + ]; + + $this->collection->expects($this->once()) + ->method('getItems') + ->willReturn([]); + + $this->context->expects($this->once()) + ->method('getRequestParam') + ->willReturn(1); + $this->customerRepository->expects($this->once()) + ->method('getById') + ->willReturn($this->customer); + $this->customer->expects($this->once()) + ->method('getFirstname') + ->willReturn('John'); + $this->customer->expects($this->once()) + ->method('getLastname') + ->willReturn('Doe'); + + $this->assertEquals($expectedData, $this->model->getData()); + } + + public function testGetData() + { + $expectedData = [ + '3' => [ + 'parent_id' => "1", + 'firstname' => 'John', + 'lastname' => 'Doe', + 'street' => [ + '42000 Ave W 55 Cedar City', + 'Apt. 33' + ] + ] + ]; + + $this->collection->expects($this->once()) + ->method('getItems') + ->willReturn([ + $this->address + ]); + + $this->customerRepository->expects($this->once()) + ->method('getById') + ->willReturn($this->customer); + $this->customer->expects($this->once()) + ->method('getDefaultBilling') + ->willReturn('1'); + $this->customer->expects($this->once()) + ->method('getDefaultShipping') + ->willReturn('1'); + + $this->address->expects($this->once()) + ->method('getEntityId') + ->willReturn('3'); + $this->address->expects($this->once()) + ->method('load') + ->with("3") + ->willReturnSelf(); + $this->address->expects($this->once()) + ->method('getData') + ->willReturn([ + 'parent_id' => "1", + 'firstname' => "John", + 'lastname' => 'Doe', + 'street' => "42000 Ave W 55 Cedar City\nApt. 33" + ]); + $this->address->expects($this->once()) + ->method('getAttributes') + ->willReturn([$this->attribute]); + $this->attribute->expects($this->once()) + ->method('getFrontendInput') + ->willReturn(null); + + $this->assertEquals($expectedData, $this->model->getData()); + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php new file mode 100644 index 0000000000000..eb1241de3e32c --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderWithDefaultAddressesTest.php @@ -0,0 +1,1065 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Model\Customer; + +use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Model\Config\Share; +use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; +use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Ui\Component\Form\Field; +use Magento\Ui\DataProvider\EavValidationRules; + +/** + * Class DataProviderTest + * + * Test for class \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class DataProviderWithDefaultAddressesTest extends \PHPUnit\Framework\TestCase +{ + const ATTRIBUTE_CODE = 'test-code'; + const OPTIONS_RESULT = 'test-options'; + + /** + * @var Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavConfigMock; + + /** + * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $customerCollectionFactoryMock; + + /** + * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject + */ + protected $eavValidationRulesMock; + + /** + * @var \Magento\Framework\Session\SessionManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $sessionMock; + + /** + * @var \Magento\Customer\Model\FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fileProcessorFactory; + + /** + * @var \Magento\Customer\Model\FileProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + protected $fileProcessor; + + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryFactoryMock; + + /** + * @var \Magento\Customer\Model\Customer + */ + private $customerMock; + + /** + * @var \Magento\Customer\Model\ResourceModel\Customer\Collection + */ + private $customerCollectionMock; + + /** + * @var \Magento\Customer\Model\Config\Share + */ + private $shareConfigMock; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsitesMock; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->eavConfigMock = $this->getMockBuilder(\Magento\Eav\Model\Config::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionFactoryMock = $this->createPartialMock( + \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory::class, + ['create'] + ); + $this->eavValidationRulesMock = $this + ->getMockBuilder(\Magento\Ui\DataProvider\EavValidationRules::class) + ->disableOriginalConstructor() + ->getMock(); + $this->sessionMock = $this + ->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->setMethods(['getCustomerFormData', 'unsCustomerFormData']) + ->getMockForAbstractClass(); + + $this->fileProcessor = $this->getMockBuilder(\Magento\Customer\Model\FileProcessor::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->fileProcessorFactory = $this->getMockBuilder(\Magento\Customer\Model\FileProcessorFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->countryFactoryMock = $this->getMockBuilder(\Magento\Directory\Model\CountryFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create', 'loadByCode', 'getName']) + ->getMock(); + + $this->customerMock = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Customer\Collection::class + ) + ->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock->expects($this->any())->method('addAttributeToSelect')->with('*'); + $this->customerCollectionFactoryMock + ->expects($this->any()) + ->method('create') + ->willReturn($this->customerCollectionMock); + + $this->eavConfigMock->expects($this->at(0)) + ->method('getEntityType') + ->with('customer') + ->willReturn($this->getTypeCustomerMock([])); + $this->eavConfigMock->expects($this->at(1)) + ->method('getEntityType') + ->with('customer_address') + ->willReturn($this->getTypeAddressMock()); + + $this->shareConfigMock = $this->getMockBuilder(\Magento\Customer\Model\Config\Share::class) + ->disableOriginalConstructor() + ->getMock(); + $this->countryWithWebsitesMock = $this->getMockBuilder(CountryWithWebsites::class) + ->disableOriginalConstructor() + ->setMethods(['getAllOptions']) + ->getMock(); + $this->countryWithWebsitesMock->expects($this->any())->method('getAllOptions')->willReturn('test-options'); + + $helper = new ObjectManager($this); + $this->dataProvider = $helper->getObject( + \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses::class, + [ + 'name' => 'test-name', + 'primaryFieldName' => 'primary-field-name', + 'requestFieldName' => 'request-field-name', + 'eavValidationRules' => $this->eavValidationRulesMock, + 'customerCollectionFactory' => $this->customerCollectionFactoryMock, + 'eavConfig' => $this->eavConfigMock, + 'countryFactory' => $this->countryFactoryMock, + 'session' => $this->sessionMock, + 'fileProcessorFactory' => $this->fileProcessorFactory, + 'shareConfig' => $this->shareConfigMock, + 'countryWithWebsites' => $this->countryWithWebsitesMock, + ] + ); + } + + /** + * Run test getAttributesMeta method + * + * @param array $expected + * @return void + * + * @dataProvider getAttributesMetaDataProvider + */ + public function testGetAttributesMetaWithOptions(array $expected) + { + $meta = $this->dataProvider->getMeta(); + $this->assertNotEmpty($meta); + $this->assertEquals($expected, $meta); + } + + /** + * Data provider for testGetAttributesMeta + * + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getAttributesMetaDataProvider() + { + return [ + [ + 'expected' => [ + 'customer' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + ], + ], + 'address' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'country_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'filterBy' => [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ] + ], + ], + ], + ] + ], + ], + ] + ] + ]; + } + + /** + * @return CollectionFactory|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getCustomerCollectionFactoryMock() + { + $collectionMock = $this->getMockBuilder(\Magento\Customer\Model\ResourceModel\Customer\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + + $collectionMock->expects($this->any()) + ->method('addAttributeToSelect') + ->with('*'); + + $this->customerCollectionFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($collectionMock); + + return $this->customerCollectionFactoryMock; + } + + /** + * @return Config|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getEavConfigMock($customerAttributes = []) + { + $this->eavConfigMock->expects($this->at(0)) + ->method('getEntityType') + ->with('customer') + ->willReturn($this->getTypeCustomerMock($customerAttributes)); + $this->eavConfigMock->expects($this->at(1)) + ->method('getEntityType') + ->with('customer_address') + ->willReturn($this->getTypeAddressMock()); + + return $this->eavConfigMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeCustomerMock($customerAttributes = []) + { + $typeCustomerMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $attributesCollection = !empty($customerAttributes) ? $customerAttributes : $this->getAttributeMock(); + $typeCustomerMock->expects($this->any()) + ->method('getEntityTypeCode') + ->willReturn('customer'); + foreach ($attributesCollection as $attribute) { + $attribute->expects($this->any()) + ->method('getEntityType') + ->willReturn($typeCustomerMock); + } + + $typeCustomerMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($attributesCollection); + + return $typeCustomerMock; + } + + /** + * @return Type|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypeAddressMock() + { + $typeAddressMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + + $typeAddressMock->expects($this->once()) + ->method('getAttributeCollection') + ->willReturn($this->getAttributeMock('address')); + + return $typeAddressMock; + } + + /** + * @param \PHPUnit_Framework_MockObject_MockObject $attributeMock + * @param \PHPUnit_Framework_MockObject_MockObject $attributeBooleanMock + * @param array $options + */ + private function injectVisibilityProps( + \PHPUnit_Framework_MockObject_MockObject $attributeMock, + \PHPUnit_Framework_MockObject_MockObject $attributeBooleanMock, + array $options = [] + ) { + if (isset($options[self::ATTRIBUTE_CODE]['visible'])) { + $attributeMock->expects($this->any()) + ->method('getIsVisible') + ->willReturn($options[self::ATTRIBUTE_CODE]['visible']); + } + + if (isset($options[self::ATTRIBUTE_CODE]['user_defined'])) { + $attributeMock->expects($this->any()) + ->method('getIsUserDefined') + ->willReturn($options[self::ATTRIBUTE_CODE]['user_defined']); + } + + if (isset($options[self::ATTRIBUTE_CODE]['is_used_in_forms'])) { + $attributeMock->expects($this->any()) + ->method('getUsedInForms') + ->willReturn($options[self::ATTRIBUTE_CODE]['is_used_in_forms']); + } + + if (isset($options['test-code-boolean']['visible'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getIsVisible') + ->willReturn($options['test-code-boolean']['visible']); + } + + if (isset($options['test-code-boolean']['user_defined'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getIsUserDefined') + ->willReturn($options['test-code-boolean']['user_defined']); + } + + if (isset($options['test-code-boolean']['is_used_in_forms'])) { + $attributeBooleanMock->expects($this->any()) + ->method('getUsedInForms') + ->willReturn($options['test-code-boolean']['is_used_in_forms']); + } + } + + /** + * @return AbstractAttribute[]|\PHPUnit_Framework_MockObject_MockObject[] + */ + protected function getAttributeMock($type = 'customer', $options = []) + { + $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods( + [ + 'getAttributeCode', + 'getDataUsingMethod', + 'usesSource', + 'getFrontendInput', + 'getIsVisible', + 'getSource', + 'getIsUserDefined', + 'getUsedInForms', + 'getEntityType', + ] + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $sourceMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Source\AbstractSource::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $attributeCode = self::ATTRIBUTE_CODE; + if (isset($options[self::ATTRIBUTE_CODE]['specific_code_prefix'])) { + $attributeCode .= $options[self::ATTRIBUTE_CODE]['specific_code_prefix']; + } + + $attributeMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn($attributeCode); + + $sourceMock->expects($this->any()) + ->method('getAllOptions') + ->willReturn(self::OPTIONS_RESULT); + + $attributeMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback($this->attributeGetUsingMethodCallback()); + + $attributeMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $attributeMock->expects($this->any()) + ->method('getSource') + ->willReturn($sourceMock); + + $attributeBooleanMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods( + [ + 'getAttributeCode', + 'getDataUsingMethod', + 'usesSource', + 'getFrontendInput', + 'getIsVisible', + 'getIsUserDefined', + 'getUsedInForms', + 'getSource', + 'getEntityType', + ] + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $attributeBooleanMock->expects($this->any()) + ->method('getFrontendInput') + ->willReturn('boolean'); + $attributeBooleanMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback($this->attributeGetUsingMethodCallback()); + + $attributeBooleanMock->expects($this->once()) + ->method('usesSource') + ->willReturn(false); + $booleanAttributeCode = 'test-code-boolean'; + if (isset($options['test-code-boolean']['specific_code_prefix'])) { + $booleanAttributeCode .= $options['test-code-boolean']['specific_code_prefix']; + } + + $attributeBooleanMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn($booleanAttributeCode); + + $this->eavValidationRulesMock->expects($this->any()) + ->method('build') + ->willReturnMap([ + [$attributeMock, $this->logicalNot($this->isEmpty()), []], + [$attributeBooleanMock, $this->logicalNot($this->isEmpty()), []], + ]); + $mocks = [$attributeMock, $attributeBooleanMock]; + $this->injectVisibilityProps($attributeMock, $attributeBooleanMock, $options); + if ($type == "address") { + $mocks[] = $this->getCountryAttrMock(); + } + return $mocks; + } + + /** + * Callback for ::getDataUsingMethod + * + * @return \Closure + */ + private function attributeGetUsingMethodCallback() + { + return function ($origName) { + return $origName; + }; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function getCountryAttrMock() + { + $objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class); + $objectManagerMock->expects($this->any()) + ->method('get') + ->willReturnMap([ + [CountryWithWebsites::class, $this->countryWithWebsitesMock], + [Share::class, $this->shareConfigMock], + ]); + \Magento\Framework\App\ObjectManager::setInstance($objectManagerMock); + $countryAttrMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class) + ->setMethods(['getAttributeCode', 'getDataUsingMethod', 'usesSource', 'getSource', 'getLabel']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $countryAttrMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn('country_id'); + + $countryAttrMock->expects($this->any()) + ->method('getDataUsingMethod') + ->willReturnCallback( + function ($origName) { + return $origName; + } + ); + $countryAttrMock->expects($this->any()) + ->method('getLabel') + ->willReturn(__('frontend_label')); + $countryAttrMock->expects($this->any()) + ->method('usesSource') + ->willReturn(true); + $countryAttrMock->expects($this->any()) + ->method('getSource') + ->willReturn(null); + + return $countryAttrMock; + } + + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetData() + { + $customerData = [ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + 'password_hash' => 'password_hash', + 'rp_token' => 'rp_token', + 'confirmation' => 'confirmation', + ]; + + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class)->disableOriginalConstructor() + ->getMock(); + $this->customerCollectionMock->expects($this->once())->method('getItems')->willReturn([$this->customerMock]); + $this->customerMock->expects($this->once())->method('getData')->willReturn($customerData); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([]); + + $this->customerMock->expects($this->once())->method('getDefaultBillingAddress')->willReturn($address); + $this->countryFactoryMock->expects($this->once())->method('create')->willReturnSelf(); + $this->countryFactoryMock->expects($this->once())->method('loadByCode')->willReturnSelf(); + $this->countryFactoryMock->expects($this->once())->method('getName')->willReturn('Ukraine'); + + $this->sessionMock->expects($this->once()) + ->method('getCustomerFormData') + ->willReturn(null); + + $this->assertEquals( + [ + '' => [ + 'customer' => [ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + ], + 'default_billing_address' => [ + 'country' => 'Ukraine', + ], + 'default_shipping_address' => [] + ] + ], + $this->dataProvider->getData() + ); + } + + /** + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetDataWithCustomerFormData() + { + $customerId = 11; + $customerFormData = [ + 'customer' => [ + 'email' => 'test1@test1.ua', + 'default_billing' => 3, + 'default_shipping' => 3, + 'entity_id' => $customerId, + ], + 'address' => [ + 3 => [ + 'firstname' => 'firstname1', + 'lastname' => 'lastname1', + 'street' => [ + 'street1', + 'street2', + ], + 'default_billing' => 3, + 'default_shipping' => 3, + ], + ], + ]; + + $this->customerCollectionMock->expects($this->once())->method('getItems')->willReturn([$this->customerMock]); + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => 'test@test.ua', + 'default_billing' => 2, + 'default_shipping' => 2, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([]); + + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn($customerFormData); + $this->sessionMock->expects($this->once())->method('unsCustomerFormData'); + + $this->assertEquals([$customerId => $customerFormData], $this->dataProvider->getData()); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @return void + */ + public function testGetDataWithCustomAttributeImage() + { + $customerId = 1; + $customerEmail = 'user1@example.com'; + + $filename = '/filename.ext1'; + $viewUrl = 'viewUrl'; + $mime = 'image/png'; + + $expectedData = [ + $customerId => [ + 'customer' => [ + 'email' => $customerEmail, + 'img1' => [ + [ + 'file' => $filename, + 'size' => 1, + 'url' => $viewUrl, + 'name' => 'filename.ext1', + 'type' => $mime, + ], + ], + ], + 'default_billing_address' => [], + 'default_shipping_address' => [], + ], + ]; + + $attributeMock = $this->getMockBuilder(\Magento\Customer\Model\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->exactly(2)) + ->method('getFrontendInput') + ->willReturn('image'); + $attributeMock->expects($this->exactly(2)) + ->method('getAttributeCode') + ->willReturn('img1'); + + $entityTypeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $entityTypeMock->expects($this->once()) + ->method('getEntityTypeCode') + ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => $customerEmail, + 'img1' => $filename, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([$attributeMock]); + $this->customerMock->expects($this->once())->method('getEntityType')->willReturn($entityTypeMock); + $this->customerCollectionMock->expects($this->any())->method('getItems')->willReturn([$this->customerMock]); + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn([]); + $this->fileProcessorFactory->expects($this->any()) + ->method('create') + ->with([ + 'entityTypeCode' => CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, + ]) + ->willReturn($this->fileProcessor); + $this->fileProcessor->expects($this->once())->method('isExist')->with($filename)->willReturn(true); + $this->fileProcessor->expects($this->once())->method('getStat')->with($filename)->willReturn(['size' => 1]); + $this->fileProcessor->expects($this->once())->method('getViewUrl') + ->with('/filename.ext1', 'image') + ->willReturn($viewUrl); + $this->fileProcessor->expects($this->once())->method('getMimeType')->with($filename)->willReturn($mime); + + $objectManager = new ObjectManager($this); + + $objectManager->setBackwardCompatibleProperty( + $this->dataProvider, + 'fileProcessorFactory', + $this->fileProcessorFactory + ); + + $this->assertEquals($expectedData, $this->dataProvider->getData()); + } + + public function testGetDataWithCustomAttributeImageNoData() + { + $customerId = 1; + $customerEmail = 'user1@example.com'; + + $expectedData = [ + $customerId => [ + 'customer' => [ + 'email' => $customerEmail, + 'img1' => [], + ], + 'default_billing_address' => [], + 'default_shipping_address' => [], + ], + ]; + + $attributeMock = $this->getMockBuilder(\Magento\Customer\Model\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $attributeMock->expects($this->once()) + ->method('getFrontendInput') + ->willReturn('image'); + $attributeMock->expects($this->exactly(2))->method('getAttributeCode') + ->willReturn('img1'); + + $entityTypeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Type::class) + ->disableOriginalConstructor() + ->getMock(); + $entityTypeMock->expects($this->once()) + ->method('getEntityTypeCode') + ->willReturn(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + + $this->customerMock->expects($this->once()) + ->method('getData') + ->willReturn([ + 'email' => $customerEmail, + ]); + $this->customerMock->expects($this->once())->method('getId')->willReturn($customerId); + $this->customerMock->expects($this->once())->method('getAttributes')->willReturn([$attributeMock]); + $this->customerMock->expects($this->once())->method('getEntityType')->willReturn($entityTypeMock); + $this->customerCollectionMock->expects($this->any())->method('getItems')->willReturn([$this->customerMock]); + $this->sessionMock->expects($this->once())->method('getCustomerFormData')->willReturn([]); + + $this->assertEquals($expectedData, $this->dataProvider->getData()); + } + + /** + * @return void + */ + public function testGetDataWithVisibleAttributes() + { + $firstAttributesBundle = $this->getAttributeMock( + 'customer', + [ + self::ATTRIBUTE_CODE => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_edit'], + 'user_defined' => true, + 'specific_code_prefix' => "_1" + ], + 'test-code-boolean' => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => true, + 'specific_code_prefix' => "_1" + ] + ] + ); + $secondAttributesBundle = $this->getAttributeMock( + 'customer', + [ + self::ATTRIBUTE_CODE => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => false, + 'specific_code_prefix' => "_2" + ], + 'test-code-boolean' => [ + 'visible' => true, + 'is_used_in_forms' => ['customer_account_create'], + 'user_defined' => true, + 'specific_code_prefix' => "_2" + ] + ] + ); + + $helper = new ObjectManager($this); + /** @var \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses $dataProvider */ + $dataProvider = $helper->getObject( + \Magento\Customer\Model\Customer\DataProviderWithDefaultAddresses::class, + [ + 'name' => 'test-name', + 'primaryFieldName' => 'primary-field-name', + 'requestFieldName' => 'request-field-name', + 'eavValidationRules' => $this->eavValidationRulesMock, + 'customerCollectionFactory' => $this->getCustomerCollectionFactoryMock(), + 'eavConfig' => $this->getEavConfigMock(array_merge($firstAttributesBundle, $secondAttributesBundle)) + ] + ); + + $helper->setBackwardCompatibleProperty( + $dataProvider, + 'fileProcessorFactory', + $this->fileProcessorFactory + ); + + $meta = $dataProvider->getMeta(); + $this->assertNotEmpty($meta); + $this->assertEquals($this->getExpectationForVisibleAttributes(), $meta); + } + + /** + * Retrieve all customer variations of attributes with all variations of visibility + * + * @param bool $isRegistration + * @return array + */ + private function getCustomerAttributeExpectations($isRegistration) + { + return [ + self::ATTRIBUTE_CODE . "_1" => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => !$isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + self::ATTRIBUTE_CODE . "_2" => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => true, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean_1' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => $isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'test-code-boolean_2' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => $isRegistration, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + ]; + } + + /** + * Retrieve all variations of attributes with all variations of visibility + * + * @param bool $isRegistration + * @return array + */ + private function getExpectationForVisibleAttributes($isRegistration = true) + { + return [ + 'customer' => [ + 'children' => $this->getCustomerAttributeExpectations($isRegistration), + ], + 'address' => [ + 'children' => [ + self::ATTRIBUTE_CODE => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => 'test-options', + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + ], + ], + ], + ], + 'test-code-boolean' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'visible' => null, + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'prefer' => 'toggle', + 'valueMap' => [ + 'true' => 1, + 'false' => 0, + ], + ], + ], + ], + ], + 'country_id' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'dataType' => 'frontend_input', + 'formElement' => 'frontend_input', + 'options' => null, + 'visible' => null, + 'required' => 'is_required', + 'label' => __('frontend_label'), + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + 'componentType' => Field::NAME, + 'filterBy' => [ + 'target' => '${ $.provider }:data.customer.website_id', + 'field' => 'website_ids' + ] + ], + ], + ], + ] + ], + ], + ]; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index a142f87dcf6c4..1d262e7549873 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -195,35 +195,6 @@ public function testSave() $customerId = 1; $storeId = 2; - $region = $this->getMockForAbstractClass(\Magento\Customer\Api\Data\RegionInterface::class, [], '', false); - $address = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $address2 = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ 'getId', 'setId', @@ -243,10 +214,6 @@ public function testSave() $origCustomer = $this->customer; - $this->customer->expects($this->atLeastOnce()) - ->method('__toArray') - ->willReturn(['default_billing', 'default_shipping']); - $customerAttributesMetaData = $this->getMockForAbstractClass( \Magento\Framework\Api\CustomAttributesDataInterface::class, [], @@ -258,8 +225,6 @@ public function testSave() 'getId', 'getEmail', 'getWebsiteId', - 'getAddresses', - 'setAddresses' ] ); $customerSecureData = $this->createPartialMock(\Magento\Customer\Model\Data\CustomerSecure::class, [ @@ -287,28 +252,6 @@ public function testSave() $this->customerRegistry->expects($this->atLeastOnce()) ->method("remove") ->with($customerId); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $address->expects($this->once()) - ->method('getRegion') - ->willReturn($region); - $address->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(7); - $address->expects($this->once()) - ->method('setRegion') - ->with($region); - $customerAttributesMetaData->expects($this->atLeastOnce()) - ->method('getAddresses') - ->willReturn([$address]); - $customerAttributesMetaData->expects($this->at(1)) - ->method('setAddresses') - ->with([]); - $customerAttributesMetaData->expects($this->at(2)) - ->method('setAddresses') - ->with([$address]); $this->extensibleDataObjectConverter->expects($this->once()) ->method('toNestedArray') ->with($customerAttributesMetaData, [], \Magento\Customer\Api\Data\CustomerInterface::class) @@ -393,12 +336,6 @@ public function testSave() $this->customerRegistry->expects($this->once()) ->method('push') ->with($customerModel); - $this->customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address, $address2]); - $this->addressRepository->expects($this->once()) - ->method('save') - ->with($address); $customerAttributesMetaData->expects($this->once()) ->method('getEmail') ->willReturn('example@example.com'); @@ -446,41 +383,8 @@ public function testSaveWithPasswordHash() '', false ); - $address = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $address2 = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\AddressInterface::class, - [], - '', - false, - false, - true, - [ - 'setCustomerId', - 'setRegion', - 'getRegion', - 'getId' - ] - ); - $origCustomer = $this->customer; - $this->customer->expects($this->atLeastOnce()) - ->method('__toArray') - ->willReturn(['default_billing', 'default_shipping']); - $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ 'getId', 'setId', @@ -505,8 +409,6 @@ public function testSaveWithPasswordHash() 'getId', 'getEmail', 'getWebsiteId', - 'getAddresses', - 'setAddresses' ] ); $customerModel->expects($this->atLeastOnce()) @@ -559,28 +461,6 @@ public function testSaveWithPasswordHash() ->method('save') ->with($this->customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $this->customer) ->willReturn($customerAttributesMetaData); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $address->expects($this->once()) - ->method('getRegion') - ->willReturn($region); - $address->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(7); - $address->expects($this->once()) - ->method('setRegion') - ->with($region); - $customerAttributesMetaData->expects($this->any()) - ->method('getAddresses') - ->willReturn([$address]); - $customerAttributesMetaData->expects($this->at(1)) - ->method('setAddresses') - ->with([]); - $customerAttributesMetaData->expects($this->at(2)) - ->method('setAddresses') - ->with([$address]); $customerAttributesMetaData ->expects($this->atLeastOnce()) ->method('getId') @@ -618,12 +498,6 @@ public function testSaveWithPasswordHash() $this->customerRegistry->expects($this->once()) ->method('push') ->with($customerModel); - $this->customer->expects($this->any()) - ->method('getAddresses') - ->willReturn([$address, $address2]); - $this->addressRepository->expects($this->once()) - ->method('save') - ->with($address); $customerAttributesMetaData->expects($this->once()) ->method('getEmail') ->willReturn('example@example.com'); diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php new file mode 100644 index 0000000000000..82ce4249bcd85 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Ui\Test\Unit\Component\Form; + +use Magento\Customer\Ui\Component\Form\AddressFieldset; +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Test for class \Magento\Customer\Ui\Component\Form\AddressFieldset + */ +class AddressFieldsetTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var AddressFieldset + */ + protected $fieldset; + + /** + * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $context; + + /** + * Set up + * + * @return void + */ + protected function setUp() + { + $this->context = $this->getMockForAbstractClass( + \Magento\Framework\View\Element\UiComponent\ContextInterface::class + ); + $this->fieldset = new AddressFieldset( + $this->context, + [], + [] + ); + } + + /** + * Run test for canShow() method + * + * @return void + * + */ + public function testCanShow() + { + $this->context->expects($this->atLeastOnce())->method('getRequestParam')->with('id') + ->willReturn(1); + $this->assertEquals(true, $this->fieldset->canShow()); + } + + /** + * Run test for canShow() method without customer id in context + * + * @return void + * + */ + public function testCanShowWithoutId() + { + $this->context->expects($this->atLeastOnce())->method('getRequestParam')->with('id') + ->willReturn(null); + $this->assertEquals(false, $this->fieldset->canShow()); + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php b/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php new file mode 100644 index 0000000000000..4d7464b321e85 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Form/AddressFieldset.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Ui\Component\Form; + +use Magento\Framework\View\Element\UiComponent\ContextInterface; + +/** + * Customer addresses fieldset class + */ +class AddressFieldset extends \Magento\Ui\Component\Form\Fieldset +{ + /** + * @param ContextInterface $context + * @param array $components + * @param array $data + */ + public function __construct( + ContextInterface $context, + array $components = [], + array $data = [] + ) { + $this->context = $context; + + parent::__construct($context, $components, $data); + } + + /** + * Can show customer addresses tab in tabs or not + * + * Will return false for not registered customer in a case when admin user created new customer account. + * Needed to hide addresses tab from create new customer page + * + * @return boolean + */ + public function canShow(): bool + { + $customerId = $this->context->getRequestParam('id'); + return (bool)$customerId; + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php new file mode 100644 index 0000000000000..75c02974ded8f --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -0,0 +1,134 @@ +<?php +declare(strict_types=1); +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Ui\Component\Listing\Address\Column; + +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Ui\Component\Listing\Columns\Column; +use Magento\Framework\UrlInterface; + +/** + * Prepare actions column for customer addresses grid + */ +class Actions extends Column +{ + const CUSTOMER_ADDRESS_PATH_DELETE = 'customer/address/delete'; + const CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING = 'customer/address/defaultShippingAddress'; + const CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING = 'customer/address/defaultBillingAddress'; + + /** + * @var UrlInterface + */ + protected $urlBuilder; + + /** + * @param ContextInterface $context + * @param UiComponentFactory $uiComponentFactory + * @param UrlInterface $urlBuilder + * @param array $components + * @param array $data + */ + public function __construct( + ContextInterface $context, + UiComponentFactory $uiComponentFactory, + UrlInterface $urlBuilder, + array $components = [], + array $data = [] + ) { + $this->urlBuilder = $urlBuilder; + parent::__construct($context, $uiComponentFactory, $components, $data); + } + + /** + * Prepare Data Source + * + * @param array $dataSource + * @return array + */ + public function prepareDataSource(array $dataSource): array + { + if (isset($dataSource['data']['items'])) { + foreach ($dataSource['data']['items'] as &$item) { + $name = $this->getData('name'); + if (isset($item['entity_id'])) { + $item[$name]['edit'] = [ + 'callback' => [ + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal.update_customer_address_form_loader', + 'target' => 'destroyInserted', + ], + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal', + 'target' => 'openModal', + ], + [ + 'provider' => 'customer_form.areas.address.address' + . '.customer_address_update_modal.update_customer_address_form_loader', + 'target' => 'render', + 'params' => [ + 'entity_id' => $item['entity_id'], + ], + ] + ], + 'href' => '#', + 'label' => __('Edit'), + 'hidden' => false, + ]; + + $item[$name]['set_default_shipping'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Set as default shipping'), + 'confirm' => [ + 'title' => __('Set address as default shipping'), + 'message' => __( + 'Are you sure you want to set the address with ID: %1 as default shipping address?', + $item['entity_id'] + ) + ] + ]; + + $item[$name]['set_default_billing'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Set as default billing'), + 'confirm' => [ + 'title' => __('Set address as default billing'), + 'message' => __( + 'Are you sure you want to set the address with ID: %1 as default billing address?', + $item['entity_id'] + ) + ] + ]; + + $item[$name]['delete'] = [ + 'href' => $this->urlBuilder->getUrl( + self::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] + ), + 'label' => __('Delete'), + 'confirm' => [ + 'title' => __('Delete address'), + 'message' => __( + 'Are you sure you want to delete the address with ID: %1?', + $item['entity_id'] + ) + ] + ]; + } + } + } + + return $dataSource; + } +} diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php new file mode 100644 index 0000000000000..438a16ec3ba55 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php @@ -0,0 +1,37 @@ +<?php + +namespace Magento\Customer\Ui\Component\Listing\Address\Column; + +use Magento\Framework\Data\OptionSourceInterface; + +/** + * Class for process countries in customer addresses grid + */ +class Countries implements OptionSourceInterface +{ + /** + * @var \Magento\Directory\Model\ResourceModel\Country\CollectionFactory + */ + private $countryCollectionFactory; + + /** + * @param \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $collectionFactory + */ + public function __construct( + \Magento\Directory\Model\ResourceModel\Country\CollectionFactory $collectionFactory + ) { + $this->countryCollectionFactory = $collectionFactory; + } + + /** + * Get list of countries with country id as value and code as label + * + * @return array + */ + public function toOptionArray(): array + { + /** @var \Magento\Directory\Model\ResourceModel\Country\Collection $countryCollection */ + $countryCollection = $this->countryCollectionFactory->create(); + return $countryCollection->toOptionArray(); + } +} diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 7971627521740..7e0b911e26184 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -120,6 +120,15 @@ <index referenceId="CUSTOMER_ADDRESS_ENTITY_PARENT_ID" indexType="btree"> <column name="parent_id"/> </index> + <index name="CUSTOMER_ADDRESS_ENTITY_FULLTEXT_INDEX" indexType="fulltext"> + <column name="firstname"/> + <column name="lastname"/> + <column name="street"/> + <column name="city"/> + <column name="region"/> + <column name="postcode"/> + <column name="telephone"/> + </index> </table> <table name="customer_address_entity_datetime" resource="default" engine="innodb" comment="Customer Address Entity Datetime"> diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6e8c3dc68ed28..a63bff59f1dcf 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -223,6 +223,7 @@ <item name="customer_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Grid\Collection</item> <item name="customer_online_grid_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Online\Grid\Collection</item> <item name="customer_group_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Group\Grid\Collection</item> + <item name="customer_address_listing_data_source" xsi:type="string">Magento\Customer\Model\ResourceModel\Address\Grid\Collection</item> </argument> </arguments> </type> @@ -449,6 +450,14 @@ <argument name="resourceModel" xsi:type="string">Magento\Customer\Model\ResourceModel\Group</argument> </arguments> </type> + <type name="Magento\Customer\Model\ResourceModel\Address\Grid\Collection"> + <arguments> + <argument name="mainTable" xsi:type="string">customer_address_entity</argument> + <argument name="eventPrefix" xsi:type="string">customer_address_entity_grid_collection</argument> + <argument name="eventObject" xsi:type="string">customer_address_entity_grid_collection</argument> + <argument name="resourceModel" xsi:type="string">Magento\Customer\Model\ResourceModel\Address</argument> + </arguments> + </type> <preference for="Magento\Customer\Api\AccountDelegationInterface" type="Magento\Customer\Model\Delegation\AccountDelegation" /> diff --git a/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml b/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml new file mode 100644 index 0000000000000..3acae3acec8aa --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/layout/customer_address_edit.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <update handle="styles"/> + <body> + <referenceContainer name="content"> + <uiComponent name="customer_address_form"/> + </referenceContainer> + </body> +</page> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml new file mode 100644 index 0000000000000..a628c1b1b0b1e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> + </item> + <item name="label" xsi:type="string" translate="true">Update Address</item> + <item name="reverseMetadataMerge" xsi:type="boolean">true</item> + <item name="template" xsi:type="string">templates/form/collapsible</item> + </argument> + <settings> + <buttons> + <button name="cancel" class="Magento\Customer\Block\Adminhtml\Edit\Address\CancelButton"/> + <button name="delete" class="Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton"/> + <button name="save" class="Magento\Customer\Block\Adminhtml\Edit\Address\SaveButton"/> + </buttons> + <namespace>customer_address_form</namespace> + <dataScope>data</dataScope> + <deps> + <dep>customer_address_form.customer_address_form_data_source</dep> + </deps> + </settings> + <dataSource name="customer_address_form_data_source"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="component" xsi:type="string">Magento_Ui/js/form/provider</item> + </item> + </argument> + <settings> + <submitUrl path="customer/address/save"/> + <validateUrl path="customer/address/validate"/> + </settings> + <aclResource>Magento_Customer::manage</aclResource> + <dataProvider class="Magento\Customer\Model\Address\DataProvider" name="customer_address_form_data_source"> + <settings> + <requestFieldName>entity_id</requestFieldName> + <primaryFieldName>entity_id</primaryFieldName> + </settings> + </dataProvider> + </dataSource> + <fieldset name="general"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="is_collection" xsi:type="boolean">true</item> + </item> + </argument> + <settings> + <label/> + <dataScope/> + </settings> + + <field name="entity_id" formElement="hidden"> + <settings> + <dataType>text</dataType> + </settings> + </field> + <field name="default_shipping" sortOrder="0" formElement="checkbox"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="default" xsi:type="number">0</item> + </item> + </argument> + <settings> + <dataType>boolean</dataType> + <label translate="true">Default Shipping Address</label> + <dataScope>default_shipping</dataScope> + </settings> + <formElements> + <checkbox> + <settings> + <valueMap> + <map name="false" xsi:type="number">0</map> + <map name="true" xsi:type="number">1</map> + </valueMap> + <prefer>toggle</prefer> + </settings> + </checkbox> + </formElements> + </field> + <field name="default_billing" sortOrder="1" formElement="checkbox"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="default" xsi:type="number">0</item> + </item> + </argument> + <settings> + <dataType>boolean</dataType> + <label translate="true">Default Billing Address</label> + <dataScope>default_billing</dataScope> + </settings> + <formElements> + <checkbox> + <settings> + <valueMap> + <map name="false" xsi:type="number">0</map> + <map name="true" xsi:type="number">1</map> + </valueMap> + <prefer>toggle</prefer> + </settings> + </checkbox> + </formElements> + </field> + <field name="prefix" sortOrder="10" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Name Prefix</label> + </settings> + </field> + <field name="firstname" sortOrder="20" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">First Name</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="lastname" sortOrder="30" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Last Name</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="suffix" sortOrder="40" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Name Suffix</label> + </settings> + </field> + <field name="middlename" sortOrder="50" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Middle Name/Initial</label> + </settings> + </field> + <field name="company" sortOrder="60" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Company</label> + </settings> + </field> + <field name="city" sortOrder="80" formElement="input"> + <settings> + <dataType>text</dataType> + <label translate="true">City</label> + <visible>true</visible> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="country_id" component="Magento_Ui/js/form/element/country" sortOrder="90" formElement="select"> + <settings> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + <dataType>text</dataType> + </settings> + <formElements> + <select> + <settings> + <options class="Magento\Directory\Model\ResourceModel\Country\Collection"/> + </settings> + </select> + </formElements> + </field> + <field name="region_id" component="Magento_Ui/js/form/element/region" formElement="select"> + <settings> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + <dataType>text</dataType> + <label translate="true">State/Province</label> + </settings> + <formElements> + <select> + <settings> + <filterBy> + <field>country_id</field> + <target>${ $.provider }:${ $.parentScope }.country_id</target> + </filterBy> + <customEntry>region</customEntry> + <options class="Magento\Directory\Model\ResourceModel\Region\Collection"/> + </settings> + </select> + </formElements> + </field> + <field name="postcode" sortOrder="120" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Zip/Postal Code</label> + <validation> + <rule name="required-entry" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + <field name="telephone" sortOrder="130" formElement="input"> + <settings> + <dataType>text</dataType> + <visible>true</visible> + <label translate="true">Phone Number</label> + </settings> + </field> + <field name="vat_id" sortOrder="140" formElement="input"> + <settings> + <dataType>text</dataType> + <label translate="true">VAT Number</label> + <validation> + <rule name="validate-number" xsi:type="boolean">true</rule> + </validation> + </settings> + </field> + </fieldset> +</form> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml new file mode 100644 index 0000000000000..cfc62fc99b10e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -0,0 +1,171 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> + <argument name="data" xsi:type="array"> + <item name="js_config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> + </item> + </argument> + <settings> + <spinner>customer_address_columns</spinner> + <deps> + <dep>customer_address_listing.customer_address_listing_data_source</dep> + </deps> + </settings> + <dataSource name="customer_address_listing_data_source" component="Magento_Ui/js/grid/provider"> + <settings> + <filterUrlParams> + <param name="id">*</param> + </filterUrlParams> + <storageConfig> + <param name="indexField" xsi:type="string">entity_id</param> + </storageConfig> + <updateUrl path="mui/index/render"/> + </settings> + <aclResource>Magento_Customer::manage</aclResource> + <dataProvider class="Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider" name="customer_address_listing_data_source"> + <settings> + <requestFieldName>id</requestFieldName> + <primaryFieldName>entity_id</primaryFieldName> + </settings> + </dataProvider> + </dataSource> + <listingToolbar name="listing_top"> + <bookmark name="bookmarks"/> + <columnsControls name="columns_controls"/> + <!-- Filter Search --> + <filterSearch name="fulltext"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> + <item name="chipsProvider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</item> + <item name="storageConfig" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> + <item name="namespace" xsi:type="string">current.search</item> + </item> + </item> + </argument> + </filterSearch> + <filters name="listing_filters"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="storageConfig" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> + <item name="namespace" xsi:type="string">current.filters</item> + </item> + <item name="childDefaults" xsi:type="array"> + <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> + <item name="imports" xsi:type="array"> + <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> + </item> + </item> + </item> + </argument> + </filters> + <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> + <action name="delete"> + <settings> + <confirm> + <message translate="true">Are you sure to delete selected address?</message> + <title translate="true">Delete items + + + delete + + + + + + + + + + + + false + + entity_id + true + customer_address_listing.customer_address_listing.address_columns.ids + + + + customer_address_listing.customer_address_listing.address_columns_editor + startEdit + + ${ $.$data.rowIndex } + true + + + + + + + entity_id + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + text + + + + + + select + + select + + + + + + text + + text + + + + + + + entity_id + + + + diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js new file mode 100644 index 0000000000000..a715aae1ebd96 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js @@ -0,0 +1,17 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'uiElement' +], function($, Component) { + 'use strict'; + + return Component.extend({ + defaults: { + template: 'Magento_Customer/default-address' + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js new file mode 100644 index 0000000000000..3a1500e5dc99e --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -0,0 +1,44 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/button' +], function (Button) { + 'use strict'; + + return Button.extend({ + initialize: function () { + this._super(); + if (!this.parent_id) { + this.visible(this.entity_id); + } + }, + + defaults: { + entity_id: null, + parent_id: null + }, + + /** + * Apply action on target component, + * but previously create this component from template if it is not existed + * + * @param {Object} action - action configuration + */ + applyAction: function (action) { + if (action.params && action.params[0]) { + action.params[0].entity_id = this.entity_id; + action.params[0].parent_id = this.parent_id; + } else { + action.params = [{ + entity_id: this.entity_id, + parent_id: this.parent_id + }]; + } + + this._super(); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js new file mode 100644 index 0000000000000..94701f4c1af99 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js @@ -0,0 +1,203 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'Magento_Ui/js/modal/modal-component', + 'uiRegistry', + 'underscore' +], function ($, Modal, registry, _) { + 'use strict'; + + return Modal.extend({ + defaults: { + modules: { + emailProvider: '${ $.emailProvider }' + } + }, + + /** + * Initializes component. + * + * @returns {Object} Chainable. + */ + initialize: function () { + this._super(); + + // console.log(this.name); + + return this; + }, + + /** + * Open modal. + */ + openModal: function (data) { + debugger; + if (data == null){ + // add + this.setTitle(this.options.title); + this._super(); + } else { + // edit + var addressId = data.uuid; + var address = { + 'city': 'city', + 'company': 'company', + 'country_id': 'country_id', + 'customer_id': 'customer_id', + 'created_at': 'created_at', + 'default_billing': 'default_billing', + 'default_shipping': 'default_shipping', + 'entity_id': 'entity_id', + 'fax': 'fax', + 'firstname': 'firstname', + 'increment_id': 'increment_id', + 'is_active': 'is_active', + 'lastname': 'lastname', + 'middlename': 'middlename', + 'parent_id': 'parent_id', + 'postcode': 'postcode', + 'prefix': 'prefix', + 'region': 'region', + 'region_id': 'region_id', + 'street': [0, 1], + 'suffix': 'suffix', + 'telephone': 'telephone', + 'updated_at': 'updated_at', + 'vat_id': 'vat_id', + 'vat_is_valid': 'vat_is_valid', + 'vat_request_date': 'vat_request_date', + 'vat_request_id': 'vat_request_id', + 'vat_request_success': 'vat_request_success' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; + + _.each(address, function(value, key) { + if (key === 'default_billing' || key === 'default_shipping') { + var defaultValue = source.get('data.address.' + addressId + '.' + value); + // convert boolean to integer + var val = +defaultValue; + source.set(modal + '.' + key, val.toString()); + } else if (key === 'street' && _.isArray(address[key])) { + _.each(address[key], function(element, index) { + source.set(modal + '.' + key + '[' + index + ']', source.get('data.address.' + addressId + '.' + key + '.' + element)); + }); + } else { + source.set(modal + '.' + key, source.get('data.address.' + addressId + '.' + value)); + } + }); + + this.setTitle(this.options.title); + this._super(); + } + }, + + /** + * Close popup modal. + * @public + */ + closeModal: function () { + debugger; + this._clearData(); + this._super(); + }, + + /** + * Clear modal data. + * + * @private + */ + _clearData: function () { + debugger; + var address = { + 'city': '', + 'company': '', + 'country_id': '', + 'default_billing': "0", + 'default_shipping': "0", + 'entity_id': '', + 'firstname': '', + 'is_active': '', + 'lastname': '', + 'middlename': '', + 'postcode': '', + 'prefix': '', + 'region': '', + 'region_id': '', + 'street[0]': '', + 'street[1]': '', + 'suffix': '', + 'telephone': '', + 'vat_id': '' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; + + _.each(address, function(value, key) { + source.set(modal + '.' + key, value); + }); + }, + + /** + * Open modal. + */ + save: function () { + debugger; + + var address = { + 'city': 'city', + 'company': 'company', + 'country_id': 'country_id', + 'customer_id': 'customer_id', + 'created_at': 'created_at', + 'default_billing': 'default_billing', + 'default_shipping': 'default_shipping', + 'entity_id': 'entity_id', + 'fax': 'fax', + 'firstname': 'firstname', + 'increment_id': 'increment_id', + 'is_active': 'is_active', + 'lastname': 'lastname', + 'middlename': 'middlename', + 'parent_id': 'parent_id', + 'postcode': 'postcode', + 'prefix': 'prefix', + 'region': 'region', + 'region_id': 'region_id', + 'street': ['street[0]', 'street[1]'], + 'suffix': 'region_id', + 'telephone': 'telephone', + 'updated_at': 'updated_at', + 'vat_id': 'vat_id', + 'vat_is_valid': 'vat_is_valid', + 'vat_request_date': 'vat_request_date', + 'vat_request_id': 'vat_request_id', + 'vat_request_success': 'vat_request_success' + }; + + var source = registry.get('customer_form.customer_form_data_source'); + var formData = source.get('data.address_listing.address_form.update_customer_address_form_modal'); + var entityId = formData.entity_id; + + $.ajax({ + url: this.options.url, + showLoader: true, + data: formData, + type: "POST", + dataType: 'json', + success: function(data) { + console.log('SUCCESS: ', data); + }, + error: function(data) { + console.log('ERROR: ', data); + } + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js new file mode 100644 index 0000000000000..edfb004654a9b --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -0,0 +1,164 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-form' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + // Should be refactored after form save.!!!!! + // defaults: { + // updateModalProvider: '${ $.parentName }', + // subTitlePrefix: $t('Belongs to '), + // switcherSelector: '.store-switcher', + // toRemove: [], + // // imports: { + // // removeResponseData: '${ $.removeResponseProvider }', + // // modalTitle: '${ $.modalTitleProvider }', + // // modalSubTitle: '${ $.modalSubTitleProvider }', + // // destroyClosedModalContents: '${ $.updateModalProvider }:state' + // // }, + // // listens: { + // // responseData: 'afterUpdate', + // // removeResponseData: 'afterRemove', + // // modalTitle: 'changeModalTitle', + // // modalSubTitle: 'changeModalSubTitle' + // // }, + // modules: { + // updateModal: '${ $.updateModalProvider }', + // removeModal: '${ $.removeModalProvider }', + // upcomingListing: 'index = ${ $.upcomingListingProvider }' + // } + // }, + // + // /** @inheritdoc **/ + // initialize: function () { + // _.bindAll(this, 'onSwitcherSelect'); + // this._super(); + // this.updateModal(this.initSwitcherHandler.bind(this)); + // + // return this; + // }, + // + // initConfig: function (options) { + // debugger; + // return this._super(); + // }, + // + // /** @inheritdoc */ + // destroyInserted: function () { + // if (this.isRendered) { + // _.each(this.toRemove, function (componentName) { + // registry.get(componentName, function (component) { + // if (component.hasOwnProperty('delegate')) { + // component.delegate('destroy'); + // } else { + // component.destroy(); + // } + // }); + // }); + // } + // + // this._super(); + // }, + // + // // /** + // // * Form save callback. + // // * + // // * @param {Object} data + // // */ + // // afterUpdate: function (data) { + // // if (!data.error) { + // // this.updateModal('closeModal'); + // // this.upcomingListing('reload'); + // // } + // // }, + // + // // /** + // // * Form remove callback. + // // * + // // * @param {Object} data + // // */ + // // afterRemove: function (data) { + // // if (!data.error) { + // // this.removeModal('closeModal'); + // // this.afterUpdate(data); + // // } + // // }, + // + // // /** + // // * Change modal title. + // // * + // // * @param {String} title + // // */ + // // changeModalTitle: function (title) { + // // this.updateModal('setTitle', title); + // // }, + // // + // // /** + // // * Change modal sub title. + // // * + // // * @param {String} subTitle + // // */ + // // changeModalSubTitle: function (subTitle) { + // // subTitle = subTitle ? + // // this.subTitlePrefix + this.modalTitle + ' ' + subTitle : + // // ''; + // // + // // this.updateModal('setSubTitle', subTitle); + // // }, + // + // /** + // * Destroy contents of modal when it is closed + // * + // * @param {Boolean} state + // */ + // destroyClosedModalContents: function (state) { + // if (state === false) { + // this.destroyInserted(); + // } + // }, + // + // /** + // * Switcher initialization. + // */ + // initSwitcherHandler: function () { + // var switcherSelector = this.updateModal().rootSelector + ' ' + this.switcherSelector, + // self = this; + // + // $.async(switcherSelector, function (switcher) { + // $(switcher).on('click', 'li a', self.onSwitcherSelect); + // }); + // }, + // + // /** + // * Store switcher selection handler. + // * @param {Object} e - event object. + // */ + // onSwitcherSelect: function (e) { + // var self = this, + // param = $(e.currentTarget).data('param'), + // params = { + // store: 0 + // }; + // + // params[param] = $(e.currentTarget).data('value'); + // + // uiConfirm({ + // content: $t('Please confirm scope switching. All data that hasn\'t been saved will be lost.'), + // actions: { + // + // /** Confirm callback. */ + // confirm: function () { + // self.destroyInserted(); + // params = _.extend(self.previousParams, params); + // self.render(params); + // } + // } + // }); + // } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html new file mode 100644 index 0000000000000..1ee5a4da81d2b --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -0,0 +1,42 @@ +
+
+
+
+ +
+
+ + + + + +
+ + +
+
+ + +
+
+ + + + +
+
+ + +
T: +
+ +
F: +
+ +
VAT: +
+
+ +
+
+
diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index d2a9b3f44624d..1eb3652628c28 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -43,7 +43,7 @@ - + id entity_id @@ -303,262 +303,175 @@ -
- - - true - Are you sure you want to delete this item? - - +
+ false + fieldset + + true + - - - - address - - - - number - false - - - + - address + billing-address + Default Billing Address + customer-default-billing-address-content + The customer does not have default billing address - text - true - - - - - - address - - - - - true - - text - ${ $.provider }:data.customer.firstname + ${ $.provider}:data.default_billing_address - - - - - address - - - - text - true - - - - - - address + + + + + - address + shipping-address + Default Shipping Address + customer-default-shipping-address-content + The customer does not have default shipping address - - true - - text - - - - - - address - - - - - true - - text - ${ $.provider }:data.customer.website_id + ${ $.provider}:data.default_shipping_address - - - - - address - - - - text - false - - - - - - address - - - - - true - - text - - - - - - - - - address - - - - - true - - text - - - - - - address - - - - text - - - - - - address - - - - - 0 - - text - - - - - - address + + + + + - ui/form/element/checkbox - boolean + + + - - - - Default Shipping Address - - - - + + + + + customer_address_edit + 1 + + false + ${ $.parentName } + ${ $.ns }.customer_address_form_data_source + customer_address_form + + + + + + + false + true + + customer_address_listing.customer_address_listing_data_source + customer_address_listing.customer_address_listing.customer_address_listing_columns.ids + true + customer_address_listing + customer_address_listing + + ${ $.externalProvider }:params.parent_id + + + ${ $.provider }:data.customer.entity_id + + +
diff --git a/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php b/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php index c2460fd8385c1..f15a97e96c549 100644 --- a/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php +++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Media.php @@ -35,6 +35,7 @@ public function prepare() $this->getData(), [ 'config' => [ + 'dataScope' => $this->getName(), 'uploaderConfig' => [ 'url' => $url ], diff --git a/app/code/Magento/Ui/Component/Form/Fieldset.php b/app/code/Magento/Ui/Component/Form/Fieldset.php index 745068ca0fa8a..ebfe58f3abb89 100644 --- a/app/code/Magento/Ui/Component/Form/Fieldset.php +++ b/app/code/Magento/Ui/Component/Form/Fieldset.php @@ -5,11 +5,7 @@ */ namespace Magento\Ui\Component\Form; -use Magento\Ui\Component\Container; use Magento\Ui\Component\AbstractComponent; -use Magento\Framework\View\Element\UiComponentFactory; -use Magento\Framework\View\Element\UiComponentInterface; -use Magento\Framework\View\Element\UiComponent\ContextInterface; /** * @api @@ -33,4 +29,14 @@ public function getComponentName() { return static::NAME; } + + /** + * Check that fieldset can be shown. + * + * @return bool + */ + public function canShow(): bool + { + return true; + } } diff --git a/app/code/Magento/Ui/Component/Layout/Tabs.php b/app/code/Magento/Ui/Component/Layout/Tabs.php index 8ceac716ae218..02e8979f525ef 100644 --- a/app/code/Magento/Ui/Component/Layout/Tabs.php +++ b/app/code/Magento/Ui/Component/Layout/Tabs.php @@ -11,6 +11,7 @@ use Magento\Framework\View\Element\UiComponent\LayoutInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; +use Magento\Ui\Component\Form\Fieldset; use Magento\Ui\Component\Layout\Tabs\TabInterface; /** @@ -89,6 +90,9 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $this->addWrappedBlock($childComponent, $childrenAreas); continue; } + if ($childComponent instanceof Fieldset && false === $childComponent->canShow()) { + continue; + } $name = $childComponent->getName(); $config = $childComponent->getData('config'); diff --git a/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php new file mode 100644 index 0000000000000..9a8cf28ae0719 --- /dev/null +++ b/app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php @@ -0,0 +1,69 @@ +context = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\ContextInterface::class) + ->getMockForAbstractClass(); + + $this->fieldset = new Fieldset( + $this->context, + [], + [] + ); + } + + /** + * Run test for getComponentName() method + * + * @return void + * + */ + public function testGetComponentName() + { + $this->assertEquals(self::NAME, $this->fieldset->getComponentName()); + } + + /** + * Run test for canShow() method + * + * @return void + * + */ + public function testCanShow() + { + $this->assertEquals(true, $this->fieldset->canShow()); + } +} diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js index 2c12486ceb519..dbea61b13e626 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js @@ -5,6 +5,9 @@ /** * @api + * @deprecated as customer addresses are handled by ui components. + * This collection component manages rendering address list in Addresses tab of customer. + * Now address list is rendered with ui component listing. */ define([ 'underscore', @@ -46,6 +49,7 @@ define([ * @param {Object} elem - Incoming child. */ initElement: function (elem) { + debugger; this._super(); elem.activate(); @@ -153,6 +157,7 @@ define([ * Creates function that removes element * from collection using '_removeChild' method. * @param {Object} elem - Element that should be removed. + * @deprecated Not used anymore */ removeAddress: function (elem) { var self = this; @@ -169,7 +174,7 @@ define([ }, /** - * Removes elememt from both collection and data storage, + * Removes element from both collection and data storage, * activates first element if removed one was active, * triggers 'update' event. * diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js index c2a65371471c5..ae7f375bdca02 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js @@ -5,6 +5,9 @@ /** * @api + * @deprecated as customer addresses are handled by ui components. + * This item component renders address list item preview in Addresses tab. + * But now address list item is rendered with ui component in customer form. */ define([ 'underscore', @@ -19,7 +22,7 @@ define([ }; /** - * Parses incoming data and returnes result merged with default preview config + * Parses incoming data and returns result merged with default preview config * * @param {Object|String} data * @return {Object} diff --git a/app/code/Magento/Ui/view/base/web/templates/form/insert.html b/app/code/Magento/Ui/view/base/web/templates/form/insert.html index e19b2784e6bc6..e590b5e2adedf 100644 --- a/app/code/Magento/Ui/view/base/web/templates/form/insert.html +++ b/app/code/Magento/Ui/view/base/web/templates/form/insert.html @@ -6,9 +6,6 @@ -->
diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index a80cc9a5163f8..8a5fe698eb196 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -3,14 +3,72 @@ // * See COPYING.txt for license details. // */ -// General rule hides group legend and shows first field label instead -// in app/design/adminhtml/Magento/backend/web/css/source/forms/_fields.less -// This must be reset for Customer Address page -.address-item-edit-content { +.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { .admin__field { - legend { - &.admin__field-label { - opacity: 1; + .admin__field { + .admin__field-label { + background: none; + } + } + } +} + +.customer-address-form { + + *, *:before, *:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + + address { + font-style: normal; + } + + .customer-default-billing-address-content, + .customer-default-shipping-address-content + { + float: left; + width: 550px; + } + + .edit-default-billing-address-button, + .edit-default-shipping-address-button { + float: left; + position: relative; + top: 2px; + } + + .edit-default-billing-address-button { + left: -336px; + } + + .edit-default-shipping-address-button { + left: -315px; + } + + .customer_form_areas_address_address_customer_address_listing { + clear: both; + } + + .add-new-address-button { + position: relative; + clear: both; + float: right; + margin-bottom: 30px; + } + + .address-information { + float: left; + margin-bottom: 20px; + + address { + float: left; + + .address_caption { + font-size: 18px; + font-weight: bold; + margin-bottom: 16px; } } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php new file mode 100644 index 0000000000000..6a41dd70e89e2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -0,0 +1,222 @@ +customerRepository = Bootstrap::getObjectManager()->get( + \Magento\Customer\Api\CustomerRepositoryInterface::class + ); + $this->accountManagement = Bootstrap::getObjectManager()->get( + \Magento\Customer\Api\AccountManagementInterface::class + ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->customerAddress = $this->objectManager->get(\Magento\Customer\Controller\Adminhtml\Address\Save::class); + } + + /** + * @inheritDoc + */ + protected function tearDown() + { + /** + * Unset customer data + */ + Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->setCustomerData(null); + + /** + * Unset messages + */ + Bootstrap::getObjectManager()->get(\Magento\Backend\Model\Session::class)->getMessages(true); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_address.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithValidAddressData() + { + $customer = $this->customerRepository->get('customer5@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + $customer = $this->customerRepository->getById($customerId); + + $this->assertEquals('Firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(1, $addresses); + $this->assertNull($this->accountManagement->getDefaultBillingAddress($customerId)); + $this->assertNull($this->accountManagement->getDefaultShippingAddress($customerId)); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_no_address.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithDefaultShippingAndBilling() + { + $customer = $this->customerRepository->get('customer5@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + 'default_billing' => true, + 'default_shipping' => true + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + /** + * Remove stored customer from registry + */ + $this->objectManager->get(\Magento\Customer\Model\CustomerRegistry::class)->remove($customerId); + $customer = $this->customerRepository->get('customer5@example.com'); + $this->assertEquals('Firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(1, $addresses); + + $this->assertNotNull($this->accountManagement->getDefaultBillingAddress($customerId)); + $this->assertNotNull($this->accountManagement->getDefaultShippingAddress($customerId)); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer_sample.php + * + * Check that customer id set and addresses saved + */ + public function testSaveActionWithExistingAdresses() + { + $customer = $this->customerRepository->get('customer@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => 'test firstname', + 'lastname' => 'test lastname', + 'street' => ['test street'], + 'city' => 'test city', + 'region_id' => 10, + 'country_id' => 'US', + 'postcode' => '01001', + 'telephone' => '+7000000001', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); + + /** + * Check that customer data were cleaned after it was saved successfully + */ + $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); + + /** + * Check that success message is set + */ + $this->assertSessionMessages( + $this->logicalNot($this->isEmpty()), + \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS + ); + + $customer = $this->customerRepository->getById($customerId); + + $this->assertEquals('test firstname', $customer->getFirstname()); + $addresses = $customer->getAddresses(); + $this->assertCount(4, $addresses); + } +} diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt index 877583e5b6a29..5c5c380c4dd33 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt @@ -1 +1 @@ -# Format: or simply +# Format: or simply \ No newline at end of file diff --git a/setup/performance-toolkit/config/customerConfig.xml b/setup/performance-toolkit/config/customerConfig.xml index 8fd74d7b53885..b77d9f6d4c941 100644 --- a/setup/performance-toolkit/config/customerConfig.xml +++ b/setup/performance-toolkit/config/customerConfig.xml @@ -6,5 +6,5 @@ */ --> - 2 + 5 From e2b3f791b49e961f757685eaa06b3f221b718148 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 16:35:24 +0300 Subject: [PATCH 025/216] MAGETWO-95671: Remove address id from dialog alerts --- .../Component/Listing/Address/Column/Actions.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 75c02974ded8f..e0fea85bd3d80 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -89,10 +89,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Set as default shipping'), 'confirm' => [ 'title' => __('Set address as default shipping'), - 'message' => __( - 'Are you sure you want to set the address with ID: %1 as default shipping address?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to set the address as default shipping address?') ] ]; @@ -104,10 +101,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Set as default billing'), 'confirm' => [ 'title' => __('Set address as default billing'), - 'message' => __( - 'Are you sure you want to set the address with ID: %1 as default billing address?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; @@ -119,10 +113,7 @@ public function prepareDataSource(array $dataSource): array 'label' => __('Delete'), 'confirm' => [ 'title' => __('Delete address'), - 'message' => __( - 'Are you sure you want to delete the address with ID: %1?', - $item['entity_id'] - ) + 'message' => __('Are you sure you want to delete the address?') ] ]; } From f1a23e4418aeb12f0011af06dc40e2b3b1f17539 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 16:40:35 +0300 Subject: [PATCH 026/216] MAGETWO-95671: Remove address id from dialog alerts --- .../Listing/Address/Column/Actions.php | 20 +++++++++---------- .../ui_component/customer_address_form.xml | 12 +++++------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index e0fea85bd3d80..e44dc7988761f 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -81,27 +81,27 @@ public function prepareDataSource(array $dataSource): array 'hidden' => false, ]; - $item[$name]['set_default_shipping'] = [ + $item[$name]['set_default_billing'] = [ 'href' => $this->urlBuilder->getUrl( - self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, + self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), - 'label' => __('Set as default shipping'), + 'label' => __('Set as default billing'), 'confirm' => [ - 'title' => __('Set address as default shipping'), - 'message' => __('Are you sure you want to set the address as default shipping address?') + 'title' => __('Set address as default billing'), + 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; - $item[$name]['set_default_billing'] = [ + $item[$name]['set_default_shipping'] = [ 'href' => $this->urlBuilder->getUrl( - self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, + self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), - 'label' => __('Set as default billing'), + 'label' => __('Set as default shipping'), 'confirm' => [ - 'title' => __('Set address as default billing'), - 'message' => __('Are you sure you want to set the address as default billing address?') + 'title' => __('Set address as default shipping'), + 'message' => __('Are you sure you want to set the address as default shipping address?') ] ]; diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index a628c1b1b0b1e..9e432f9f10e0c 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -60,7 +60,7 @@ text - + 0 @@ -68,8 +68,8 @@ boolean - - default_shipping + + default_billing @@ -83,7 +83,7 @@ - + 0 @@ -91,8 +91,8 @@ boolean - - default_billing + + default_shipping From 04af36ed9ec5bf498682b38857fd33991cfc13ff Mon Sep 17 00:00:00 2001 From: Jeroen Date: Fri, 26 Oct 2018 14:44:08 +0200 Subject: [PATCH 027/216] Cancel expired orders using OrderManagementInterface --- .../Model/CronJob/CleanExpiredOrders.php | 25 +++++++++++++++---- .../Model/CronJob/CleanExpiredOrdersTest.php | 22 +++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php index 8a7bd0260df0f..80370c21d4d7b 100644 --- a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php +++ b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php @@ -3,8 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Model\CronJob; +use Magento\Framework\App\ObjectManager; +use Magento\Sales\Api\OrderManagementInterface; +use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; use Magento\Store\Model\StoresConfig; use Magento\Sales\Model\Order; @@ -16,20 +21,28 @@ class CleanExpiredOrders protected $storesConfig; /** - * @var \Magento\Sales\Model\ResourceModel\Order\CollectionFactory + * @var CollectionFactory */ protected $orderCollectionFactory; + /** + * @var OrderManagementInterface + */ + private $orderManagement; + /** * @param StoresConfig $storesConfig - * @param \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $collectionFactory + * @param CollectionFactory $collectionFactory + * @param OrderManagementInterface|null $orderManagement */ public function __construct( StoresConfig $storesConfig, - \Magento\Sales\Model\ResourceModel\Order\CollectionFactory $collectionFactory + CollectionFactory $collectionFactory, + OrderManagementInterface $orderManagement = null ) { $this->storesConfig = $storesConfig; $this->orderCollectionFactory = $collectionFactory; + $this->orderManagement = $orderManagement ?: ObjectManager::getInstance()->get(OrderManagementInterface::class); } /** @@ -48,8 +61,10 @@ public function execute() $orders->getSelect()->where( new \Zend_Db_Expr('TIME_TO_SEC(TIMEDIFF(CURRENT_TIMESTAMP, `updated_at`)) >= ' . $lifetime * 60) ); - $orders->walk('cancel'); - $orders->walk('save'); + + foreach ($orders->getAllIds() as $entityId) { + $this->orderManagement->cancel((int) $entityId); + } } } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php b/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php index 269ce829e64d3..6844b908ea98d 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/CronJob/CleanExpiredOrdersTest.php @@ -26,6 +26,11 @@ class CleanExpiredOrdersTest extends \PHPUnit\Framework\TestCase */ protected $orderCollectionMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $orderManagementMock; + /** * @var ObjectManager */ @@ -44,10 +49,12 @@ protected function setUp() ['create'] ); $this->orderCollectionMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Collection::class); + $this->orderManagementMock = $this->createMock(\Magento\Sales\Api\OrderManagementInterface::class); $this->model = new CleanExpiredOrders( $this->storesConfigMock, - $this->collectionFactoryMock + $this->collectionFactoryMock, + $this->orderManagementMock ); } @@ -64,8 +71,11 @@ public function testExecute() $this->collectionFactoryMock->expects($this->exactly(2)) ->method('create') ->willReturn($this->orderCollectionMock); + $this->orderCollectionMock->expects($this->exactly(2)) + ->method('getAllIds') + ->willReturn([1, 2]); $this->orderCollectionMock->expects($this->exactly(4))->method('addFieldToFilter'); - $this->orderCollectionMock->expects($this->exactly(4))->method('walk'); + $this->orderManagementMock->expects($this->exactly(4))->method('cancel'); $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); $selectMock->expects($this->exactly(2))->method('where')->willReturnSelf(); @@ -92,14 +102,18 @@ public function testExecuteWithException() $this->collectionFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->orderCollectionMock); + $this->orderCollectionMock->expects($this->once()) + ->method('getAllIds') + ->willReturn([1]); $this->orderCollectionMock->expects($this->exactly(2))->method('addFieldToFilter'); + $this->orderManagementMock->expects($this->once())->method('cancel'); $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); $selectMock->expects($this->once())->method('where')->willReturnSelf(); $this->orderCollectionMock->expects($this->once())->method('getSelect')->willReturn($selectMock); - $this->orderCollectionMock->expects($this->once()) - ->method('walk') + $this->orderManagementMock->expects($this->once()) + ->method('cancel') ->willThrowException(new \Exception($exceptionMessage)); $this->model->execute(); From d51c135b4b27c69e36bf45f6caf7ba92c0c67131 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 18:23:15 +0300 Subject: [PATCH 028/216] MAGETWO-95687: Remove old implementation of customer addresses tab --- .../Adminhtml/Edit/Address/CancelButton.php | 2 +- .../Adminhtml/Edit/Address/SaveButton.php | 2 +- .../Controller/Adminhtml/Address/Save.php | 3 +- .../Controller/Adminhtml/Address/Validate.php | 4 +-- .../Controller/Adminhtml/Index/Save.php | 2 ++ .../Controller/Adminhtml/Index/Validate.php | 3 ++ .../Customer/Model/Address/DataProvider.php | 31 +++++-------------- .../Customer/Model/Customer/DataProvider.php | 1 + .../DataProviderWithDefaultAddresses.php | 20 +----------- .../Customer/Model/Metadata/Form/File.php | 17 +++++----- .../ResourceModel/Address/Grid/Collection.php | 4 +-- .../Test/Unit/Controller/Address/SaveTest.php | 2 -- .../Unit/Model/Customer/DataProviderTest.php | 1 + .../Magento/Ui/Component/Form/Fieldset.php | 2 ++ 14 files changed, 34 insertions(+), 60 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php index 80d9780f819d0..6270e8073d0e8 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -14,7 +14,7 @@ class CancelButton extends GenericButton implements ButtonProviderInterface { /** - * {@inheritdoc} + * @inheritdoc * * @return array */ diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php index 706ef32c9e5a5..0d3a9f57ff5a3 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/SaveButton.php @@ -14,7 +14,7 @@ class SaveButton extends GenericButton implements ButtonProviderInterface { /** - * {@inheritdoc} + * @inheritdoc * * @return array */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index df041ac4e1202..e1d605a8d0890 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -135,7 +135,8 @@ public function execute(): Redirect $this->logger->critical($e); } catch (\Exception $e) { $this->messageManager->addExceptionMessage( - $e, __('We can\'t change customer address right now.') + $e, + __('We can\'t change customer address right now.') ); } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php index 01ce720a20e63..696bf3099db11 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -33,9 +33,9 @@ class Validate extends \Magento\Backend\App\Action implements HttpPostActionInte private $formFactory; /** - * @param Action\Context $context + * @param Action\Context $context * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory - * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory + * @param \Magento\Customer\Model\Metadata\FormFactory $formFactory */ public function __construct( Action\Context $context, diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php index aed7908337ee1..d80c712914ef0 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Save.php @@ -15,6 +15,8 @@ use Magento\Framework\Exception\LocalizedException; /** + * Save customer action. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Save extends \Magento\Customer\Controller\Adminhtml\Index implements HttpPostActionInterface diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php index 67adf98d6c718..d91bc7424bffe 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Validate.php @@ -11,6 +11,9 @@ use Magento\Framework\Message\Error; use Magento\Customer\Controller\Adminhtml\Index as CustomerAction; +/** + * Class for validation of customer + */ class Validate extends CustomerAction implements HttpPostActionInterface, HttpGetActionInterface { /** diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 34f4b8b4eca89..c92cd731db743 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -27,9 +27,9 @@ use Magento\Customer\Model\FileProcessorFactory; /** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * * Dataprovider for customer address grid. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider { @@ -53,11 +53,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $loadedData; - /** - * @var Config - */ - private $eavConfig; - /** * EAV attribute properties to fetch from meta storage * @var array @@ -154,6 +149,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param ContextInterface $context * @param FileProcessorFactory $fileProcessorFactory * @param \Magento\Customer\Model\Config\Share $shareConfig + * @param CountryWithWebsites $countryWithWebsites * @param array $meta * @param array $data * @param bool $allowToShowHiddenAttributes @@ -170,6 +166,7 @@ public function __construct( ContextInterface $context, FileProcessorFactory $fileProcessorFactory, \Magento\Customer\Model\Config\Share $shareConfig, + CountryWithWebsites $countryWithWebsites, array $meta = [], array $data = [], $allowToShowHiddenAttributes = true @@ -182,6 +179,7 @@ public function __construct( $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->context = $context; $this->fileProcessorFactory = $fileProcessorFactory; + $this->countryWithWebsiteSource = $countryWithWebsites; $this->shareConfig = $shareConfig; $this->meta['general']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer_address') @@ -323,7 +321,7 @@ protected function getAttributesMeta(Type $entityType): array if ($attribute->usesSource()) { if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->getCountryWithWebsiteSource() + $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource ->getAllOptions(); } else { $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); @@ -364,25 +362,10 @@ private function processFrontendInput(AttributeInterface $attribute, array &$met } } - /** - * Retrieve Country With Websites Source - * - * @return CountryWithWebsites - * @deprecated 100.2.0 - */ - private function getCountryWithWebsiteSource(): CountryWithWebsites - { - if (!$this->countryWithWebsiteSource) { - $this->countryWithWebsiteSource = ObjectManager::getInstance()->get(CountryWithWebsites::class); - } - - return $this->countryWithWebsiteSource; - } - /** * Detect can we show attribute on specific form or not * - * @param Attribute $customerAttribute + * @param AbstractAttribute $customerAttribute * @return bool */ private function canShowAttribute(AbstractAttribute $customerAttribute): bool diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index ce976d3f62c74..c834dd26824cd 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -31,6 +31,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * + * @deprecated \Magento\Customer\Model\Address\DataProvider is used instead * @api * @since 100.0.2 */ diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index d52c94fb034c6..2e47787b9adbc 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -186,9 +186,6 @@ public function __construct( $this->meta['customer']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer') ); -// $this->meta['address']['children'] = $this->getAttributesMeta( -// $eavConfig->getEntityType('customer_address') -// ); } /** @@ -300,7 +297,7 @@ private function getFileUploaderData( $file = $customerData[$attributeCode] ?? ''; /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->getFileProcessorFactory()->create([ + $fileProcessor = $this->fileProcessorFactory->create([ 'entityTypeCode' => $entityType->getEntityTypeCode(), ]); @@ -567,19 +564,4 @@ protected function prepareAddressData($addressId, array &$addresses, array $cust $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); } } - - /** - * Get FileProcessorFactory instance - * - * @return FileProcessorFactory - * @deprecated 100.1.3 - */ - private function getFileProcessorFactory(): FileProcessorFactory - { - if ($this->fileProcessorFactory === null) { - $this->fileProcessorFactory = ObjectManager::getInstance() - ->get(\Magento\Customer\Model\FileProcessorFactory::class); - } - return $this->fileProcessorFactory; - } } diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index aca5b277186ca..b9bec01f9ba7c 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -15,6 +15,8 @@ use Magento\Framework\Filesystem; /** + * Processes files that are save for customer. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class File extends AbstractData @@ -66,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param null $value + * @param array|string $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder @@ -101,7 +103,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function extractValue(\Magento\Framework\App\RequestInterface $request) @@ -160,8 +162,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request) } /** - * Validate file by attribute validate rules - * Return array of errors + * Validate file by attribute validate rules. Returns array of errors. * * @param array $value * @return string[] @@ -232,7 +233,7 @@ protected function _isUploadedFile($filename) } /** - * {@inheritdoc} + * @inheritdoc * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -273,7 +274,7 @@ public function validateValue($value) } /** - * {@inheritdoc} + * @inheritdoc * * @return ImageContentInterface|array|string|null */ @@ -358,7 +359,7 @@ protected function processInputFieldValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function restoreValue($value) { @@ -366,7 +367,7 @@ public function restoreValue($value) } /** - * {@inheritdoc} + * @inheritdoc */ public function outputValue($format = \Magento\Customer\Model\Metadata\ElementFactory::OUTPUT_FORMAT_TEXT) { diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 83129fee9b59b..8026349563867 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -92,7 +92,7 @@ protected function _initSelect() } /** - * {@inheritdoc} + * @inheritdoc * * @return AggregationInterface */ @@ -102,7 +102,7 @@ public function getAggregations() } /** - * {@inheritdoc} + * @inheritdoc * * @param AggregationInterface $aggregations * @return $this diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php index 47088eece23ed..863ce260ab68c 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Address/SaveTest.php @@ -24,7 +24,6 @@ class SaveTest extends \PHPUnit\Framework\TestCase */ private $addressRepositoryMock; - /** * @var \Magento\Customer\Model\Metadata\FormFactory|\PHPUnit_Framework_MockObject_MockObject */ @@ -65,7 +64,6 @@ class SaveTest extends \PHPUnit\Framework\TestCase */ private $messageManagerMock; - /** * @inheritdoc */ diff --git a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php index 50c21379054bf..bf6d3f0f9bbc5 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Customer/DataProviderTest.php @@ -21,6 +21,7 @@ * * Test for class \Magento\Customer\Model\Customer\DataProvider * + * @deprecated tested class is not used. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProviderTest extends \PHPUnit\Framework\TestCase diff --git a/app/code/Magento/Ui/Component/Form/Fieldset.php b/app/code/Magento/Ui/Component/Form/Fieldset.php index ebfe58f3abb89..ef115fe459eba 100644 --- a/app/code/Magento/Ui/Component/Form/Fieldset.php +++ b/app/code/Magento/Ui/Component/Form/Fieldset.php @@ -8,6 +8,8 @@ use Magento\Ui\Component\AbstractComponent; /** + * Fieldset UI Component. + * * @api * @since 100.0.2 */ From dc506771ce4353b0d3a272368acd7322dbf391c8 Mon Sep 17 00:00:00 2001 From: Ruslan Kostiv Date: Fri, 26 Oct 2018 19:16:12 +0300 Subject: [PATCH 029/216] MAGETWO-95687: Remove old implementation of customer addresses tab --- .../Customer/Model/Address/DataProvider.php | 2 +- .../DataProviderWithDefaultAddresses.php | 25 ------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index c92cd731db743..7f23deddd89a6 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -384,7 +384,7 @@ private function canShowAttribute(AbstractAttribute $customerAttribute): bool /** * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... * - * @param Attribute $customerAttribute + * @param AbstractAttribute $customerAttribute * @return bool */ private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 2e47787b9adbc..7ba6484dc3f2b 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -539,29 +539,4 @@ private function processFrontendInput(AttributeInterface $attribute, array &$met ]; } } - - /** - * Prepare address data - * - * @param int $addressId - * @param array $addresses - * @param array $customer - * @return void - */ - protected function prepareAddressData($addressId, array &$addresses, array $customer) - { - if (isset($customer['default_billing']) - && $addressId == $customer['default_billing'] - ) { - $addresses[$addressId]['default_billing'] = $customer['default_billing']; - } - if (isset($customer['default_shipping']) - && $addressId == $customer['default_shipping'] - ) { - $addresses[$addressId]['default_shipping'] = $customer['default_shipping']; - } - if (isset($addresses[$addressId]['street']) && !\is_array($addresses[$addressId]['street'])) { - $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); - } - } } From 3d317714b5e5a6d190b1e930726e95501cf03631 Mon Sep 17 00:00:00 2001 From: bshevchenko <1408sheva@gmail.com> Date: Mon, 29 Oct 2018 16:31:09 +0200 Subject: [PATCH 030/216] MAGETWO-94840: Automate with MFTF Managing Advanced Prices from Shared Catalog Page --- .../Mftf/ActionGroup/AdminProductActionGroup.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index 1f6c2ab4bb25f..b637ad1fc358c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -276,4 +276,18 @@ + + + + + + + + + + {{amount}} + $grabProductTierPriceInput + + + From 63d8818f8ed7ae112cb758e15f1ca967c10ca9f2 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Tue, 30 Oct 2018 18:25:45 +0200 Subject: [PATCH 031/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Remove redundant js files; - Refactored customer and customer address data providers; --- .../Address/AbstractDefaultAddress.php | 2 +- .../Controller/Adminhtml/Address/Delete.php | 2 +- .../Adminhtml/Address/MassDelete.php | 6 +- .../Controller/Adminhtml/Address/Save.php | 2 +- .../Controller/Adminhtml/Address/Validate.php | 6 +- .../Customer/Model/Address/DataProvider.php | 411 ++---------------- .../Model/AttributeMetadataResolver.php | 238 ++++++++++ .../DataProviderWithDefaultAddresses.php | 398 ++--------------- .../Model/FileUploaderDataResolver.php | 201 +++++++++ .../ui_component/customer_address_form.xml | 4 +- .../web/js/address/default-address-block.js | 17 - .../view/adminhtml/web/js/address/modal.js | 203 --------- .../web/js/form/components/insert-form.js | 164 ------- .../view/base/ui_component/customer_form.xml | 9 +- .../base/web/js/form/components/collection.js | 4 - .../web/js/form/components/collection/item.js | 3 - .../Test/Php/_files/blacklist/strict_type.txt | 2 +- .../config/customerConfig.xml | 2 +- 18 files changed, 524 insertions(+), 1150 deletions(-) create mode 100644 app/code/Magento/Customer/Model/AttributeMetadataResolver.php create mode 100644 app/code/Magento/Customer/Model/FileUploaderDataResolver.php delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js delete mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index a2f9d12282188..75b888bb06675 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -49,7 +49,7 @@ public function __construct( } /** - * Execute action to change customer default address + * Execute action to set customer default billing or shipping address * * @return \Magento\Framework\Controller\Result\Redirect */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 8443c777546f6..1620f343700ed 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -40,7 +40,7 @@ public function __construct( } /** - * Delete action + * Delete customer address action * * @return \Magento\Framework\Controller\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index f022ea36f420d..2ea4b79f78028 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -9,7 +9,6 @@ use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; -use Magento\Backend\Model\View\Result\Redirect; use Magento\Customer\Api\AddressRepositoryInterface; /** @@ -58,7 +57,7 @@ public function __construct( } /** - * Execute action + * Delete specified customer addresses using grid massaction * * @return \Magento\Backend\Model\View\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException|\Exception @@ -69,8 +68,7 @@ public function execute() $collection = $this->filter->getCollection($this->collectionFactory->create()); $collectionSize = $collection->getSize(); - // Get id of the first item from addresses collection for providing it to the ResultRedirect and build a - // proper redirect URL + // Get id of the first item from addresses collection for the ResultRedirect and build a correct redirect URL $customerId = $collection->getFirstItem()->getParentId(); /** @var \Magento\Customer\Model\Address $address */ diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index e1d605a8d0890..9113640112e3b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -79,7 +79,7 @@ public function __construct( } /** - * Execute action to save customer address + * Save customer address action * * @return \Magento\Framework\Controller\Result\Redirect * @throws \Magento\Framework\Exception\LocalizedException diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php index 696bf3099db11..e4583230d5294 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Validate.php @@ -48,7 +48,7 @@ public function __construct( } /** - * AJAX customer validation action + * AJAX customer address validation action * * @return \Magento\Framework\Controller\Result\Json */ @@ -56,7 +56,7 @@ public function execute() { /** @var \Magento\Framework\DataObject $response */ $response = new \Magento\Framework\DataObject(); - $response->setError(0); + $response->setError(false); /** @var \Magento\Framework\DataObject $validatedResponse */ $validatedResponse = $this->validateCustomerAddress($response); @@ -89,7 +89,7 @@ private function validateCustomerAddress(\Magento\Framework\DataObject $response $messages[] = $error; } $response->setMessages($messages); - $response->setError(1); + $response->setError(true); } return $response; diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 7f23deddd89a6..5fd7c884cf6b5 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -1,9 +1,9 @@ 'frontend_input', - 'visible' => 'is_visible', - 'required' => 'is_required', - 'label' => 'frontend_label', - 'sortOrder' => 'sort_order', - 'notice' => 'note', - 'default' => 'default_value', - 'size' => 'multiline_count', - ]; - - /** - * Form element mapping - * - * @var array - */ - private $formElement = [ - 'text' => 'input', - 'hidden' => 'input', - 'boolean' => 'checkbox', - ]; - - /** - * @var EavValidationRules - */ - private $eavValidationRules; - - /** - * @var CountryWithWebsites - */ - private $countryWithWebsiteSource; - /** * Allow to manage attributes, even they are hidden on storefront * @@ -101,26 +44,6 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $context; - /** - * File types allowed for file_uploader UI component - * - * @var array - */ - private $fileUploaderTypes = [ - 'image', - 'file', - ]; - - /** - * @var \Magento\Customer\Model\Config\Share - */ - private $shareConfig; - - /** - * @var FileProcessorFactory - */ - private $fileProcessorFactory; - /** * @var array */ @@ -129,7 +52,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider /** * @var array */ - private $attributesToEliminate = [ + private static $attributesToEliminate = [ 'region', 'vat_is_valid', 'vat_request_date', @@ -137,6 +60,16 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider 'vat_request_success' ]; + /** + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver + */ + private $attributeMetadataResolver; + /** * DataProvider constructor. * @param string $name @@ -145,11 +78,9 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param CollectionFactory $addressCollectionFactory * @param CustomerRepositoryInterface $customerRepository * @param Config $eavConfig - * @param EavValidationRules $eavValidationRules * @param ContextInterface $context - * @param FileProcessorFactory $fileProcessorFactory - * @param \Magento\Customer\Model\Config\Share $shareConfig - * @param CountryWithWebsites $countryWithWebsites + * @param FileUploaderDataResolver $fileUploaderDataResolver + * @param AttributeMetadataResolver $attributeMetadataResolver * @param array $meta * @param array $data * @param bool $allowToShowHiddenAttributes @@ -162,11 +93,9 @@ public function __construct( CollectionFactory $addressCollectionFactory, CustomerRepositoryInterface $customerRepository, Config $eavConfig, - EavValidationRules $eavValidationRules, ContextInterface $context, - FileProcessorFactory $fileProcessorFactory, - \Magento\Customer\Model\Config\Share $shareConfig, - CountryWithWebsites $countryWithWebsites, + FileUploaderDataResolver $fileUploaderDataResolver, + AttributeMetadataResolver $attributeMetadataResolver, array $meta = [], array $data = [], $allowToShowHiddenAttributes = true @@ -175,12 +104,10 @@ public function __construct( $this->collection = $addressCollectionFactory->create(); $this->collection->addAttributeToSelect('*'); $this->customerRepository = $customerRepository; - $this->eavValidationRules = $eavValidationRules; $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->context = $context; - $this->fileProcessorFactory = $fileProcessorFactory; - $this->countryWithWebsiteSource = $countryWithWebsites; - $this->shareConfig = $shareConfig; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->attributeMetadataResolver = $attributeMetadataResolver; $this->meta['general']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer_address') ); @@ -193,7 +120,7 @@ public function __construct( * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function getData() + public function getData(): array { if (null !== $this->loadedData) { return $this->loadedData; @@ -210,7 +137,8 @@ public function getData() $defaultBilling = $customer->getDefaultBilling(); $defaultShipping = $customer->getDefaultShipping(); $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - $this->overrideFileUploaderData($item, $this->loadedData[$addressId]); + + $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); } if (null === $this->loadedData) { @@ -229,15 +157,15 @@ public function getData() * @param string|null $defaultShipping * @return void */ - private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping) + private function prepareAddressData($addressId, array &$addresses, $defaultBilling, $defaultShipping): void { - if (null !== $defaultBilling && $addressId == $defaultBilling) { + if (null !== $defaultBilling && $addressId === $defaultBilling) { $addresses[$addressId]['default_billing'] = '1'; } - if (null !== $defaultShipping && $addressId == $defaultShipping) { + if (null !== $defaultShipping && $addressId === $defaultShipping) { $addresses[$addressId]['default_shipping'] = '1'; } - if (null !== $addresses[$addressId]['street'] && !is_array($addresses[$addressId]['street'])) { + if (null !== $addresses[$addressId]['street'] && !\is_array($addresses[$addressId]['street'])) { $addresses[$addressId]['street'] = explode("\n", $addresses[$addressId]['street']); } } @@ -249,7 +177,7 @@ private function prepareAddressData($addressId, array &$addresses, $defaultBilli * @throws \Magento\Framework\Exception\NoSuchEntityException * @return array */ - private function getDefaultData() + private function getDefaultData(): array { $parentId = $this->context->getRequestParam('parent_id'); $customer = $this->customerRepository->getById($parentId); @@ -262,30 +190,6 @@ private function getDefaultData() return $data; } - /** - * Override file uploader UI component data - * - * Overrides data for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Address $entity - * @param array $entityData - * @return void - */ - private function overrideFileUploaderData($entity, array &$entityData) - { - $attributes = $entity->getAttributes(); - foreach ($attributes as $attribute) { - /** @var Attribute $attribute */ - if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( - $entity->getEntityType(), - $attribute, - $entityData - ); - } - } - } - /** * Get attributes meta * @@ -299,259 +203,22 @@ protected function getAttributesMeta(Type $entityType): array $attributes = $entityType->getAttributeCollection(); /* @var AbstractAttribute $attribute */ foreach ($attributes as $attribute) { - $this->processFrontendInput($attribute, $meta); - - $code = $attribute->getAttributeCode(); - - if (in_array($attribute->getFrontendInput(), $this->bannedInputTypes)) { + if (\in_array($attribute->getFrontendInput(), $this->bannedInputTypes, true)) { continue; } - if (in_array($attribute->getAttributeCode(), $this->attributesToEliminate)) { + if (\in_array($attribute->getAttributeCode(), self::$attributesToEliminate, true)) { continue; } - // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value - foreach ($this->metaProperties as $metaName => $origName) { - $value = $attribute->getDataUsingMethod($origName); - $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; - if ('frontend_input' === $origName) { - $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; - } - } - - if ($attribute->usesSource()) { - if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource - ->getAllOptions(); - } else { - $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); - } - } - - $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); - if (!empty($rules)) { - $meta[$code]['arguments']['data']['config']['validation'] = $rules; - } - - $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; - $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); - - $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + $meta[$attribute->getAttributeCode()] = $this->attributeMetadataResolver->getAttributesMeta( + $attribute, + $entityType, + $this->allowToShowHiddenAttributes, + $this->getRequestFieldName() + ); } + $this->attributeMetadataResolver->processWebsiteMeta($meta); - $this->processWebsiteMeta($meta); return $meta; } - - /** - * Process attributes by frontend input type - * - * @param AttributeInterface $attribute - * @param array $meta - * @return void - */ - private function processFrontendInput(AttributeInterface $attribute, array &$meta) - { - $code = $attribute->getAttributeCode(); - if ($attribute->getFrontendInput() === 'boolean') { - $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; - $meta[$code]['arguments']['data']['config']['valueMap'] = [ - 'true' => '1', - 'false' => '0', - ]; - } - } - - /** - * Detect can we show attribute on specific form or not - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttribute(AbstractAttribute $customerAttribute): bool - { - $userDefined = (bool) $customerAttribute->getIsUserDefined(); - if (!$userDefined) { - return $customerAttribute->getIsVisible(); - } - - $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); - - return ($this->allowToShowHiddenAttributes && $canShowOnForm) || - (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); - } - - /** - * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttributeInForm(AbstractAttribute $customerAttribute): bool - { - $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; - - if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { - return is_array($customerAttribute->getUsedInForms()) && - ( - (in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || - (in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) - ); - } - return is_array($customerAttribute->getUsedInForms()) && - in_array('customer_address_edit', $customerAttribute->getUsedInForms()); - } - - /** - * Override file uploader UI component metadata - * - * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Type $entityType - * @param AbstractAttribute $attribute - * @param array $config - * @return void - */ - private function overrideFileUploaderMetadata( - Type $entityType, - AbstractAttribute $attribute, - array &$config - ) { - if (in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $maxFileSize = self::MAX_FILE_SIZE; - - if (isset($config['validation']['max_file_size'])) { - $maxFileSize = (int)$config['validation']['max_file_size']; - } - - $allowedExtensions = []; - - if (isset($config['validation']['file_extensions'])) { - $allowedExtensions = explode(',', $config['validation']['file_extensions']); - array_walk($allowedExtensions, function (&$value) { - $value = strtolower(trim($value)); - }); - } - - $allowedExtensions = implode(' ', $allowedExtensions); - - $entityTypeCode = $entityType->getEntityTypeCode(); - $url = $this->getFileUploadUrl($entityTypeCode); - - $config = [ - 'formElement' => 'fileUploader', - 'componentType' => 'fileUploader', - 'maxFileSize' => $maxFileSize, - 'allowedExtensions' => $allowedExtensions, - 'uploaderConfig' => [ - 'url' => $url, - ], - 'label' => $this->getMetadataValue($config, 'label'), - 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), - 'required' => $this->getMetadataValue($config, 'required'), - 'visible' => $this->getMetadataValue($config, 'visible'), - 'validation' => $this->getMetadataValue($config, 'validation'), - ]; - } - } - - /** - * Add global scope parameter and filter options to website meta - * - * @param array $meta - * @return void - */ - private function processWebsiteMeta(&$meta) - { - if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { - $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; - } - - if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { - $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ - 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', - 'field' => 'website_ids' - ]; - } - } - - /** - * Retrieve metadata value - * - * @param array $config - * @param string $name - * @param mixed $default - * @return mixed - */ - private function getMetadataValue($config, $name, $default = null) - { - return $config[$name] ?? $default; - } - - /** - * Retrieve URL to file upload - * - * @param string $entityTypeCode - * @return string - */ - private function getFileUploadUrl($entityTypeCode): string - { - switch ($entityTypeCode) { - case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: - $url = 'customer/file/customer_upload'; - break; - - case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: - $url = 'customer/file/address_upload'; - break; - - default: - $url = ''; - break; - } - return $url; - } - - /** - * Retrieve array of values required by file uploader UI component - * - * @param Type $entityType - * @param Attribute $attribute - * @param array $customerData - * @return array - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function getFileUploaderData( - Type $entityType, - Attribute $attribute, - array $customerData - ): array { - $attributeCode = $attribute->getAttributeCode(); - - $file = $customerData[$attributeCode] ?? ''; - - /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->fileProcessorFactory->create([ - 'entityTypeCode' => $entityType->getEntityTypeCode(), - ]); - - if (!empty($file) - && $fileProcessor->isExist($file) - ) { - $stat = $fileProcessor->getStat($file); - $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); - - return [ - [ - 'file' => $file, - 'size' => null !== $stat ? $stat['size'] : 0, - 'url' => $viewUrl ?? '', - 'name' => basename($file), - 'type' => $fileProcessor->getMimeType($file), - ], - ]; - } - - return []; - } } diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php new file mode 100644 index 0000000000000..36ffcb2f5495b --- /dev/null +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -0,0 +1,238 @@ + 'frontend_input', + 'visible' => 'is_visible', + 'required' => 'is_required', + 'label' => 'frontend_label', + 'sortOrder' => 'sort_order', + 'notice' => 'note', + 'default' => 'default_value', + 'size' => 'multiline_count', + ]; + + /** + * Form element mapping + * + * @var array + */ + private static $formElement = [ + 'text' => 'input', + 'hidden' => 'input', + 'boolean' => 'checkbox', + ]; + + /** + * @var CountryWithWebsites + */ + private $countryWithWebsiteSource; + + /** + * @var EavValidationRules + */ + private $eavValidationRules; + + /** + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var ContextInterface + */ + private $context; + + /** + * @var ShareConfig + */ + private $shareConfig; + + /** + * @param CountryWithWebsites $countryWithWebsiteSource + * @param EavValidationRules $eavValidationRules + * @param \Magento\Customer\Model\FileUploaderDataResolver $fileUploaderDataResolver + * @param ContextInterface $context + * @param ShareConfig $shareConfig + */ + public function __construct( + CountryWithWebsites $countryWithWebsiteSource, + EavValidationRules $eavValidationRules, + fileUploaderDataResolver $fileUploaderDataResolver, + ContextInterface $context, + ShareConfig $shareConfig + ) { + $this->countryWithWebsiteSource = $countryWithWebsiteSource; + $this->eavValidationRules = $eavValidationRules; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->context = $context; + $this->shareConfig = $shareConfig; + } + + /** + * Get meta data of the customer or customer address attribute + * + * @param AbstractAttribute $attribute + * @param Type $entityType + * @param bool $allowToShowHiddenAttributes + * @param string $requestFieldName + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function getAttributesMeta( + AbstractAttribute $attribute, + Type $entityType, + bool $allowToShowHiddenAttributes, + string $requestFieldName + ): array { + $meta = $this->modifyBooleanAttributeMeta($attribute); + // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value + foreach (self::$metaProperties as $metaName => $origName) { + $value = $attribute->getDataUsingMethod($origName); + $meta['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; + if ('frontend_input' === $origName) { + $meta['arguments']['data']['config']['formElement'] = self::$formElement[$value] ?? $value; + } + } + + if ($attribute->usesSource()) { + if ($attribute->getAttributeCode() === AddressInterface::COUNTRY_ID) { + $meta['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource + ->getAllOptions(); + } else { + $meta['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); + } + } + + $rules = $this->eavValidationRules->build($attribute, $meta['arguments']['data']['config']); + if (!empty($rules)) { + $meta['arguments']['data']['config']['validation'] = $rules; + } + + $meta['arguments']['data']['config']['componentType'] = Field::NAME; + $meta['arguments']['data']['config']['visible'] = $this->canShowAttribute( + $attribute, + $requestFieldName, + $allowToShowHiddenAttributes + ); + + $this->fileUploaderDataResolver->overrideFileUploaderMetadata( + $entityType, + $attribute, + $meta['arguments']['data']['config'] + ); + + return $meta; + } + + /** + * Detect can we show attribute on specific form or not + * + * @param AbstractAttribute $customerAttribute + * @param string $requestFieldName + * @param bool $allowToShowHiddenAttributes + * @return bool + */ + private function canShowAttribute( + AbstractAttribute $customerAttribute, + string $requestFieldName, + bool $allowToShowHiddenAttributes + ) { + $userDefined = (bool)$customerAttribute->getIsUserDefined(); + if (!$userDefined) { + return $customerAttribute->getIsVisible(); + } + + $canShowOnForm = $this->canShowAttributeInForm($customerAttribute, $requestFieldName); + + return ($allowToShowHiddenAttributes && $canShowOnForm) || + (!$allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); + } + + /** + * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... + * + * @param AbstractAttribute $customerAttribute + * @param string $requestFieldName + * @return bool + */ + private function canShowAttributeInForm(AbstractAttribute $customerAttribute, string $requestFieldName): bool + { + $isRegistration = $this->context->getRequestParam($requestFieldName) === null; + + if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { + return \is_array($customerAttribute->getUsedInForms()) && + ( + (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) && !$isRegistration) + ); + } + return \is_array($customerAttribute->getUsedInForms()) && + \in_array('customer_address_edit', $customerAttribute->getUsedInForms(), true); + } + + /** + * Modify boolean attribute meta data + * + * @param AttributeInterface $attribute + * @return array + */ + private function modifyBooleanAttributeMeta(AttributeInterface $attribute): array + { + $meta = []; + if ($attribute->getFrontendInput() === 'boolean') { + $meta['arguments']['data']['config']['prefer'] = 'toggle'; + $meta['arguments']['data']['config']['valueMap'] = [ + 'true' => '1', + 'false' => '0', + ]; + } + + return $meta; + } + + /** + * Add global scope parameter and filter options to website meta + * + * @param array $meta + * @return void + */ + public function processWebsiteMeta(&$meta): void + { + if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { + $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; + } + + if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { + $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ + 'target' => 'customer_form.customer_form_data_source:data.customer.website_id', + 'field' => 'website_ids' + ]; + } + } +} diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 7ba6484dc3f2b..9131fb2ccdce2 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -6,112 +6,37 @@ */ namespace Magento\Customer\Model\Customer; -use Magento\Customer\Api\AddressMetadataInterface; -use Magento\Customer\Api\CustomerMetadataInterface; -use Magento\Customer\Api\Data\AddressInterface; -use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Model\Address; -use Magento\Customer\Model\Attribute; use Magento\Customer\Model\Customer; -use Magento\Customer\Model\FileProcessor; -use Magento\Customer\Model\FileProcessorFactory; -use Magento\Customer\Model\ResourceModel\Address\Attribute\Source\CountryWithWebsites; use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory as CustomerCollectionFactory; -use Magento\Eav\Api\Data\AttributeInterface; use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Eav\Model\Entity\Type; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Session\SessionManagerInterface; -use Magento\Framework\View\Element\UiComponent\ContextInterface; -use Magento\Ui\Component\Form\Field; -use Magento\Ui\DataProvider\EavValidationRules; +use Magento\Customer\Model\FileUploaderDataResolver; +use Magento\Customer\Model\AttributeMetadataResolver; /** * Refactored version of Magento\Customer\Model\Customer\DataProvider with eliminated usage of addresses collection. - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\AbstractDataProvider { - /** - * Maximum file size allowed for file_uploader UI component - */ - const MAX_FILE_SIZE = 2097152; - /** * @var array */ private $loadedData; - /** - * @var CountryWithWebsites - */ - private $countryWithWebsiteSource; - - /** - * @var \Magento\Customer\Model\Config\Share - */ - private $shareConfig; - - /** - * EAV attribute properties to fetch from meta storage - * @var array - */ - private $metaProperties = [ - 'dataType' => 'frontend_input', - 'visible' => 'is_visible', - 'required' => 'is_required', - 'label' => 'frontend_label', - 'sortOrder' => 'sort_order', - 'notice' => 'note', - 'default' => 'default_value', - 'size' => 'multiline_count', - ]; - - /** - * Form element mapping - * - * @var array - */ - private $formElement = [ - 'text' => 'input', - 'hidden' => 'input', - 'boolean' => 'checkbox', - ]; - - /** - * @var EavValidationRules - */ - private $eavValidationRules; - /** * @var SessionManagerInterface - * @since 100.1.0 */ private $session; - /** - * @var FileProcessorFactory - */ - private $fileProcessorFactory; - - /** - * File types allowed for file_uploader UI component - * - * @var array - */ - private $fileUploaderTypes = [ - 'image', - 'file', - ]; - /** * Customer fields that must be removed * * @var array */ - private $forbiddenCustomerFields = [ + private static $forbiddenCustomerFields = [ 'password_hash', 'rp_token', 'confirmation', @@ -135,54 +60,52 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract private $countryFactory; /** - * DataProviderWithDefaultAddresses constructor. - * + * @var FileUploaderDataResolver + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver + */ + private $attributeMetadataResolver; + + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName - * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig - * @param FileProcessorFactory $fileProcessorFactory - * @param ContextInterface $context * @param \Magento\Directory\Model\CountryFactory $countryFactory * @param SessionManagerInterface $session - * @param \Magento\Customer\Model\Config\Share $shareConfig - * @param CountryWithWebsites $countryWithWebsites + * @param FileUploaderDataResolver $fileUploaderDataResolver + * @param AttributeMetadataResolver $attributeMetadataResolver * @param bool $allowToShowHiddenAttributes * @param array $meta * @param array $data - * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @throws \Magento\Framework\Exception\LocalizedException */ public function __construct( string $name, string $primaryFieldName, string $requestFieldName, - EavValidationRules $eavValidationRules, CustomerCollectionFactory $customerCollectionFactory, Config $eavConfig, - FileProcessorFactory $fileProcessorFactory, - ContextInterface $context, \Magento\Directory\Model\CountryFactory $countryFactory, - \Magento\Framework\Session\SessionManagerInterface $session, - \Magento\Customer\Model\Config\Share $shareConfig, - CountryWithWebsites $countryWithWebsites, + SessionManagerInterface $session, + FileUploaderDataResolver $fileUploaderDataResolver, + AttributeMetadataResolver $attributeMetadataResolver, $allowToShowHiddenAttributes = true, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); - $this->eavValidationRules = $eavValidationRules; $this->collection = $customerCollectionFactory->create(); $this->collection->addAttributeToSelect('*'); - $this->fileProcessorFactory = $fileProcessorFactory; - $this->context = $context ?: ObjectManager::getInstance()->get(ContextInterface::class); $this->allowToShowHiddenAttributes = $allowToShowHiddenAttributes; $this->session = $session; - $this->countryWithWebsiteSource = $countryWithWebsites; - $this->shareConfig = $shareConfig; $this->countryFactory = $countryFactory; + $this->fileUploaderDataResolver = $fileUploaderDataResolver; + $this->attributeMetadataResolver = $attributeMetadataResolver; $this->meta['customer']['children'] = $this->getAttributesMeta( $eavConfig->getEntityType('customer') ); @@ -193,7 +116,7 @@ public function __construct( * * @return array */ - public function getData() + public function getData(): array { if (null !== $this->loadedData) { return $this->loadedData; @@ -203,11 +126,11 @@ public function getData() foreach ($items as $customer) { $result['customer'] = $customer->getData(); - $this->overrideFileUploaderData($customer, $result['customer']); + $this->fileUploaderDataResolver->overrideFileUploaderData($customer, $result['customer']); $result['customer'] = array_diff_key( $result['customer'], - array_flip($this->forbiddenCustomerFields) + array_flip(self::$forbiddenCustomerFields) ); unset($result['address']); @@ -254,73 +177,6 @@ private function prepareDefaultAddress($address): array return $addressData; } - /** - * Override file uploader UI component data - * - * Overrides data for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Customer|Address $entity - * @param array $entityData - * @return void - */ - private function overrideFileUploaderData($entity, array &$entityData) - { - $attributes = $entity->getAttributes(); - foreach ($attributes as $attribute) { - /** @var Attribute $attribute */ - if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( - $entity->getEntityType(), - $attribute, - $entityData - ); - } - } - } - - /** - * Retrieve array of values required by file uploader UI component - * - * @param Type $entityType - * @param Attribute $attribute - * @param array $customerData - * @return array - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - private function getFileUploaderData( - Type $entityType, - Attribute $attribute, - array $customerData - ): array { - $attributeCode = $attribute->getAttributeCode(); - - $file = $customerData[$attributeCode] ?? ''; - - /** @var FileProcessor $fileProcessor */ - $fileProcessor = $this->fileProcessorFactory->create([ - 'entityTypeCode' => $entityType->getEntityTypeCode(), - ]); - - if (!empty($file) - && $fileProcessor->isExist($file) - ) { - $stat = $fileProcessor->getStat($file); - $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); - - return [ - [ - 'file' => $file, - 'size' => null !== $stat ? $stat['size'] : 0, - 'url' => $viewUrl ?? '', - 'name' => basename($file), - 'type' => $fileProcessor->getMimeType($file), - ], - ]; - } - - return []; - } - /** * Get attributes meta * @@ -334,209 +190,15 @@ protected function getAttributesMeta(Type $entityType): array $attributes = $entityType->getAttributeCollection(); /* @var AbstractAttribute $attribute */ foreach ($attributes as $attribute) { - $this->processFrontendInput($attribute, $meta); - - $code = $attribute->getAttributeCode(); - - // use getDataUsingMethod, since some getters are defined and apply additional processing of returning value - foreach ($this->metaProperties as $metaName => $origName) { - $value = $attribute->getDataUsingMethod($origName); - $meta[$code]['arguments']['data']['config'][$metaName] = ($metaName === 'label') ? __($value) : $value; - if ('frontend_input' === $origName) { - $meta[$code]['arguments']['data']['config']['formElement'] = $this->formElement[$value] ?? $value; - } - } - - if ($attribute->usesSource()) { - if ($code == AddressInterface::COUNTRY_ID) { - $meta[$code]['arguments']['data']['config']['options'] = $this->countryWithWebsiteSource - ->getAllOptions(); - } else { - $meta[$code]['arguments']['data']['config']['options'] = $attribute->getSource()->getAllOptions(); - } - } - - $rules = $this->eavValidationRules->build($attribute, $meta[$code]['arguments']['data']['config']); - if (!empty($rules)) { - $meta[$code]['arguments']['data']['config']['validation'] = $rules; - } - - $meta[$code]['arguments']['data']['config']['componentType'] = Field::NAME; - $meta[$code]['arguments']['data']['config']['visible'] = $this->canShowAttribute($attribute); - - $this->overrideFileUploaderMetadata($entityType, $attribute, $meta[$code]['arguments']['data']['config']); + $meta[$attribute->getAttributeCode()] = $this->attributeMetadataResolver->getAttributesMeta( + $attribute, + $entityType, + $this->allowToShowHiddenAttributes, + $this->getRequestFieldName() + ); } + $this->attributeMetadataResolver->processWebsiteMeta($meta); - $this->processWebsiteMeta($meta); return $meta; } - - /** - * Check whether the specific attribute can be shown in form: customer registration, customer edit, etc... - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttributeInForm(AbstractAttribute $customerAttribute) - { - $isRegistration = $this->context->getRequestParam($this->getRequestFieldName()) === null; - - if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { - return \is_array($customerAttribute->getUsedInForms()) && - ( - (\in_array('customer_account_create', $customerAttribute->getUsedInForms()) && $isRegistration) || - (\in_array('customer_account_edit', $customerAttribute->getUsedInForms()) && !$isRegistration) - ); - } - return \is_array($customerAttribute->getUsedInForms()) && - \in_array('customer_address_edit', $customerAttribute->getUsedInForms()); - } - - /** - * Detect can we show attribute on specific form or not - * - * @param AbstractAttribute $customerAttribute - * @return bool - */ - private function canShowAttribute(AbstractAttribute $customerAttribute) - { - $userDefined = (bool) $customerAttribute->getIsUserDefined(); - if (!$userDefined) { - return $customerAttribute->getIsVisible(); - } - - $canShowOnForm = $this->canShowAttributeInForm($customerAttribute); - - return ($this->allowToShowHiddenAttributes && $canShowOnForm) || - (!$this->allowToShowHiddenAttributes && $canShowOnForm && $customerAttribute->getIsVisible()); - } - - /** - * Add global scope parameter and filter options to website meta - * - * @param array $meta - * @return void - */ - private function processWebsiteMeta(&$meta) - { - if (isset($meta[CustomerInterface::WEBSITE_ID]) && $this->shareConfig->isGlobalScope()) { - $meta[CustomerInterface::WEBSITE_ID]['arguments']['data']['config']['isGlobalScope'] = 1; - } - - if (isset($meta[AddressInterface::COUNTRY_ID]) && !$this->shareConfig->isGlobalScope()) { - $meta[AddressInterface::COUNTRY_ID]['arguments']['data']['config']['filterBy'] = [ - 'target' => '${ $.provider }:data.customer.website_id', - 'field' => 'website_ids' - ]; - } - } - - /** - * Override file uploader UI component metadata - * - * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. - * - * @param Type $entityType - * @param AbstractAttribute $attribute - * @param array $config - * @return void - */ - private function overrideFileUploaderMetadata( - Type $entityType, - AbstractAttribute $attribute, - array &$config - ) { - if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes)) { - $maxFileSize = self::MAX_FILE_SIZE; - - if (isset($config['validation']['max_file_size'])) { - $maxFileSize = (int)$config['validation']['max_file_size']; - } - - $allowedExtensions = []; - - if (isset($config['validation']['file_extensions'])) { - $allowedExtensions = explode(',', $config['validation']['file_extensions']); - array_walk($allowedExtensions, function (&$value) { - $value = strtolower(trim($value)); - }); - } - - $allowedExtensions = implode(' ', $allowedExtensions); - - $entityTypeCode = $entityType->getEntityTypeCode(); - $url = $this->getFileUploadUrl($entityTypeCode); - - $config = [ - 'formElement' => 'fileUploader', - 'componentType' => 'fileUploader', - 'maxFileSize' => $maxFileSize, - 'allowedExtensions' => $allowedExtensions, - 'uploaderConfig' => [ - 'url' => $url, - ], - 'label' => $this->getMetadataValue($config, 'label'), - 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), - 'required' => $this->getMetadataValue($config, 'required'), - 'visible' => $this->getMetadataValue($config, 'visible'), - 'validation' => $this->getMetadataValue($config, 'validation'), - ]; - } - } - - /** - * Retrieve metadata value - * - * @param array $config - * @param string $name - * @param mixed $default - * @return mixed - */ - private function getMetadataValue($config, $name, $default = null) - { - return $config[$name] ?? $default; - } - - /** - * Retrieve URL to file upload - * - * @param string $entityTypeCode - * @return string - */ - private function getFileUploadUrl($entityTypeCode): string - { - switch ($entityTypeCode) { - case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: - $url = 'customer/file/customer_upload'; - break; - - case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: - $url = 'customer/file/address_upload'; - break; - - default: - $url = ''; - break; - } - return $url; - } - - /** - * Process attributes by frontend input type - * - * @param AttributeInterface $attribute - * @param array $meta - * @return void - */ - private function processFrontendInput(AttributeInterface $attribute, array &$meta) - { - $code = $attribute->getAttributeCode(); - if ($attribute->getFrontendInput() === 'boolean') { - $meta[$code]['arguments']['data']['config']['prefer'] = 'toggle'; - $meta[$code]['arguments']['data']['config']['valueMap'] = [ - 'true' => '1', - 'false' => '0', - ]; - } - } } diff --git a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php new file mode 100644 index 0000000000000..a132507deaa2f --- /dev/null +++ b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php @@ -0,0 +1,201 @@ +fileProcessorFactory = $fileProcessorFactory; + } + + /** + * Override file uploader UI component data + * + * Overrides data for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Customer|Address $entity + * @param array $entityData + * @return void + */ + public function overrideFileUploaderData($entity, array &$entityData): void + { + $attributes = $entity->getAttributes(); + foreach ($attributes as $attribute) { + /** @var Attribute $attribute */ + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes, true)) { + $entityData[$attribute->getAttributeCode()] = $this->getFileUploaderData( + $entity->getEntityType(), + $attribute, + $entityData + ); + } + } + } + + /** + * Retrieve array of values required by file uploader UI component + * + * @param Type $entityType + * @param Attribute $attribute + * @param array $customerData + * @return array + */ + private function getFileUploaderData( + Type $entityType, + Attribute $attribute, + array $customerData + ): array { + $attributeCode = $attribute->getAttributeCode(); + + $file = $customerData[$attributeCode] ?? ''; + + /** @var FileProcessor $fileProcessor */ + $fileProcessor = $this->fileProcessorFactory->create([ + 'entityTypeCode' => $entityType->getEntityTypeCode(), + ]); + + if (!empty($file) + && $fileProcessor->isExist($file) + ) { + $stat = $fileProcessor->getStat($file); + $viewUrl = $fileProcessor->getViewUrl($file, $attribute->getFrontendInput()); + + return [ + [ + 'file' => $file, + 'size' => null !== $stat ? $stat['size'] : 0, + 'url' => $viewUrl ?? '', + 'name' => basename($file), + 'type' => $fileProcessor->getMimeType($file), + ], + ]; + } + + return []; + } + + /** + * Override file uploader UI component metadata + * + * Overrides metadata for attributes with frontend_input equal to 'image' or 'file'. + * + * @param Type $entityType + * @param AbstractAttribute $attribute + * @param array $config + * @return void + */ + public function overrideFileUploaderMetadata( + Type $entityType, + AbstractAttribute $attribute, + array &$config + ): void { + if (\in_array($attribute->getFrontendInput(), $this->fileUploaderTypes, true)) { + $maxFileSize = self::MAX_FILE_SIZE; + + if (isset($config['validation']['max_file_size'])) { + $maxFileSize = (int)$config['validation']['max_file_size']; + } + + $allowedExtensions = []; + + if (isset($config['validation']['file_extensions'])) { + $allowedExtensions = explode(',', $config['validation']['file_extensions']); + array_walk($allowedExtensions, function (&$value) { + $value = strtolower(trim($value)); + }); + } + + $allowedExtensions = implode(' ', $allowedExtensions); + + $entityTypeCode = $entityType->getEntityTypeCode(); + $url = $this->getFileUploadUrl($entityTypeCode); + + $config = [ + 'formElement' => 'fileUploader', + 'componentType' => 'fileUploader', + 'maxFileSize' => $maxFileSize, + 'allowedExtensions' => $allowedExtensions, + 'uploaderConfig' => [ + 'url' => $url, + ], + 'label' => $this->getMetadataValue($config, 'label'), + 'sortOrder' => $this->getMetadataValue($config, 'sortOrder'), + 'required' => $this->getMetadataValue($config, 'required'), + 'visible' => $this->getMetadataValue($config, 'visible'), + 'validation' => $this->getMetadataValue($config, 'validation'), + ]; + } + } + + /** + * Retrieve metadata value + * + * @param array $config + * @param string $name + * @param mixed $default + * @return mixed + */ + private function getMetadataValue($config, $name, $default = null) + { + return $config[$name] ?? $default; + } + + /** + * Retrieve URL to file upload + * + * @param string $entityTypeCode + * @return string + */ + private function getFileUploadUrl($entityTypeCode): string + { + switch ($entityTypeCode) { + case CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER: + $url = 'customer/file/customer_upload'; + break; + + case AddressMetadataInterface::ENTITY_TYPE_ADDRESS: + $url = 'customer/file/address_upload'; + break; + + default: + $url = ''; + break; + } + return $url; + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 9e432f9f10e0c..1c30d08879eed 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -60,7 +60,7 @@ text - + 0 @@ -83,7 +83,7 @@ - + 0 diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js deleted file mode 100644 index a715aae1ebd96..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address-block.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'jquery', - 'uiElement' -], function($, Component) { - 'use strict'; - - return Component.extend({ - defaults: { - template: 'Magento_Customer/default-address' - } - }); -}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js deleted file mode 100644 index 94701f4c1af99..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/modal.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'jquery', - 'Magento_Ui/js/modal/modal-component', - 'uiRegistry', - 'underscore' -], function ($, Modal, registry, _) { - 'use strict'; - - return Modal.extend({ - defaults: { - modules: { - emailProvider: '${ $.emailProvider }' - } - }, - - /** - * Initializes component. - * - * @returns {Object} Chainable. - */ - initialize: function () { - this._super(); - - // console.log(this.name); - - return this; - }, - - /** - * Open modal. - */ - openModal: function (data) { - debugger; - if (data == null){ - // add - this.setTitle(this.options.title); - this._super(); - } else { - // edit - var addressId = data.uuid; - var address = { - 'city': 'city', - 'company': 'company', - 'country_id': 'country_id', - 'customer_id': 'customer_id', - 'created_at': 'created_at', - 'default_billing': 'default_billing', - 'default_shipping': 'default_shipping', - 'entity_id': 'entity_id', - 'fax': 'fax', - 'firstname': 'firstname', - 'increment_id': 'increment_id', - 'is_active': 'is_active', - 'lastname': 'lastname', - 'middlename': 'middlename', - 'parent_id': 'parent_id', - 'postcode': 'postcode', - 'prefix': 'prefix', - 'region': 'region', - 'region_id': 'region_id', - 'street': [0, 1], - 'suffix': 'suffix', - 'telephone': 'telephone', - 'updated_at': 'updated_at', - 'vat_id': 'vat_id', - 'vat_is_valid': 'vat_is_valid', - 'vat_request_date': 'vat_request_date', - 'vat_request_id': 'vat_request_id', - 'vat_request_success': 'vat_request_success' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; - - _.each(address, function(value, key) { - if (key === 'default_billing' || key === 'default_shipping') { - var defaultValue = source.get('data.address.' + addressId + '.' + value); - // convert boolean to integer - var val = +defaultValue; - source.set(modal + '.' + key, val.toString()); - } else if (key === 'street' && _.isArray(address[key])) { - _.each(address[key], function(element, index) { - source.set(modal + '.' + key + '[' + index + ']', source.get('data.address.' + addressId + '.' + key + '.' + element)); - }); - } else { - source.set(modal + '.' + key, source.get('data.address.' + addressId + '.' + value)); - } - }); - - this.setTitle(this.options.title); - this._super(); - } - }, - - /** - * Close popup modal. - * @public - */ - closeModal: function () { - debugger; - this._clearData(); - this._super(); - }, - - /** - * Clear modal data. - * - * @private - */ - _clearData: function () { - debugger; - var address = { - 'city': '', - 'company': '', - 'country_id': '', - 'default_billing': "0", - 'default_shipping': "0", - 'entity_id': '', - 'firstname': '', - 'is_active': '', - 'lastname': '', - 'middlename': '', - 'postcode': '', - 'prefix': '', - 'region': '', - 'region_id': '', - 'street[0]': '', - 'street[1]': '', - 'suffix': '', - 'telephone': '', - 'vat_id': '' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var modal = 'data.address_listing.address_form.update_customer_address_form_modal'; - - _.each(address, function(value, key) { - source.set(modal + '.' + key, value); - }); - }, - - /** - * Open modal. - */ - save: function () { - debugger; - - var address = { - 'city': 'city', - 'company': 'company', - 'country_id': 'country_id', - 'customer_id': 'customer_id', - 'created_at': 'created_at', - 'default_billing': 'default_billing', - 'default_shipping': 'default_shipping', - 'entity_id': 'entity_id', - 'fax': 'fax', - 'firstname': 'firstname', - 'increment_id': 'increment_id', - 'is_active': 'is_active', - 'lastname': 'lastname', - 'middlename': 'middlename', - 'parent_id': 'parent_id', - 'postcode': 'postcode', - 'prefix': 'prefix', - 'region': 'region', - 'region_id': 'region_id', - 'street': ['street[0]', 'street[1]'], - 'suffix': 'region_id', - 'telephone': 'telephone', - 'updated_at': 'updated_at', - 'vat_id': 'vat_id', - 'vat_is_valid': 'vat_is_valid', - 'vat_request_date': 'vat_request_date', - 'vat_request_id': 'vat_request_id', - 'vat_request_success': 'vat_request_success' - }; - - var source = registry.get('customer_form.customer_form_data_source'); - var formData = source.get('data.address_listing.address_form.update_customer_address_form_modal'); - var entityId = formData.entity_id; - - $.ajax({ - url: this.options.url, - showLoader: true, - data: formData, - type: "POST", - dataType: 'json', - success: function(data) { - console.log('SUCCESS: ', data); - }, - error: function(data) { - console.log('ERROR: ', data); - } - }); - } - }); -}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js deleted file mode 100644 index edfb004654a9b..0000000000000 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -define([ - 'Magento_Ui/js/form/components/insert-form' -], function (Insert) { - 'use strict'; - - return Insert.extend({ - // Should be refactored after form save.!!!!! - // defaults: { - // updateModalProvider: '${ $.parentName }', - // subTitlePrefix: $t('Belongs to '), - // switcherSelector: '.store-switcher', - // toRemove: [], - // // imports: { - // // removeResponseData: '${ $.removeResponseProvider }', - // // modalTitle: '${ $.modalTitleProvider }', - // // modalSubTitle: '${ $.modalSubTitleProvider }', - // // destroyClosedModalContents: '${ $.updateModalProvider }:state' - // // }, - // // listens: { - // // responseData: 'afterUpdate', - // // removeResponseData: 'afterRemove', - // // modalTitle: 'changeModalTitle', - // // modalSubTitle: 'changeModalSubTitle' - // // }, - // modules: { - // updateModal: '${ $.updateModalProvider }', - // removeModal: '${ $.removeModalProvider }', - // upcomingListing: 'index = ${ $.upcomingListingProvider }' - // } - // }, - // - // /** @inheritdoc **/ - // initialize: function () { - // _.bindAll(this, 'onSwitcherSelect'); - // this._super(); - // this.updateModal(this.initSwitcherHandler.bind(this)); - // - // return this; - // }, - // - // initConfig: function (options) { - // debugger; - // return this._super(); - // }, - // - // /** @inheritdoc */ - // destroyInserted: function () { - // if (this.isRendered) { - // _.each(this.toRemove, function (componentName) { - // registry.get(componentName, function (component) { - // if (component.hasOwnProperty('delegate')) { - // component.delegate('destroy'); - // } else { - // component.destroy(); - // } - // }); - // }); - // } - // - // this._super(); - // }, - // - // // /** - // // * Form save callback. - // // * - // // * @param {Object} data - // // */ - // // afterUpdate: function (data) { - // // if (!data.error) { - // // this.updateModal('closeModal'); - // // this.upcomingListing('reload'); - // // } - // // }, - // - // // /** - // // * Form remove callback. - // // * - // // * @param {Object} data - // // */ - // // afterRemove: function (data) { - // // if (!data.error) { - // // this.removeModal('closeModal'); - // // this.afterUpdate(data); - // // } - // // }, - // - // // /** - // // * Change modal title. - // // * - // // * @param {String} title - // // */ - // // changeModalTitle: function (title) { - // // this.updateModal('setTitle', title); - // // }, - // // - // // /** - // // * Change modal sub title. - // // * - // // * @param {String} subTitle - // // */ - // // changeModalSubTitle: function (subTitle) { - // // subTitle = subTitle ? - // // this.subTitlePrefix + this.modalTitle + ' ' + subTitle : - // // ''; - // // - // // this.updateModal('setSubTitle', subTitle); - // // }, - // - // /** - // * Destroy contents of modal when it is closed - // * - // * @param {Boolean} state - // */ - // destroyClosedModalContents: function (state) { - // if (state === false) { - // this.destroyInserted(); - // } - // }, - // - // /** - // * Switcher initialization. - // */ - // initSwitcherHandler: function () { - // var switcherSelector = this.updateModal().rootSelector + ' ' + this.switcherSelector, - // self = this; - // - // $.async(switcherSelector, function (switcher) { - // $(switcher).on('click', 'li a', self.onSwitcherSelect); - // }); - // }, - // - // /** - // * Store switcher selection handler. - // * @param {Object} e - event object. - // */ - // onSwitcherSelect: function (e) { - // var self = this, - // param = $(e.currentTarget).data('param'), - // params = { - // store: 0 - // }; - // - // params[param] = $(e.currentTarget).data('value'); - // - // uiConfirm({ - // content: $t('Please confirm scope switching. All data that hasn\'t been saved will be lost.'), - // actions: { - // - // /** Confirm callback. */ - // confirm: function () { - // self.destroyInserted(); - // params = _.extend(self.previousParams, params); - // self.render(params); - // } - // } - // }); - // } - }); -}); diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 1eb3652628c28..6fc8fcac6099f 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -351,7 +351,7 @@ button - Edit + Edit true ${ $.provider}:data.default_billing_address.entity_id @@ -398,7 +398,7 @@ button - Edit + Edit true ${ $.provider}:data.default_shipping_address.entity_id @@ -428,7 +428,7 @@ - Add New Address + Add New Address ${ $.provider}:data.customer_id @@ -440,9 +440,8 @@ - + - customer_address_edit 1 diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js index dbea61b13e626..96d2a9e83a8f5 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection.js @@ -5,9 +5,6 @@ /** * @api - * @deprecated as customer addresses are handled by ui components. - * This collection component manages rendering address list in Addresses tab of customer. - * Now address list is rendered with ui component listing. */ define([ 'underscore', @@ -49,7 +46,6 @@ define([ * @param {Object} elem - Incoming child. */ initElement: function (elem) { - debugger; this._super(); elem.activate(); diff --git a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js index ae7f375bdca02..045c25ab7911f 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js +++ b/app/code/Magento/Ui/view/base/web/js/form/components/collection/item.js @@ -5,9 +5,6 @@ /** * @api - * @deprecated as customer addresses are handled by ui components. - * This item component renders address list item preview in Addresses tab. - * But now address list item is rendered with ui component in customer form. */ define([ 'underscore', diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt index 5c5c380c4dd33..877583e5b6a29 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/blacklist/strict_type.txt @@ -1 +1 @@ -# Format: or simply \ No newline at end of file +# Format: or simply diff --git a/setup/performance-toolkit/config/customerConfig.xml b/setup/performance-toolkit/config/customerConfig.xml index b77d9f6d4c941..8fd74d7b53885 100644 --- a/setup/performance-toolkit/config/customerConfig.xml +++ b/setup/performance-toolkit/config/customerConfig.xml @@ -6,5 +6,5 @@ */ --> - 5 + 2 From 867fc399768238d7cd084f34295bc750d93fb671 Mon Sep 17 00:00:00 2001 From: Yuliya Labudova Date: Wed, 31 Oct 2018 17:05:51 +0300 Subject: [PATCH 032/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fix static test --- .../Magento/Authorizenet/Model/Directpost.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Authorizenet/Model/Directpost.php b/app/code/Magento/Authorizenet/Model/Directpost.php index c59c44622b8cb..a409251aa76ef 100644 --- a/app/code/Magento/Authorizenet/Model/Directpost.php +++ b/app/code/Magento/Authorizenet/Model/Directpost.php @@ -371,8 +371,7 @@ public function void(\Magento\Payment\Model\InfoInterface $payment) } /** - * Refund the amount - * Need to decode last 4 digits for request. + * Refund the amount need to decode last 4 digits for request. * * @param \Magento\Framework\DataObject|\Magento\Payment\Model\InfoInterface $payment * @param float $amount @@ -630,7 +629,7 @@ protected function fillPaymentByResponse(\Magento\Framework\DataObject $payment) $additionalInformationKeys = explode(',', $this->getValue('paymentInfoKeys')); foreach ($additionalInformationKeys as $paymentInfoKey) { $paymentInfoValue = $response->getDataByKey($paymentInfoKey); - if($paymentInfoValue !== null) { + if ($paymentInfoValue !== null) { $payment->setAdditionalInformation($paymentInfoKey, $paymentInfoValue); } } @@ -690,6 +689,7 @@ protected function matchAmount($amount) /** * Operate with order using information from Authorize.net. + * * Authorize order or authorize and capture it. * * @param \Magento\Sales\Model\Order $order @@ -866,7 +866,7 @@ public function getConfigInterface() * Getter for specified value according to set payment method code * * @param mixed $key - * @param null $storeId + * @param int|string|null|\Magento\Store\Model\Store $storeId * @return mixed */ public function getValue($key, $storeId = null) @@ -930,6 +930,8 @@ public function fetchTransactionInfo(\Magento\Payment\Model\InfoInterface $payme } /** + * Add statuc comment on update. + * * @param \Magento\Sales\Model\Order\Payment $payment * @param \Magento\Framework\DataObject $response * @param string $transactionId @@ -1004,8 +1006,9 @@ protected function getTransactionResponse($transactionId) } /** - * @return \Psr\Log\LoggerInterface + * Get psr logger. * + * @return \Psr\Log\LoggerInterface * @deprecated 100.1.0 */ private function getPsrLogger() @@ -1046,7 +1049,9 @@ private function getOrderIncrementId(): string } /** - * Checks if filter action is Report Only. Transactions that trigger this filter are processed as normal, + * Checks if filter action is Report Only. + * + * Transactions that trigger this filter are processed as normal, * but are also reported in the Merchant Interface as triggering this filter. * * @param string $fdsFilterAction From 3478e785f5a08e6220ff604836cec9199c2f30ba Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Wed, 31 Oct 2018 17:15:41 +0200 Subject: [PATCH 033/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix static tests; --- .../Adminhtml/Edit/Address/CancelButton.php | 1 + .../Adminhtml/Edit/Address/SaveButton.php | 1 + .../Address/AbstractDefaultAddress.php | 4 +- .../Address/DefaultBillingAddress.php | 1 + .../Address/DefaultShippingAddress.php | 1 + .../Controller/Adminhtml/Address/Delete.php | 4 +- .../Adminhtml/Address/MassDelete.php | 10 +- .../Controller/Adminhtml/Address/Save.php | 4 +- .../Controller/Adminhtml/Address/Validate.php | 14 ++- .../Adminhtml/File/Address/Upload.php | 3 +- .../Customer/Model/Address/DataProvider.php | 1 + .../Model/AttributeMetadataResolver.php | 13 +- .../Customer/Model/Customer/DataProvider.php | 14 ++- .../DataProviderWithDefaultAddresses.php | 6 +- .../Model/FileUploaderDataResolver.php | 4 +- .../Model/ResourceModel/Address/Relation.php | 2 - .../Unit/Model/Address/DataProviderTest.php | 62 ++++------ .../ResourceModel/CustomerRepositoryTest.php | 6 - .../Ui/Component/Form/AddressFieldsetTest.php | 2 +- .../Listing/Address/Column/Countries.php | 6 +- .../ui_component/customer_address_form.xml | 2 +- .../web/js/address/default-address.js | 15 ++- app/code/Magento/Ui/Component/Layout/Tabs.php | 115 ++++++++++-------- .../web/css/source/_module.less | 15 +-- 24 files changed, 167 insertions(+), 139 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php index 6270e8073d0e8..d94b956918370 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/CancelButton.php @@ -1,4 +1,5 @@ filter->getCollection($this->collectionFactory->create()); diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 9113640112e3b..8b70263d3f95b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -1,4 +1,5 @@ formFactory->create('customer_address', 'adminhtml_customer_address'); $formData = $addressForm->extractData($this->getRequest()); diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index be1b1aec7b3a3..afa62d2148eb4 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -10,6 +10,7 @@ use Magento\Customer\Api\AddressMetadataInterface; use Magento\Customer\Model\FileUploader; use Magento\Customer\Model\FileUploaderFactory; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; @@ -17,7 +18,7 @@ /** * Uploads files for customer address */ -class Upload extends Action +class Upload extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 5fd7c884cf6b5..1b4bcf94fec15 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -85,6 +85,7 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider * @param array $data * @param bool $allowToShowHiddenAttributes * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( $name, diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php index 36ffcb2f5495b..6b006d7f44e7e 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -19,6 +19,7 @@ /** * Class to build meta data of the customer or customer address attribute + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AttributeMetadataResolver { @@ -188,8 +189,16 @@ private function canShowAttributeInForm(AbstractAttribute $customerAttribute, st if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { return \is_array($customerAttribute->getUsedInForms()) && ( - (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) && $isRegistration) || - (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) && !$isRegistration) + (\in_array( + 'customer_account_create', + $customerAttribute->getUsedInForms(), + true + ) && $isRegistration) || + (\in_array( + 'customer_account_edit', + $customerAttribute->getUsedInForms(), + true + ) && !$isRegistration) ); } return \is_array($customerAttribute->getUsedInForms()) && diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index c834dd26824cd..7b770d20263dc 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -29,6 +29,8 @@ use Magento\Ui\DataProvider\EavValidationRules; /** + * Data provider for customer and customer address data and meta data + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * * @deprecated \Magento\Customer\Model\Address\DataProvider is used instead @@ -148,18 +150,20 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider private $allowToShowHiddenAttributes; /** - * @param string $name - * @param string $primaryFieldName - * @param string $requestFieldName + * DataProvider constructor. + * @param $name + * @param $primaryFieldName + * @param $requestFieldName * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig * @param FilterPool $filterPool - * @param FileProcessorFactory $fileProcessorFactory - * @param ContextInterface $context + * @param FileProcessorFactory|null $fileProcessorFactory * @param array $meta * @param array $data + * @param ContextInterface|null $context * @param bool $allowToShowHiddenAttributes + * @throws \Magento\Framework\Exception\LocalizedException * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index 9131fb2ccdce2..eafa5907efac9 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -42,11 +42,6 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract 'confirmation', ]; - /* - * @var ContextInterface - */ - private $context; - /** * Allow to manage attributes, even they are hidden on storefront * @@ -83,6 +78,7 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract * @param array $meta * @param array $data * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( string $name, diff --git a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php index a132507deaa2f..9dd5084739c74 100644 --- a/app/code/Magento/Customer/Model/FileUploaderDataResolver.php +++ b/app/code/Magento/Customer/Model/FileUploaderDataResolver.php @@ -39,7 +39,9 @@ class FileUploaderDataResolver /** * @param FileProcessorFactory $fileProcessorFactory */ - public function __construct(FileProcessorFactory $fileProcessorFactory) { + public function __construct( + FileProcessorFactory $fileProcessorFactory + ) { $this->fileProcessorFactory = $fileProcessorFactory; } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index cbfebe87812bc..37a633d47f512 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -46,7 +46,6 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() - && !$object->getIsDefaultBilling() ) { $changedAddresses['default_billing'] = null; } @@ -55,7 +54,6 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() - && !$object->getIsDefaultShipping() ) { $changedAddresses['default_shipping'] = null; } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php index 815a47288e370..81266a8934c87 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -7,16 +7,15 @@ namespace Magento\Customer\Test\Unit\Model\Address; use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\AttributeMetadataResolver; +use Magento\Customer\Model\FileUploaderDataResolver; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; use Magento\Customer\Model\ResourceModel\Address\Collection as AddressCollection; use Magento\Eav\Model\Config; use Magento\Eav\Model\Entity\Type; -use Magento\Ui\DataProvider\EavValidationRules; -use Magento\Customer\Model\Attribute as AttributeModel; use Magento\Customer\Api\Data\CustomerInterface; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Customer\Model\Address as AddressModel; -use Magento\Customer\Model\FileProcessorFactory; class DataProviderTest extends \PHPUnit\Framework\TestCase { @@ -45,26 +44,11 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase */ private $eavConfig; - /** - * @var EavValidationRules|\PHPUnit_Framework_MockObject_MockObject - */ - private $eavValidationRules; - /* * @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject */ private $context; - /** - * @var \Magento\Customer\Model\Config\Share|\PHPUnit_Framework_MockObject_MockObject - */ - private $shareConfig; - - /** - * @var FileProcessorFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $fileProcessorFactory; - /** * @var Type|\PHPUnit_Framework_MockObject_MockObject */ @@ -76,9 +60,14 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase private $address; /** - * @var AttributeModel|\PHPUnit_Framework_MockObject_MockObject + * @var FileUploaderDataResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileUploaderDataResolver; + + /** + * @var AttributeMetadataResolver|\PHPUnit_Framework_MockObject_MockObject */ - private $attribute; + private $attributeMetadataResolver; /** * @var \Magento\Customer\Model\Address\DataProvider @@ -88,6 +77,12 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase protected function setUp() { $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->fileUploaderDataResolver = $this->getMockBuilder(FileUploaderDataResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->attributeMetadataResolver = $this->getMockBuilder(AttributeMetadataResolver::class) + ->disableOriginalConstructor() + ->getMock(); $this->addressCollectionFactory = $this->getMockBuilder(CollectionFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) @@ -96,13 +91,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); $this->customerRepository = $this->getMockForAbstractClass(CustomerRepositoryInterface::class); - $this->eavValidationRules = $this->createMock(EavValidationRules::class); $this->context = $this->getMockForAbstractClass(ContextInterface::class); - $this->fileProcessorFactory = $this->getMockBuilder(FileProcessorFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->shareConfig = $this->createMock(\Magento\Customer\Model\Config\Share::class); $this->addressCollectionFactory->expects($this->once()) ->method('create') ->willReturn($this->collection); @@ -122,9 +111,6 @@ protected function setUp() $this->address = $this->getMockBuilder(AddressModel::class) ->disableOriginalConstructor() ->getMock(); - $this->attribute = $this->getMockBuilder(AttributeModel::class) - ->disableOriginalConstructor() - ->getMock(); $this->model = $objectManagerHelper->getObject( \Magento\Customer\Model\Address\DataProvider::class, @@ -135,10 +121,9 @@ protected function setUp() 'addressCollectionFactory' => $this->addressCollectionFactory, 'customerRepository' => $this->customerRepository, 'eavConfig' => $this->eavConfig, - 'eavValidationRules' => $this->eavValidationRules, 'context' => $this->context, - 'fileProcessorFactory' => $this->fileProcessorFactory, - 'shareConfig' => $this->shareConfig, + 'fileUploaderDataResolver' => $this->fileUploaderDataResolver, + 'attributeMetadataResolver' => $this->attributeMetadataResolver, [], [], true @@ -146,7 +131,7 @@ protected function setUp() ); } - public function testGetDefaultData() + public function testGetDefaultData(): void { $expectedData = [ '' => [ @@ -176,7 +161,7 @@ public function testGetDefaultData() $this->assertEquals($expectedData, $this->model->getData()); } - public function testGetData() + public function testGetData(): void { $expectedData = [ '3' => [ @@ -221,12 +206,9 @@ public function testGetData() 'lastname' => 'Doe', 'street' => "42000 Ave W 55 Cedar City\nApt. 33" ]); - $this->address->expects($this->once()) - ->method('getAttributes') - ->willReturn([$this->attribute]); - $this->attribute->expects($this->once()) - ->method('getFrontendInput') - ->willReturn(null); + $this->fileUploaderDataResolver->expects($this->once()) + ->method('overrideFileUploaderData') + ->willReturnSelf(); $this->assertEquals($expectedData, $this->model->getData()); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index 1d262e7549873..034832ce72bfb 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -377,12 +377,6 @@ public function testSaveWithPasswordHash() 'getFirstFailure', 'getLockExpires', ]); - $region = $this->getMockForAbstractClass( - \Magento\Customer\Api\Data\RegionInterface::class, - [], - '', - false - ); $origCustomer = $this->customer; $customerModel = $this->createPartialMock(\Magento\Customer\Model\Customer::class, [ diff --git a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php index 82ce4249bcd85..31a8a1bfacc64 100644 --- a/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php +++ b/app/code/Magento/Customer/Test/Unit/Ui/Component/Form/AddressFieldsetTest.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Ui\Test\Unit\Component\Form; +namespace Magento\Customer\Test\Unit\Ui\Component\Form; use Magento\Customer\Ui\Component\Form\AddressFieldset; use Magento\Framework\View\Element\UiComponent\ContextInterface; diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php index 438a16ec3ba55..d05d5d1c592a7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Countries.php @@ -1,5 +1,9 @@ text - + 0 diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index 3a1500e5dc99e..b4ec734cb4033 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -9,16 +9,23 @@ define([ 'use strict'; return Button.extend({ + defaults: { + entity_id: null, + parent_id: null + }, + + /** + * Initializes component. + * + * @returns {Button} + */ initialize: function () { this._super(); if (!this.parent_id) { this.visible(this.entity_id); } - }, - defaults: { - entity_id: null, - parent_id: null + return this; }, /** diff --git a/app/code/Magento/Ui/Component/Layout/Tabs.php b/app/code/Magento/Ui/Component/Layout/Tabs.php index 02e8979f525ef..f5a9c86977c3c 100644 --- a/app/code/Magento/Ui/Component/Layout/Tabs.php +++ b/app/code/Magento/Ui/Component/Layout/Tabs.php @@ -5,10 +5,8 @@ */ namespace Magento\Ui\Component\Layout; -use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\UiComponent\BlockWrapperInterface; use Magento\Framework\View\Element\UiComponent\DataSourceInterface; -use Magento\Framework\View\Element\UiComponent\LayoutInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; use Magento\Ui\Component\Form\Fieldset; @@ -17,7 +15,7 @@ /** * Class Tabs */ -class Tabs extends \Magento\Framework\View\Layout\Generic implements LayoutInterface +class Tabs extends \Magento\Framework\View\Layout\Generic { /** * @var string @@ -97,54 +95,8 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $name = $childComponent->getName(); $config = $childComponent->getData('config'); $collectedComponents[$name] = true; - if (isset($config['is_collection']) && $config['is_collection'] === true) { - $label = $childComponent->getData('config/label'); - $this->component->getContext()->addComponentDefinition( - 'collection', - [ - 'component' => 'Magento_Ui/js/form/components/collection', - 'extends' => $this->namespace - ] - ); - - /** - * @var UiComponentInterface $childComponent - * @var array $structure - */ - list($childComponent, $structure) = $this->prepareChildComponents($childComponent, $name); - - $childrenStructure = $structure[$name]['children']; - - $structure[$name]['children'] = [ - $name . '_collection' => [ - 'type' => 'collection', - 'config' => [ - 'active' => 1, - 'removeLabel' => __('Remove %1', $label), - 'addLabel' => __('Add New %1', $label), - 'removeMessage' => $childComponent->getData('config/removeMessage'), - 'itemTemplate' => 'item_template', - ], - 'children' => [ - 'item_template' => ['type' => $this->namespace, - 'isTemplate' => true, - 'component' => 'Magento_Ui/js/form/components/collection/item', - 'childType' => 'group', - 'config' => [ - 'label' => __('New %1', $label), - ], - 'children' => $childrenStructure - ] - ] - ] - ]; - } else { - /** - * @var UiComponentInterface $childComponent - * @var array $structure - */ - list($childComponent, $structure) = $this->prepareChildComponents($childComponent, $name); - } + + [$childComponent, $structure] = $this->buildChildComponentStructure($config, $childComponent); $tabComponent = $this->createTabComponent($childComponent, $name); @@ -172,6 +124,67 @@ protected function addChildren(array &$topNode, UiComponentInterface $component, $topNode = $this->structure; } + /** + * Build child components structure of the tab + * + * @param array $config + * @param UiComponentInterface $childComponent + * @return array + */ + private function buildChildComponentStructure(array $config, $childComponent): array + { + $name = $childComponent->getName(); + if (isset($config['is_collection']) && $config['is_collection'] === true) { + $label = $childComponent->getData('config/label'); + $this->component->getContext()->addComponentDefinition( + 'collection', + [ + 'component' => 'Magento_Ui/js/form/components/collection', + 'extends' => $this->namespace + ] + ); + /** + * @var UiComponentInterface $childComponent + * @var array $structure + */ + [$childComponent, $structure] = $this->prepareChildComponents($childComponent, $name); + + $childrenStructure = $structure[$name]['children']; + + $structure[$name]['children'] = [ + $name . '_collection' => [ + 'type' => 'collection', + 'config' => [ + 'active' => 1, + 'removeLabel' => __('Remove %1', $label), + 'addLabel' => __('Add New %1', $label), + 'removeMessage' => $childComponent->getData('config/removeMessage'), + 'itemTemplate' => 'item_template', + ], + 'children' => [ + 'item_template' => ['type' => $this->namespace, + 'isTemplate' => true, + 'component' => 'Magento_Ui/js/form/components/collection/item', + 'childType' => 'group', + 'config' => [ + 'label' => __('New %1', $label), + ], + 'children' => $childrenStructure + ] + ] + ] + ]; + } else { + /** + * @var UiComponentInterface $childComponent + * @var array $structure + */ + [$childComponent, $structure] = $this->prepareChildComponents($childComponent, $name); + } + + return [$childComponent, $structure]; + } + /** * Add wrapped layout block * diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index 8a5fe698eb196..876859ff38d1a 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -3,7 +3,7 @@ // * See COPYING.txt for license details. // */ -.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { +.customer_form_areas_address_address_customer_address_update_modal_update_customer_address_form_loader { .admin__field { .admin__field { .admin__field-label { @@ -15,10 +15,12 @@ .customer-address-form { - *, *:before, *:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; + *, + *:before, + *:after { box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; } address { @@ -26,8 +28,7 @@ } .customer-default-billing-address-content, - .customer-default-shipping-address-content - { + .customer-default-shipping-address-content { float: left; width: 550px; } @@ -52,10 +53,10 @@ } .add-new-address-button { - position: relative; clear: both; float: right; margin-bottom: 30px; + position: relative; } .address-information { From 47251f6b9802a579fadd55146c649c1a2bf04140 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Wed, 31 Oct 2018 10:24:09 -0500 Subject: [PATCH 034/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added the out of stock filter to the grouped product model to replicate frontend behavior --- .../Model/Product/Type/Grouped.php | 14 +++- .../Api/CartItemRepositoryTest.php | 68 +++++++++++++++++ ...oduct_grouped_with_simple_out_of_stock.php | 75 +++++++++++++++++++ ...uped_with_simple_out_of_stock_rollback.php | 34 +++++++++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php create mode 100644 dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 80824d45cb6e5..8844aedcb3d99 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -8,6 +8,8 @@ namespace Magento\GroupedProduct\Model\Product\Type; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\App\ObjectManager; +use Magento\CatalogInventory\Helper\Stock as StockHelper; /** * Grouped product type model @@ -86,6 +88,11 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $msrpData; + /** + * @var \Magento\CatalogInventory\Helper\Stock|null + */ + private $stockHelper; + /** * @param \Magento\Catalog\Model\Product\Option $catalogProductOption * @param \Magento\Eav\Model\Config $eavConfig @@ -102,6 +109,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType * @param \Magento\Framework\App\State $appState * @param \Magento\Msrp\Helper\Data $msrpData * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer + * @param \Magento\CatalogInventory\Helper\Stock|null $stockHelper * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -119,13 +127,15 @@ public function __construct( \Magento\Catalog\Model\Product\Attribute\Source\Status $catalogProductStatus, \Magento\Framework\App\State $appState, \Magento\Msrp\Helper\Data $msrpData, - \Magento\Framework\Serialize\Serializer\Json $serializer = null + \Magento\Framework\Serialize\Serializer\Json $serializer = null, + StockHelper $stockHelper = null ) { $this->productLinks = $catalogProductLink; $this->_storeManager = $storeManager; $this->_catalogProductStatus = $catalogProductStatus; $this->_appState = $appState; $this->msrpData = $msrpData; + $this->stockHelper = $stockHelper ?: ObjectManager::getInstance()->get(StockHelper::class); parent::__construct( $catalogProductOption, $eavConfig, @@ -218,6 +228,8 @@ public function getAssociatedProducts($product) ['in' => $this->getStatusFilters($product)] ); + $this->stockHelper->addIsInStockFilterToCollection($collection); + foreach ($collection as $item) { $associatedProducts[] = $item; } diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php new file mode 100644 index 0000000000000..61f07ac3aa043 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php @@ -0,0 +1,68 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_address_saved.php + * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php + */ + public function testAddGroupedProductToCartThatHasAnOutOfStockItemInTheGroup() + { + $this->_markTestAsRestOnly(); + + /** @var \Magento\Catalog\Model\Product $product */ + $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class)->load('100000003'); + $productSku = $product->getSku(); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); + $quote->load('test_order_1', 'reserved_order_id'); + $cartId = $quote->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items', + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = [ + 'cartItem' => [ + 'sku' => $productSku, + 'qty' => 1, + 'quote_id' => $cartId, + ], + ]; + $this->_webApiCall($serviceInfo, $requestData); + $this->assertTrue($quote->hasProductId('100000001')); + $this->assertFalse($quote->hasProductId('100000002')); + } +} diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php new file mode 100644 index 0000000000000..6ef9b5cd5b0a8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock.php @@ -0,0 +1,75 @@ +get(ProductRepositoryInterface::class); + +$productLinkFactory = Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory::class); +$productConfigs = [ + [ + 'id' => '100000001', + 'stock_config' => ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] + ], + [ + 'id' => '100000002', + 'stock_config' => ['use_config_manage_stock' => 1, 'qty' => 0, 'is_qty_decimal' => 0, 'is_in_stock' => 0] + ] +]; + +foreach ($productConfigs as $productConfig) { + /** @var $product Product */ + $product = Bootstrap::getObjectManager()->create(Product::class); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setId($productConfig['id']) + ->setWebsiteIds([1]) + ->setAttributeSetId(4) + ->setName('Simple ' . $productConfig['id']) + ->setSku('simple_' . $productConfig['id']) + ->setPrice(100) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData($productConfig['stock_config']); + + $linkedProducts[] = $productRepository->save($product); +} + +/** @var $product Product */ +$product = Bootstrap::getObjectManager()->create(Product::class); + +$product->setTypeId(Grouped::TYPE_CODE) + ->setId('100000003') + ->setWebsiteIds([1]) + ->setAttributeSetId(4) + ->setName('Grouped Product') + ->setSku('grouped') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'is_in_stock' => 1]); + +foreach ($linkedProducts as $linkedProduct) { + /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */ + $productLink = $productLinkFactory->create(); + $productLink->setSku($product->getSku()) + ->setLinkType('associated') + ->setLinkedProductSku($linkedProduct->getSku()) + ->setLinkedProductType($linkedProduct->getTypeId()) + ->getExtensionAttributes() + ->setQty(1); + $newLinks[] = $productLink; +} + +$product->setProductLinks($newLinks); + +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php new file mode 100644 index 0000000000000..b81c008cf1ab6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GroupedProduct/_files/product_grouped_with_simple_out_of_stock_rollback.php @@ -0,0 +1,34 @@ +get(\Magento\Framework\Registry::class); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$skuList = ['simple_100000001', 'simple_100000002', 'grouped']; +foreach ($skuList as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + + $stockStatus = $objectManager->create(\Magento\CatalogInventory\Model\Stock\Status::class); + $stockStatus->load($product->getData('entity_id'), 'product_id'); + $stockStatus->delete(); + + $productRepository->delete($product); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From d9f0d55a0fc1310665eef30ad66405af5cac70d1 Mon Sep 17 00:00:00 2001 From: David Grigoryan Date: Wed, 31 Oct 2018 19:42:45 +0400 Subject: [PATCH 035/216] MAGETWO-91639: Tax is added despite customer group changes - Updated automated test --- .../Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index fd5cf8d43d8fb..c44ce895bc825 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + From 5646ab9d0decf6012ba38dc6d8e974d4d0c51330 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 1 Nov 2018 10:01:32 +0200 Subject: [PATCH 036/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix fail of code compiler; --- app/code/Magento/Customer/Model/Customer/DataProvider.php | 7 +++---- app/code/Magento/Customer/Model/Metadata/Form/File.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProvider.php b/app/code/Magento/Customer/Model/Customer/DataProvider.php index 7b770d20263dc..18e78c6bd7baf 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProvider.php +++ b/app/code/Magento/Customer/Model/Customer/DataProvider.php @@ -150,10 +150,9 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider private $allowToShowHiddenAttributes; /** - * DataProvider constructor. - * @param $name - * @param $primaryFieldName - * @param $requestFieldName + * @param string $name + * @param string $primaryFieldName + * @param string $requestFieldName * @param EavValidationRules $eavValidationRules * @param CustomerCollectionFactory $customerCollectionFactory * @param Config $eavConfig diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index b9bec01f9ba7c..3959d404d9f55 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -68,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param array|string $value + * @param null $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder From 39dfb2b5e740a315d2274b9ef695716cc94972d2 Mon Sep 17 00:00:00 2001 From: Alexey Yakimovich Date: Thu, 1 Nov 2018 12:41:22 +0300 Subject: [PATCH 037/216] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Converting base order shipping amount for correct calculation; --- app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 98b854fb07778..e05913bad8735 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -75,10 +75,11 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } $isPartialShippingRefunded = false; + $baseOrderShippingAmount = (float)$order->getBaseShippingAmount(); if ($invoice = $creditmemo->getInvoice()) { //recalculate tax amounts in case if refund shipping value was changed - if ($order->getBaseShippingAmount() && $creditmemo->getBaseShippingAmount() !== null) { - $taxFactor = $creditmemo->getBaseShippingAmount() / $order->getBaseShippingAmount(); + if ($baseOrderShippingAmount && $creditmemo->getBaseShippingAmount() !== null) { + $taxFactor = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; @@ -104,7 +105,6 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } } else { $orderShippingAmount = $order->getShippingAmount(); - $baseOrderShippingAmount = $order->getBaseShippingAmount(); $baseOrderShippingRefundedAmount = $order->getBaseShippingRefunded(); From 530d3f5356b09a2c8d0184a2f2da5d29d3224074 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 1 Nov 2018 11:48:04 +0200 Subject: [PATCH 038/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static tests fix; --- .../Model/AttributeMetadataResolver.php | 14 ++--- .../Customer/Model/Metadata/Form/File.php | 2 +- .../Model/ResourceModel/Address/Relation.php | 56 +++++++++++++------ .../Unit/Model/Address/DataProviderTest.php | 3 + 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php index 6b006d7f44e7e..c22cc9a4f23f4 100644 --- a/app/code/Magento/Customer/Model/AttributeMetadataResolver.php +++ b/app/code/Magento/Customer/Model/AttributeMetadataResolver.php @@ -189,16 +189,10 @@ private function canShowAttributeInForm(AbstractAttribute $customerAttribute, st if ($customerAttribute->getEntityType()->getEntityTypeCode() === 'customer') { return \is_array($customerAttribute->getUsedInForms()) && ( - (\in_array( - 'customer_account_create', - $customerAttribute->getUsedInForms(), - true - ) && $isRegistration) || - (\in_array( - 'customer_account_edit', - $customerAttribute->getUsedInForms(), - true - ) && !$isRegistration) + (\in_array('customer_account_create', $customerAttribute->getUsedInForms(), true) + && $isRegistration) || + (\in_array('customer_account_edit', $customerAttribute->getUsedInForms(), true) + && !$isRegistration) ); } return \is_array($customerAttribute->getUsedInForms()) && diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index 3959d404d9f55..227e85ed98f91 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -68,7 +68,7 @@ class File extends AbstractData * @param \Psr\Log\LoggerInterface $logger * @param \Magento\Customer\Api\Data\AttributeMetadataInterface $attribute * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param null $value + * @param string|array $value * @param string $entityTypeCode * @param bool $isAjax * @param \Magento\Framework\Url\EncoderInterface $urlEncoder diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index 37a633d47f512..a2ba37e7ba1dd 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -7,6 +7,8 @@ */ namespace Magento\Customer\Model\ResourceModel\Address; +use Magento\Customer\Model\Address\AddressModelInterface; +use Magento\Customer\Model\Customer; use Magento\Framework\Model\ResourceModel\Db\VersionControl\RelationInterface; /** @@ -40,23 +42,9 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) */ if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); - $changedAddresses = []; - if ($object->getIsDefaultBilling()) { - $changedAddresses['default_billing'] = $object->getId(); - } elseif ($customer->getDefaultBillingAddress() - && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() - ) { - $changedAddresses['default_billing'] = null; - } - - if ($object->getIsDefaultShipping()) { - $changedAddresses['default_shipping'] = $object->getId(); - } elseif ($customer->getDefaultShippingAddress() - && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() - ) { - $changedAddresses['default_shipping'] = null; - } + $changedAddresses['default_billing'] = $this->getDefaultBillingChangedAddress($object, $customer); + $changedAddresses['default_shipping'] = $this->getDefaultShippingChangedAddress($object, $customer); if ($changedAddresses) { $customer->getResource()->getConnection()->update( @@ -68,6 +56,42 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) } } + /** + * Get default billing changed address + * + * @param AddressModelInterface $object + * @param Customer $customer + * @return int|null + */ + private function getDefaultBillingChangedAddress(AddressModelInterface $object, Customer $customer): ?int + { + if ($object->getIsDefaultBilling()) { + return $object->getId(); + } elseif ($customer->getDefaultBillingAddress() + && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() + ) { + return null; + } + } + + /** + * Get default shipping changed address + * + * @param AddressModelInterface $object + * @param Customer $customer + * @return int|null + */ + private function getDefaultShippingChangedAddress(AddressModelInterface $object, Customer $customer): ?int + { + if ($object->getIsDefaultShipping()) { + return $object->getId(); + } elseif ($customer->getDefaultShippingAddress() + && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() + ) { + return null; + } + } + /** * Checks if address has chosen as default and has had an id * diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php index 81266a8934c87..92a15ac01fafa 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/DataProviderTest.php @@ -17,6 +17,9 @@ use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Customer\Model\Address as AddressModel; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class DataProviderTest extends \PHPUnit\Framework\TestCase { /** From 89e371f3638d26d22df0b44af4a16a8adb0abdef Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 1 Nov 2018 12:12:18 +0200 Subject: [PATCH 039/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static tests fix; --- .../Customer/Model/ResourceModel/Address/Grid/Collection.php | 1 + .../Customer/Test/Unit/Model/Address/DataProviderTest.php | 1 + .../Model/Customer/DataProviderWithDefaultAddressesTest.php | 1 + .../Test/Unit/Ui/Component/Form/AddressFieldsetTest.php | 2 +- app/code/Magento/Ui/Test/Unit/Component/Form/FieldsetTest.php | 2 +- .../Magento/Customer/Controller/Adminhtml/Address/SaveTest.php | 1 + 6 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 8026349563867..09aef78b6cebc 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -1,4 +1,5 @@ Date: Thu, 1 Nov 2018 16:01:43 +0200 Subject: [PATCH 040/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fixing static test --- .../Block/Adminhtml/Order/View/Info/PaymentDetails.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php index 40bd0f293a5fd..fb9c74d2f0ab1 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; use Magento\Framework\Phrase; From 8d9a33db147af98ca918eba5fd00a136f3b7fc04 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen Date: Thu, 1 Nov 2018 16:57:13 +0200 Subject: [PATCH 041/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Fixing static test --- .../Block/Adminhtml/Order/View/Info/PaymentDetails.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php index 40bd0f293a5fd..fb9c74d2f0ab1 100644 --- a/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php +++ b/app/code/Magento/Authorizenet/Block/Adminhtml/Order/View/Info/PaymentDetails.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Authorizenet\Block\Adminhtml\Order\View\Info; use Magento\Framework\Phrase; From 83c4dadf8fc825fbddad9e1361930f38fb37d453 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Thu, 1 Nov 2018 19:05:12 +0200 Subject: [PATCH 042/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Fix address relation model; - Unit tests updated; --- .../Adminhtml/File/Address/Upload.php | 3 +- .../Model/ResourceModel/Address/Relation.php | 45 ++++++++++++------- .../Adminhtml/File/Address/UploadTest.php | 40 +++++++++-------- .../ResourceModel/Address/RelationTest.php | 16 ++++++- 4 files changed, 66 insertions(+), 38 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php index afa62d2148eb4..e9034c8050383 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/File/Address/Upload.php @@ -11,6 +11,7 @@ use Magento\Customer\Model\FileUploader; use Magento\Customer\Model\FileUploaderFactory; use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; use Psr\Log\LoggerInterface; @@ -18,7 +19,7 @@ /** * Uploads files for customer address */ -class Upload extends Action implements HttpGetActionInterface +class Upload extends Action implements HttpGetActionInterface, HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index a2ba37e7ba1dd..a82a814d40772 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -7,7 +7,7 @@ */ namespace Magento\Customer\Model\ResourceModel\Address; -use Magento\Customer\Model\Address\AddressModelInterface; +use Magento\Customer\Model\Address; use Magento\Customer\Model\Customer; use Magento\Framework\Model\ResourceModel\Db\VersionControl\RelationInterface; @@ -38,13 +38,14 @@ public function __construct(\Magento\Customer\Model\CustomerFactory $customerFac public function processRelation(\Magento\Framework\Model\AbstractModel $object) { /** - * @var $object \Magento\Customer\Model\Address + * @var $object Address */ if (!$object->getIsCustomerSaveTransaction() && $object->getId()) { $customer = $this->customerFactory->create()->load($object->getCustomerId()); - $changedAddresses['default_billing'] = $this->getDefaultBillingChangedAddress($object, $customer); - $changedAddresses['default_shipping'] = $this->getDefaultShippingChangedAddress($object, $customer); + $changedAddresses = []; + $changedAddresses = $this->getDefaultBillingChangedAddress($object, $customer, $changedAddresses); + $changedAddresses = $this->getDefaultShippingChangedAddress($object, $customer, $changedAddresses); if ($changedAddresses) { $customer->getResource()->getConnection()->update( @@ -59,37 +60,49 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) /** * Get default billing changed address * - * @param AddressModelInterface $object + * @param Address $object * @param Customer $customer - * @return int|null + * @param array $changedAddresses + * @return array */ - private function getDefaultBillingChangedAddress(AddressModelInterface $object, Customer $customer): ?int - { + private function getDefaultBillingChangedAddress( + Address $object, + Customer $customer, + array $changedAddresses + ): array { if ($object->getIsDefaultBilling()) { - return $object->getId(); + $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() ) { - return null; + $changedAddresses['default_billing'] = null; } + + return $changedAddresses; } /** * Get default shipping changed address * - * @param AddressModelInterface $object + * @param Address $object * @param Customer $customer - * @return int|null + * @param array $changedAddresses + * @return array */ - private function getDefaultShippingChangedAddress(AddressModelInterface $object, Customer $customer): ?int - { + private function getDefaultShippingChangedAddress( + Address $object, + Customer $customer, + array $changedAddresses + ): array { if ($object->getIsDefaultShipping()) { - return $object->getId(); + $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() ) { - return null; + $changedAddresses['default_shipping'] = null; } + + return $changedAddresses; } /** diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php index 20177ab0b0db6..8f8ed0e37a46b 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/File/Address/UploadTest.php @@ -70,7 +70,8 @@ protected function setUp() $this->context, $this->fileUploaderFactory, $this->addressMetadataService, - $this->logger + $this->logger, + 'address' ); } @@ -104,27 +105,27 @@ public function testExecuteEmptyFiles() public function testExecute() { - $attributeCode = 'attribute_code'; + $attributeCode = 'file_address_attribute'; + $resultFileSize = 20000; + $resultFileName = 'text.txt'; + $resultType = 'text/plain'; $_FILES = [ - 'address' => [ - 'name' => [ - 'new_0' => [ - $attributeCode => 'filename', - ], - ], + $attributeCode => [ + 'name' => $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize ], ]; - $resultFileName = '/filename.ext1'; $resultFilePath = 'filepath'; $resultFileUrl = 'viewFileUrl'; $result = [ 'name' => $resultFileName, - 'file' => $resultFileName, - 'path' => $resultFilePath, - 'tmp_name' => $resultFilePath . $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize, + 'tmp_name' => $resultFilePath . '/' . $resultFileName, 'url' => $resultFileUrl, ]; @@ -173,15 +174,16 @@ public function testExecute() public function testExecuteWithErrors() { - $attributeCode = 'attribute_code'; + $attributeCode = 'file_address_attribute'; + $resultFileSize = 20000; + $resultFileName = 'text.txt'; + $resultType = 'text/plain'; $_FILES = [ - 'address' => [ - 'name' => [ - 'new_0' => [ - $attributeCode => 'filename', - ], - ], + $attributeCode => [ + 'name' => $resultFileName, + 'type' => $resultType, + 'size' => $resultFileSize ], ]; diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php index e81637cfb23b2..319179c5e279a 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Address/RelationTest.php @@ -6,6 +6,7 @@ namespace Magento\Customer\Test\Unit\Model\ResourceModel\Address; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Customer\Model\Address; /** * Class AddressTest @@ -40,7 +41,7 @@ protected function setUp() */ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShipping) { - $addressModel = $this->createPartialMock(\Magento\Framework\Model\AbstractModel::class, [ + $addressModel = $this->createPartialMock(Address::class, [ '__wakeup', 'getId', 'getEntityTypeId', @@ -55,7 +56,17 @@ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShi ]); $customerModel = $this->createPartialMock( \Magento\Customer\Model\Customer::class, - ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load', 'getResource', 'getId'] + [ + '__wakeup', + 'setDefaultBilling', + 'setDefaultShipping', + 'save', + 'load', + 'getResource', + 'getId', + 'getDefaultShippingAddress', + 'getDefaultBillingAddress' + ] ); $customerResource = $this->getMockForAbstractClass( \Magento\Framework\Model\ResourceModel\Db\AbstractDb::class, @@ -88,6 +99,7 @@ public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShi $this->customerFactoryMock->expects($this->any()) ->method('create') ->willReturn($customerModel); + if ($addressId && ($isDefaultBilling || $isDefaultShipping)) { $customerId = 1; $customerResource->expects($this->exactly(2))->method('getConnection')->willReturn($connectionMock); From fc5eb486c48c3c6fd709d2a042b101e0bf32c976 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov Date: Fri, 2 Nov 2018 10:39:49 +0200 Subject: [PATCH 043/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Index in db_schema.xml fixed --- app/code/Magento/Customer/etc/db_schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 7e0b911e26184..7cf4c5be641e8 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -120,8 +120,8 @@ - - + + From 8b921165cc562d5fd8fafb0126aea66080eeb8ef Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina Date: Fri, 2 Nov 2018 12:44:03 +0300 Subject: [PATCH 044/216] MAGETWO-91526: Authorize.net Direct Post does not show credit card information - Remove atomation test --- .../Test/Mftf/Data/AuthorizenetData.xml | 95 ------------------- .../Mftf/Metadata/authorize-config-meta.xml | 79 --------------- .../AuthorizenetConfiguraionSection.xml | 19 ---- .../AuthorizenetCreditCardInformationTest.xml | 81 ---------------- 4 files changed, 274 deletions(-) delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml delete mode 100644 app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml b/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml deleted file mode 100644 index c4f59ba03bf22..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Data/AuthorizenetData.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - Active - LoginId - TransactionKey - TransMD5 - TestMode - CVVVerification - CGI_UTL - CGI_URL_TD - Debug - - - 1 - - - 4By5Q8m6 - - - 9pygB4X4n783TJbw - - - Md5Hash - - - 0 - - - 1 - - - https://test.authorize.net/gateway/transact.dll - - - https://apitest.authorize.net/xml/v1/request.api - - - 1 - - - - DefaultActive - DefaultTransactionKey - DefaultTransMD5 - DefaultTestMode - DefaultCVVVerification - DefaultCGI_UTL - DefaultCGI_URL_TD - DefaultDebugMode - - - 0 - - - 0 - - - - - - - - - - - - 1 - - - 0 - - - https://secure.authorize.net/gateway/transact.dll - - - https://api2.authorize.net/xml/v1/request.api - - - - DisableConfig - - - - 0 - - diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml b/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml deleted file mode 100644 index ca9bbdad00870..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Metadata/authorize-config-meta.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - integer - - - string - - - string - - - string - - - string - - - string - - - string - - - string - - - string - - - - - - - - - - - - - integer - - - - - integer - - - - - integer - - - - - integer - - - - - integer - - - - - - - diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml b/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml deleted file mode 100644 index 5d4f6c3f9819a..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Section/AuthorizenetConfiguraionSection.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - -
- - - - - - - -
-
diff --git a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml b/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml deleted file mode 100644 index b5d0b6079bb8b..0000000000000 --- a/app/code/Magento/Authorizenet/Test/Mftf/Test/AuthorizenetCreditCardInformationTest.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - <description value="Checking credit card information of Authorize.net Direct Post"/> - <severity value="MAJOR"/> - <testCaseId value="MAGETWO-91526"/> - <group value="Authorizenet"/> - </annotations> - - <before> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="SimpleProduct" stepKey="createProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - <createData entity="Simple_US_Customer_NY" stepKey="createCustomer"/> - <createData stepKey="setConfig" entity="AuthorizenetConfig"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> - <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> - </before> - <after> - <actionGroup ref="logout" stepKey="logout"/> - <deleteData createDataKey="createCategory" stepKey="deleteProduct"/> - <deleteData createDataKey="createProduct" stepKey="deleteCategory"/> - <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> - <createData stepKey="setDefaultConfig" entity="AuthorizenetDefaultConfig"/> - <createData stepKey="DisableConfigValues" entity="DisableAuthorizenetConfig"/> - </after> - <!--Create new order--> - <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="CreateNewOrder"> - <argument name="customer" value="Simple_US_Customer_NY"/> - </actionGroup> - <!--Add product to order--> - <click selector="{{OrdersGridSection.addProducts}}" stepKey="clickToAddProduct"/> - <waitForPageLoad stepKey="waitForProductsOpened"/> - <click selector="{{OrdersGridSection.selectProduct($$createProduct.name$$)}}" stepKey="selectProduct"/> - <click stepKey="addProductsToOrder" selector="{{OrdersGridSection.addProductsToOrder}}"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - <!--Select shipping method--> - <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShipping"/> - <!--Fill Card data and submit order--> - <click selector="{{AuthorizenetConfigurationSection.paymentMethod}}" stepKey="clickToSetPaymentMethod"/> - <selectOption selector="{{AuthorizenetConfigurationSection.cardType}}" userInput="Visa" stepKey="SelectCreditCard"/> - <fillField selector="{{AuthorizenetConfigurationSection.cardNumber}}" userInput="4111111111111111" stepKey="fillCardNumber"/> - <selectOption selector="{{AuthorizenetConfigurationSection.month}}" userInput="01 - January" stepKey="SelectMonth"/> - <click selector="{{AuthorizenetConfigurationSection.year}}" stepKey="clickYear"/> - <waitForElementVisible selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="waitForDropDownMenuAppeared"/> - <click selector="{{AuthorizenetConfigurationSection.afterTwoYear}}" stepKey="selectYear"/> - <fillField selector="{{AuthorizenetConfigurationSection.verificationNumber}}" userInput="123" stepKey="fillVerificationNumber"/> - <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="SubmitOrder"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <!--Get order ID and open order page--> - <see userinput="You created the order." stepKey="verifyOrderCreated"/> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId"/> - <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> - <argument name="orderId" value="$getOrderId"/> - </actionGroup> - <click selector="{{AdminDataGridTableSection.rowViewAction('1')}}" stepKey="clickCreatedOrderInGrid"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <!--Verify required data--> - <see userinput="Credit Card Direct Post (Authorize.net)" stepKey="checkPaymentMethod"/> - <see userinput="Credit Card Type: MasterCard" stepKey="checkCardType"/> - <see userinput="Credit Card Number: XXXX1111" stepKey="checkCardCode"/> - <see userinput="AVS Response Code:" stepKey="checkAVSResponseCode"/> - <see userinput="Processor Authentication Code:" stepKey="checkProcessorAuthorizationCode"/> - <see userinput="Processor Response Text:" stepKey="checkProcessorResponseText"/> - <see userinput="CVV2 Response Code:" stepKey="checkCVVResponseCode"/> - <see userinput="The order was placed using USD." stepKey="checkCurrency"/> - </test> -</tests> From 63cbe3b36a46442a53fa13db27e039aed318ebc9 Mon Sep 17 00:00:00 2001 From: Oksana_Kremen <Oksana_Kremen@epam.com> Date: Fri, 2 Nov 2018 13:48:11 +0200 Subject: [PATCH 045/216] MAGETWO-91639: Tax is added despite customer group changes - Fixing integrity test --- app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php index 303c95b965b98..03b19c6e661a9 100644 --- a/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php +++ b/app/code/Magento/Quote/Plugin/RecollectOnGroupChange.php @@ -10,6 +10,7 @@ use Magento\Quote\Api\CartRepositoryInterface; use Magento\Customer\Model\ResourceModel\Customer as CustomerResource; use Magento\Customer\Model\Customer; +use Magento\Framework\Model\AbstractModel; /** * Recollect quote totals after change customer group @@ -35,13 +36,14 @@ public function __construct( * * @param CustomerResource $subject * @param CustomerResource $result - * @param Customer $customer + * @param AbstractModel $customer * @return CustomerResource * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterSave(CustomerResource $subject, CustomerResource $result, Customer $customer) + public function afterSave(CustomerResource $subject, CustomerResource $result, AbstractModel $customer) { + /** @var Customer $customer */ if ($customer->getOrigData('group_id') !== null && $customer->getOrigData('group_id') != $customer->getGroupId() ) { From 57e59d8044cca1d85873ecde5d6a00660f4ffb31 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Fri, 2 Nov 2018 15:20:27 +0200 Subject: [PATCH 046/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Default addresses changes --- .../Model/Customer/DataProviderWithDefaultAddresses.php | 4 ++-- .../Magento/Customer/Model/ResourceModel/Address/Relation.php | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php index eafa5907efac9..30edafe3d504c 100644 --- a/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php +++ b/app/code/Magento/Customer/Model/Customer/DataProviderWithDefaultAddresses.php @@ -24,7 +24,7 @@ class DataProviderWithDefaultAddresses extends \Magento\Ui\DataProvider\Abstract /** * @var array */ - private $loadedData; + private $loadedData = []; /** * @var SessionManagerInterface @@ -114,7 +114,7 @@ public function __construct( */ public function getData(): array { - if (null !== $this->loadedData) { + if (!empty($this->loadedData)) { return $this->loadedData; } $items = $this->collection->getItems(); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php index a82a814d40772..ae342a1b10dd8 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Relation.php @@ -73,6 +73,7 @@ private function getDefaultBillingChangedAddress( if ($object->getIsDefaultBilling()) { $changedAddresses['default_billing'] = $object->getId(); } elseif ($customer->getDefaultBillingAddress() + && $object->getIsDefaultBilling() === false && (int)$customer->getDefaultBillingAddress()->getId() === (int)$object->getId() ) { $changedAddresses['default_billing'] = null; @@ -97,6 +98,7 @@ private function getDefaultShippingChangedAddress( if ($object->getIsDefaultShipping()) { $changedAddresses['default_shipping'] = $object->getId(); } elseif ($customer->getDefaultShippingAddress() + && $object->getIsDefaultShipping() === false && (int)$customer->getDefaultShippingAddress()->getId() === (int)$object->getId() ) { $changedAddresses['default_shipping'] = null; From 43e2c4dae51a62e169eed7ae6761f565d6780692 Mon Sep 17 00:00:00 2001 From: StasKozar <staskozar.91@gmail.com> Date: Fri, 2 Nov 2018 17:31:24 +0200 Subject: [PATCH 047/216] magento/magento2#18990: Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address --- .../Checkout/Test/Mftf/Data/CountryData.xml | 22 ++++++++ ...frontCustomerCheckoutWithoutRegionTest.xml | 55 +++++++++++++++++++ .../view/frontend/web/js/view/shipping.js | 15 ++++- .../GeneralConfigurationActionGroup.xml | 13 +++++ .../Test/Mftf/Section/GeneralSection.xml | 5 ++ .../Customer/Test/Mftf/Data/CustomerData.xml | 13 +++++ 6 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml b/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml index 26bc6ff641a9c..dc82932ec5ca7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Data/CountryData.xml @@ -13,4 +13,26 @@ <item>Bahamas</item> </array> </entity> + <entity name="DefaultCountriesWithRequiredRegions" type="countryArray"> + <array key="country"> + <item>Australia</item> + <item>Brazil</item> + <item>Canada</item> + <item>Croatia</item> + <item>Estonia</item> + <item>India</item> + <item>Latvia</item> + <item>Lithuania</item> + <item>Romania</item> + <item>Spain</item> + <item>Switzerland</item> + <item>United States</item> + <item>Australia</item> + </array> + </entity> + <entity name="CustomCountryWithRequiredRegion" type="countryArray"> + <array key="country"> + <item>United Kingdom</item> + </array> + </entity> </entities> \ No newline at end of file diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml new file mode 100644 index 0000000000000..0cc0dcf38e312 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutWithoutRegionTest.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCustomerCheckoutWithoutRegionTest"> + <annotations> + <features value="Checkout"/> + <stories value="Checkout via the Admin"/> + <title value="Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address"/> + <description value="Shouldn't be able to place an order as a customer without state if it's required."/> + <severity value="CRITICAL"/> + <testCaseId value="#"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="Simple_GB_Customer" stepKey="createCustomer"/> + <actionGroup stepKey="loginToAdminPanel" ref="LoginAsAdmin"/> + <actionGroup ref="SelectCountriesWithRequiredRegion" stepKey="setCustomCountryWithRequiredRegion"> + <argument name="countries" value="CustomCountryWithRequiredRegion"/> + </actionGroup> + </before> + <after> + <actionGroup ref="SelectCountriesWithRequiredRegion" stepKey="setDefaultCountriesWithRequiredRegion"> + <argument name="countries" value="DefaultCountriesWithRequiredRegions"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + </after> + + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$createCustomer$$" /> + </actionGroup> + + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="navigateToCheckoutPage"/> + + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNextButton"/> + <see selector="{{StorefrontMessagesSection.error}}" userInput='Please specify a regionId in shipping address.' stepKey="seeErrorMessages"/> + </test> +</tests> diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 395d15bc02f36..6ac805f72f78d 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -265,7 +265,12 @@ define([ addressData, loginFormSelector = 'form[data-role=email-with-possible-login]', emailValidationResult = customer.isLoggedIn(), - field; + field, + countryIndexedOptions = registry.get( + this.parentName + '.shippingAddress.shipping-address-fieldset.country_id' + ).indexedOptions, + option = countryIndexedOptions[quote.shippingAddress().countryId], + messageContainer = registry.get('checkout.errors').messageContainer; if (!quote.shippingMethod()) { this.errorValidationMessage( @@ -318,6 +323,14 @@ define([ shippingAddress['save_in_address_book'] = 1; } selectShippingAddress(shippingAddress); + } else if (customer.isLoggedIn() + && option + && option['is_region_required'] + && !quote.shippingAddress().region + ) { + messageContainer.addErrorMessage({message: $t('Please specify a regionId in shipping address.')}); + + return false; } if (!emailValidationResult) { diff --git a/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml b/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml index fca48dfb49cfb..f05cf5be3448e 100644 --- a/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml +++ b/app/code/Magento/Config/Test/Mftf/ActionGroup/GeneralConfigurationActionGroup.xml @@ -37,4 +37,17 @@ <click selector="#save" stepKey="saveConfig"/> <waitForPageLoad stepKey="waitForSavingConfig"/> </actionGroup> + + <actionGroup name="SelectCountriesWithRequiredRegion"> + <arguments> + <argument name="countries" type="countryArray"/> + </arguments> + <amOnPage url="{{AdminConfigGeneralPage.url}}" stepKey="navigateToAdminConfigGeneralPage"/> + <conditionalClick selector="{{StateOptionsSection.stateOptions}}" dependentSelector="{{StateOptionsSection.countriesWithRequiredRegions}}" visible="false" stepKey="expandStateOptionsTab" /> + <waitForAjaxLoad stepKey="waitForAjax"/> + <scrollTo selector="{{StateOptionsSection.countriesWithRequiredRegions}}" stepKey="scrollToForm"/> + <selectOption selector="{{StateOptionsSection.countriesWithRequiredRegions}}" parameterArray="[{{countries.country}}]" stepKey="selectCountriesWithRequiredRegion"/> + <click selector="#save" stepKey="saveConfig"/> + <waitForPageLoad stepKey="waitForSavingConfig"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml index 88532dc091f45..66b40f74d8e98 100644 --- a/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml +++ b/app/code/Magento/Config/Test/Mftf/Section/GeneralSection.xml @@ -38,4 +38,9 @@ <element name="countryOptionsOpen" type="button" selector="#general_country-head.open"/> <element name="topDestinations" type="select" selector="#general_country_destinations"/> </section> + <section name="StateOptionsSection"> + <element name="stateOptions" type="button" selector="#general_region-head"/> + <element name="countriesWithRequiredRegions" type="select" selector="#general_region_state_required"/> + <element name="allowToChooseState" type="select" selector="general_region_display_all"/> + </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml index 6f5ade53e6790..a61871105a5f3 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/CustomerData.xml @@ -102,4 +102,17 @@ <data key="website_id">0</data> <requiredEntity type="address">US_Address_CA</requiredEntity> </entity> + <entity name="Simple_GB_Customer" type="customer"> + <data key="group_id">0</data> + <data key="default_billing">true</data> + <data key="default_shipping">true</data> + <data key="email" unique="prefix">Jane.Doe@example.com</data> + <data key="firstname">Jane</data> + <data key="lastname">Doe</data> + <data key="fullname">Jane Doe</data> + <data key="password">pwdTest123!</data> + <data key="store_id">0</data> + <data key="website_id">0</data> + <requiredEntity type="address">UK_Not_Default_Address</requiredEntity> + </entity> </entities> From b9367a6bab6272cc4efada12370181aaf19fa9d7 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Mon, 5 Nov 2018 10:31:23 -0600 Subject: [PATCH 048/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Fixed namespace --- .../Magento/GroupedProduct/Api/CartItemRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php index 61f07ac3aa043..602493481449f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/CartItemRepositoryTest.php @@ -4,7 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\GroupedProduce\Api; +namespace Magento\GroupedProduct\Api; use Magento\Catalog\Model\CustomOptions\CustomOptionProcessor; use Magento\Framework\Webapi\Rest\Request; From 3785225428b54e81f0b6a09e0528af0978354044 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Mon, 5 Nov 2018 18:33:04 +0200 Subject: [PATCH 049/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Static fixes; --- .../adminhtml/web/js/address/default-address.js | 16 ++++++++-------- .../Magento_Customer/web/css/source/_module.less | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index b4ec734cb4033..530df8544c841 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -10,8 +10,8 @@ define([ return Button.extend({ defaults: { - entity_id: null, - parent_id: null + entityId: null, + parentId: null }, /** @@ -21,8 +21,8 @@ define([ */ initialize: function () { this._super(); - if (!this.parent_id) { - this.visible(this.entity_id); + if (!this.parentId) { + this.visible(this.entityId); } return this; @@ -36,12 +36,12 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entity_id = this.entity_id; - action.params[0].parent_id = this.parent_id; + action.params[0].entityId = this.entityId; + action.params[0].parentId = this.parentId; } else { action.params = [{ - entity_id: this.entity_id, - parent_id: this.parent_id + entityId: this.entityId, + parentId: this.parentId }]; } diff --git a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less index 876859ff38d1a..7cb02b61fdbd8 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_Customer/web/css/source/_module.less @@ -16,8 +16,8 @@ .customer-address-form { *, - *:before, - *:after { + *:after, + *:before { box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; From 577b17576161edc6a3587d4b93a66fcac60f91a7 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi <mankivsk@adobe.com> Date: Mon, 5 Nov 2018 10:50:32 -0600 Subject: [PATCH 050/216] ENGCOM-3354: Cancel expired orders using OrderManagementInterface #18832 - Fixed docblock --- app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php index 80370c21d4d7b..999bb1786cf83 100644 --- a/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php +++ b/app/code/Magento/Sales/Model/CronJob/CleanExpiredOrders.php @@ -13,6 +13,9 @@ use Magento\Store\Model\StoresConfig; use Magento\Sales\Model\Order; +/** + * Class that provides functionality of cleaning expired quotes by cron + */ class CleanExpiredOrders { /** From 965f838c0e993c8a588f22cc5edc2db55f936a44 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Tue, 6 Nov 2018 11:45:36 +0200 Subject: [PATCH 051/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Ability to save addresses through CustomerRepository rolled back - Integration tests fixes --- .../ResourceModel/CustomerRepository.php | 57 +++- .../Customer/etc/db_schema_whitelist.json | 3 +- .../ui_component/customer_address_listing.xml | 29 +- .../view/base/ui_component/customer_form.xml | 9 +- .../Controller/Adminhtml/Address/SaveTest.php | 36 ++- .../Controller/Adminhtml/IndexTest.php | 275 +----------------- 6 files changed, 106 insertions(+), 303 deletions(-) diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 5d88cd92c1730..16c650be15b61 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -170,18 +170,22 @@ public function save(CustomerInterface $customer, $passwordHash = null) /** @var NewOperation|null $delegatedNewOperation */ $delegatedNewOperation = !$customer->getId() ? $this->delegatedStorage->consumeNewOperation() : null; $prevCustomerData = null; + $prevCustomerDataArr = null; if ($customer->getId()) { $prevCustomerData = $this->getById($customer->getId()); + $prevCustomerDataArr = $prevCustomerData->__toArray(); } - + /** @var $customer \Magento\Customer\Model\Data\Customer */ + $customerArr = $customer->__toArray(); $customer = $this->imageProcessor->save( $customer, CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER, $prevCustomerData ); - - /** @var array $customerData */ + $origAddresses = $customer->getAddresses(); + $customer->setAddresses([]); $customerData = $this->extensibleDataObjectConverter->toNestedArray($customer, [], CustomerInterface::class); + $customer->setAddresses($origAddresses); /** @var Customer $customerModel */ $customerModel = $this->customerFactory->create(['data' => $customerData]); //Model's actual ID field maybe different than "id" so "id" field from $customerData may be ignored. @@ -190,16 +194,61 @@ public function save(CustomerInterface $customer, $passwordHash = null) if ($storeId === null) { $customerModel->setStoreId($this->storeManager->getStore()->getId()); } + // Need to use attribute set or future updates can cause data loss + if (!$customerModel->getAttributeSetId()) { + $customerModel->setAttributeSetId(CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER); + } $this->populateCustomerWithSecureData($customerModel, $passwordHash); // If customer email was changed, reset RpToken info if ($prevCustomerData && $prevCustomerData->getEmail() !== $customerModel->getEmail()) { $customerModel->setRpToken(null); $customerModel->setRpTokenCreatedAt(null); } + if (!array_key_exists('default_billing', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_billing', $prevCustomerDataArr) + ) { + $customerModel->setDefaultBilling($prevCustomerDataArr['default_billing']); + } + if (!array_key_exists('default_shipping', $customerArr) + && null !== $prevCustomerDataArr + && array_key_exists('default_shipping', $prevCustomerDataArr) + ) { + $customerModel->setDefaultShipping($prevCustomerDataArr['default_shipping']); + } $customerModel->save(); $this->customerRegistry->push($customerModel); $customerId = $customerModel->getId(); - + if (!$customer->getAddresses() + && $delegatedNewOperation + && $delegatedNewOperation->getCustomer()->getAddresses() + ) { + $customer->setAddresses($delegatedNewOperation->getCustomer()->getAddresses()); + } + if ($customer->getAddresses() !== null) { + if ($customer->getId()) { + $existingAddresses = $this->getById($customer->getId())->getAddresses(); + $getIdFunc = function ($address) { + return $address->getId(); + }; + $existingAddressIds = array_map($getIdFunc, $existingAddresses); + } else { + $existingAddressIds = []; + } + $savedAddressIds = []; + foreach ($customer->getAddresses() as $address) { + $address->setCustomerId($customerId) + ->setRegion($address->getRegion()); + $this->addressRepository->save($address); + if ($address->getId()) { + $savedAddressIds[] = $address->getId(); + } + } + $addressIdsToDelete = array_diff($existingAddressIds, $savedAddressIds); + foreach ($addressIdsToDelete as $addressId) { + $this->addressRepository->deleteById($addressId); + } + } $this->customerRegistry->remove($customerId); $savedCustomer = $this->get($customer->getEmail(), $customer->getWebsiteId()); $this->eventManager->dispatch( diff --git a/app/code/Magento/Customer/etc/db_schema_whitelist.json b/app/code/Magento/Customer/etc/db_schema_whitelist.json index 4aada8f0d81fe..ec7a53945aba3 100644 --- a/app/code/Magento/Customer/etc/db_schema_whitelist.json +++ b/app/code/Magento/Customer/etc/db_schema_whitelist.json @@ -73,7 +73,8 @@ "vat_request_success": true }, "index": { - "CUSTOMER_ADDRESS_ENTITY_PARENT_ID": true + "CUSTOMER_ADDRESS_ENTITY_PARENT_ID": true, + "FTI_BA70344390184AC3F063AB2EB38BC0ED": true }, "constraint": { "PRIMARY": true, diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index cfc62fc99b10e..28b19d61fbdde 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -39,25 +39,18 @@ <bookmark name="bookmarks"/> <columnsControls name="columns_controls"/> <!-- Filter Search --> - <filterSearch name="fulltext"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing_data_source</item> - <item name="chipsProvider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</item> - <item name="storageConfig" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> - <item name="namespace" xsi:type="string">current.search</item> - </item> - </item> - </argument> + <filterSearch name="fulltext" provider="customer_address_listing.customer_address_listing_data_source"> + <settings> + <chipsProvider>customer_address_listing.customer_address_listing.listing_top.listing_filters_chips</chipsProvider> + <storageConfig> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> + <param name="namespace" xsi:type="string">current.search</param> + </storageConfig> + </settings> </filterSearch> <filters name="listing_filters"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="storageConfig" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</item> - <item name="namespace" xsi:type="string">current.filters</item> - </item> <item name="childDefaults" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> <item name="imports" xsi:type="array"> @@ -66,6 +59,12 @@ </item> </item> </argument> + <settings> + <storageConfig> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> + <param name="namespace" xsi:type="string">current.filters</param> + </storageConfig> + </settings> </filters> <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> <action name="delete"> diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 6fc8fcac6099f..17d4e7aab5cd3 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -328,10 +328,9 @@ </settings> </component> - <button name="edit_billing_address"> + <button name="edit_billing_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">edit-default-billing-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> @@ -375,10 +374,9 @@ </settings> </component> - <button name="edit_shipping_address"> + <button name="edit_shipping_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">edit-default-shipping-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> @@ -405,11 +403,10 @@ </imports> </settings> </button> - <button name="add_address"> + <button name="add_address" component="Magento_Customer/js/address/default-address"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="formElement" xsi:type="string">container</item> - <item name="component" xsi:type="string">Magento_Customer/js/address/default-address</item> <item name="buttonClasses" xsi:type="string">add-new-address-button</item> <item name="actions" xsi:type="array"> <item name="0" xsi:type="array"> diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php index c6741f76e0538..5a4a426b58cda 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -86,9 +86,7 @@ public function testSaveActionWithValidAddressData() $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); $this->customerAddress->execute(); - /** - * Check that errors was generated and set to session - */ + $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); /** @@ -220,4 +218,36 @@ public function testSaveActionWithExistingAdresses() $addresses = $customer->getAddresses(); $this->assertCount(4, $addresses); } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + */ + public function testValidateCustomerWithAddressFailure() + { + $customer = $this->customerRepository->get('customer@example.com'); + $customerId = $customer->getId(); + $post = [ + 'parent_id' => $customerId, + 'firstname' => '', + 'lastname' => '', + 'street' => ['update street'], + 'city' => 'update city', + 'postcode' => '01001', + 'telephone' => '', + ]; + $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); + + $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); + + $this->customerAddress->execute(); + + /** + * Check that errors was generated and set to session + */ + $this->assertSessionMessages( + $this->equalTo(['One or more input exceptions have occurred.']), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php index 2fe49efd74a6d..292d61c392d06 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/IndexTest.php @@ -122,226 +122,6 @@ public function testSaveActionWithInvalidFormData() $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new')); } - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithInvalidCustomerAddressData() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 0, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'example@domain.com', - 'default_billing' => '_item1', - ], - 'address' => ['_item1' => []], - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/save'); - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - /** - * Check that customer data were set to session - */ - $this->assertArraySubset( - $post, - $this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerFormData() - ); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'new')); - } - - /** - * @magentoDbIsolation enabled - */ - public function testSaveActionWithValidCustomerDataAndValidAddressData() - { - $post = [ - 'customer' => [ - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 0, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'example@domain.com', - 'default_billing' => '_item1', - 'password' => 'password', - ], - 'address' => [ - '_item1' => [ - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'street' => ['test street'], - 'city' => 'test city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_billing' => 'true', - ], - ], - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('back', '1'); - - // Emulate setting customer data to session in editAction - $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); - - $this->dispatch('backend/customer/index/save'); - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - - /** - * Check that customer data were cleaned after it was saved successfully - */ - $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - - /** - * Check that customer id set and addresses saved - */ - $registry = $this->objectManager->get(\Magento\Framework\Registry::class); - $customerId = $registry->registry(RegistryConstants::CURRENT_CUSTOMER_ID); - $customer = $this->customerRepository->getById($customerId); - $this->assertEquals('test firstname', $customer->getFirstname()); - $addresses = $customer->getAddresses(); - $this->assertEquals(1, count($addresses)); - $this->assertNotEquals(0, $this->accountManagement->getDefaultBillingAddress($customerId)); - $this->assertNull($this->accountManagement->getDefaultShippingAddress($customerId)); - - $urlPatternParts = [ - $this->_baseControllerUrl . 'edit', - 'id/' . $customerId, - 'back/1', - ]; - $urlPattern = '/^' . str_replace('/', '\/', implode('(/.*/)|/', $urlPatternParts)) . '/'; - - $this->assertRedirect( - $this->matchesRegularExpression($urlPattern) - ); - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertEmpty($subscriber->getId()); - } - - /** - * @magentoDataFixture Magento/Customer/_files/customer_sample.php - */ - public function testSaveActionExistingCustomerAndExistingAddressData() - { - $post = [ - 'customer' => [ - 'entity_id' => '1', - 'middlename' => 'test middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => 'test firstname', - 'lastname' => 'test lastname', - 'email' => 'customer@example.com', - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - 'created_at' => '2000-01-01 00:00:00', - 'default_shipping' => '_item1', - 'default_billing' => 1, - ], - 'address' => [ - '1' => [ - 'firstname' => 'update firstname', - 'lastname' => 'update lastname', - 'street' => ['update street'], - 'city' => 'update city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_billing' => 'true', - ], - '_item1' => [ - 'firstname' => 'new firstname', - 'lastname' => 'new lastname', - 'street' => ['new street'], - 'city' => 'new city', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '01001', - 'telephone' => '+7000000001', - 'default_shipping' => 'true', - ], - '_template_' => [ - 'firstname' => '', - 'lastname' => '', - 'street' => [], - 'city' => '', - 'region_id' => 10, - 'country_id' => 'US', - 'postcode' => '', - 'telephone' => '', - ], - ], - 'subscription' => '', - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - $this->getRequest()->setParam('id', 1); - $this->dispatch('backend/customer/index/save'); - - /** Check that success message is set */ - $this->assertSessionMessages( - $this->equalTo(['You saved the customer.']), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - - /** Check that customer id set and addresses saved */ - $registry = $this->objectManager->get(\Magento\Framework\Registry::class); - $customerId = $registry->registry(RegistryConstants::CURRENT_CUSTOMER_ID); - $customer = $this->customerRepository->getById($customerId); - $this->assertEquals('test firstname', $customer->getFirstname()); - - /** - * Addresses should be removed by - * \Magento\Customer\Model\ResourceModel\Customer::_saveAddresses during _afterSave - * addressOne - updated - * addressTwo - removed - * addressThree - removed - * _item1 - new address - */ - $addresses = $customer->getAddresses(); - $this->assertEquals(2, count($addresses)); - $updatedAddress = $this->addressRepository->getById(1); - $this->assertEquals('update firstname', $updatedAddress->getFirstname()); - $this->assertTrue($updatedAddress->isDefaultBilling()); - $this->assertEquals($updatedAddress->getId(), $customer->getDefaultBilling()); - $newAddress = $this->accountManagement->getDefaultShippingAddress($customerId); - $this->assertEquals('new firstname', $newAddress->getFirstname()); - - /** @var \Magento\Newsletter\Model\Subscriber $subscriber */ - $subscriber = $this->objectManager->get(\Magento\Newsletter\Model\SubscriberFactory::class)->create(); - $this->assertEmpty($subscriber->getId()); - $subscriber->loadByCustomerId($customerId); - $this->assertNotEmpty($subscriber->getId()); - $this->assertEquals(1, $subscriber->getStatus()); - $this->assertRedirect($this->stringStartsWith($this->_baseControllerUrl . 'index/key/')); - } - /** * @magentoDataFixture Magento/Newsletter/_files/subscribers.php */ @@ -544,7 +324,7 @@ public function testNewAction() /** * Test the editing of a new customer that has not been saved but the page has been reloaded */ - public function testNewActionWithCustomerData() + public function te1stNewActionWithCustomerData() { $customerData = [ 'customer_id' => 0, @@ -679,59 +459,6 @@ public function testValidateCustomerWithAddressSuccess() $this->assertEquals('{"error":0}', $body); } - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDataFixture Magento/Customer/_files/customer_address.php - */ - public function testValidateCustomerWithAddressFailure() - { - $customerData = [ - 'customer' => [ - 'entity_id' => '1', - 'middlename' => 'new middlename', - 'group_id' => 1, - 'website_id' => 1, - 'firstname' => '', - 'lastname' => '', - 'email' => '*', - 'default_shipping' => '_item1', - 'new_password' => 'auto', - 'sendemail_store_id' => '1', - 'sendemail' => '1', - ], - 'address' => [ - '1' => [ - 'firstname' => '', - 'lastname' => '', - 'street' => ['update street'], - 'city' => 'update city', - 'postcode' => '01001', - 'telephone' => '', - ], - '_template_' => [ - 'lastname' => '', - 'street' => [], - 'city' => '', - 'country_id' => 'US', - 'postcode' => '', - 'telephone' => '', - ], - ], - ]; - /** - * set customer data - */ - $this->getRequest()->setPostValue($customerData)->setMethod(HttpRequest::METHOD_POST); - $this->dispatch('backend/customer/index/validate'); - $body = $this->getResponse()->getBody(); - - $this->assertContains('{"error":true,"messages":', $body); - $this->assertContains('\"First Name\" is a required value', $body); - $this->assertContains('\"Last Name\" is a required value.', $body); - $this->assertContains('\"Country\" is a required value.', $body); - $this->assertContains('\"Phone Number\" is a required value.', $body); - } - /** * @magentoDbIsolation enabled */ From 35112c4015f6912dd29c7b65c83ee1aef9fe04b8 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Tue, 6 Nov 2018 12:30:50 +0200 Subject: [PATCH 052/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - UI component declaration fixes --- .../ui_component/customer_address_listing.xml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 28b19d61fbdde..6c97a6da5e9e2 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -49,21 +49,17 @@ </settings> </filterSearch> <filters name="listing_filters"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="childDefaults" xsi:type="array"> - <item name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</item> - <item name="imports" xsi:type="array"> - <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> - </item> - </item> - </item> - </argument> <settings> <storageConfig> <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks</param> <param name="namespace" xsi:type="string">current.filters</param> </storageConfig> + <childDefaults> + <param name="provider" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.listing_filters</param> + <param name="imports" xsi:type="array"> + <item name="visible" xsi:type="string">customer_address_listing.customer_address_listing.listing_top.bookmarks:current.columns.${ $.index }.visible</item> + </param> + </childDefaults> </settings> </filters> <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> From b545997c49beec86291b4a28741c43d01c53c41e Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Wed, 7 Nov 2018 15:14:20 +0200 Subject: [PATCH 053/216] magento/magento2#18990: Shipping address is not validated in checkout when proceeding step as logged in user with default shipping address --- .../view/frontend/web/js/view/shipping.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js index 6ac805f72f78d..c811d3a1e8369 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/view/shipping.js @@ -266,9 +266,8 @@ define([ loginFormSelector = 'form[data-role=email-with-possible-login]', emailValidationResult = customer.isLoggedIn(), field, - countryIndexedOptions = registry.get( - this.parentName + '.shippingAddress.shipping-address-fieldset.country_id' - ).indexedOptions, + country = registry.get(this.parentName + '.shippingAddress.shipping-address-fieldset.country_id'), + countryIndexedOptions = country.indexedOptions, option = countryIndexedOptions[quote.shippingAddress().countryId], messageContainer = registry.get('checkout.errors').messageContainer; @@ -323,12 +322,14 @@ define([ shippingAddress['save_in_address_book'] = 1; } selectShippingAddress(shippingAddress); - } else if (customer.isLoggedIn() - && option - && option['is_region_required'] - && !quote.shippingAddress().region + } else if (customer.isLoggedIn() && + option && + option['is_region_required'] && + !quote.shippingAddress().region ) { - messageContainer.addErrorMessage({message: $t('Please specify a regionId in shipping address.')}); + messageContainer.addErrorMessage({ + message: $t('Please specify a regionId in shipping address.') + }); return false; } From 965de969e224387fa307c7f8c099a25d78c4f5a4 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Wed, 7 Nov 2018 16:48:13 +0200 Subject: [PATCH 054/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to save address action; --- .../Controller/Adminhtml/Address/Save.php | 69 ++++++++++++------- .../Customer/Model/Address/DataProvider.php | 27 ++++---- .../web/js/address/default-address.js | 16 ++--- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 8b70263d3f95b..3bd49d038588c 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -8,7 +8,10 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Controller\ResultInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Psr\Log\LoggerInterface; /** @@ -53,6 +56,11 @@ class Save extends Action implements HttpPostActionInterface */ private $logger; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Action\Context $context * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository @@ -61,6 +69,7 @@ class Save extends Action implements HttpPostActionInterface * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper * @param \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Action\Context $context, @@ -69,7 +78,8 @@ public function __construct( \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, \Magento\Customer\Api\Data\AddressInterfaceFactory $addressDataFactory, - LoggerInterface $logger + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { parent::__construct($context); $this->addressRepository = $addressRepository; @@ -78,23 +88,24 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->addressDataFactory = $addressDataFactory; $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; } /** * Save customer address action * - * @return \Magento\Framework\Controller\Result\Redirect - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException + * @return ResultInterface */ - public function execute(): Redirect + public function execute(): ResultInterface { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('entity_id', false); - /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ - $customer = $this->customerRepository->getById($customerId); + $error = false; try { + /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ + $customer = $this->customerRepository->getById($customerId); + $addressForm = $this->formFactory->create( 'customer_address', 'adminhtml_customer_address', @@ -124,29 +135,39 @@ public function execute(): Redirect ); if ($addressId) { $addressToSave->setId($addressId); - $saveMessage = __('Customer address has been updated.'); + $message = __('Customer address has been updated.'); } else { $addressToSave->setId(null); - $saveMessage = __('New customer address has been added.'); + $message = __('New customer address has been added.'); } - - $this->addressRepository->save($addressToSave); - $this->messageManager->addSuccessMessage($saveMessage); - } catch (\Magento\Framework\Exception\LocalizedException $e) { - $this->messageManager->addErrorMessage($e->getMessage()); + $savedAddress = $this->addressRepository->save($addressToSave); + $addressId = $savedAddress->getId(); + } catch (NoSuchEntityException $e) { + $this->logger->critical($e); + $error = true; + $message = __('There is no customer with such id.'); + } catch (LocalizedException $e) { + $error = true; + $message = __($e->getMessage()); $this->logger->critical($e); } catch (\Exception $e) { - $this->messageManager->addExceptionMessage( - $e, - __('We can\'t change customer address right now.') - ); + $error = true; + $message = __('We can\'t change customer address right now.'); + $this->logger->critical($e); } - $resultRedirect = $this->resultRedirectFactory->create(); - $resultRedirect->setPath( - 'customer/index/edit', - ['id' => $customerId, '_current' => true] + $addressId = empty($addressId) ? null : $addressId; + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + 'data' => [ + 'addressId' => $addressId + ] + ] ); - return $resultRedirect; + + return $resultJson; } } diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index 1b4bcf94fec15..a7c0da08324d3 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -126,21 +126,18 @@ public function getData(): array if (null !== $this->loadedData) { return $this->loadedData; } - $items = $this->collection->getItems(); - /** @var Address $item */ - foreach ($items as $item) { - $addressId = $item->getEntityId(); - $item->load($addressId); - $this->loadedData[$addressId] = $item->getData(); - $customerId = $this->loadedData[$addressId]['parent_id']; - /** @var \Magento\Customer\Model\Customer $customer */ - $customer = $this->customerRepository->getById($customerId); - $defaultBilling = $customer->getDefaultBilling(); - $defaultShipping = $customer->getDefaultShipping(); - $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - - $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); - } + /** @var Address $address */ + $address = $this->collection->getFirstItem(); + $addressId = $address->getEntityId(); + $address->load($addressId); + $this->loadedData[$addressId] = $address->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->fileUploaderDataResolver->overrideFileUploaderData($address, $this->loadedData[$addressId]); if (null === $this->loadedData) { $this->loadedData[''] = $this->getDefaultData(); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index 530df8544c841..b4ec734cb4033 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -10,8 +10,8 @@ define([ return Button.extend({ defaults: { - entityId: null, - parentId: null + entity_id: null, + parent_id: null }, /** @@ -21,8 +21,8 @@ define([ */ initialize: function () { this._super(); - if (!this.parentId) { - this.visible(this.entityId); + if (!this.parent_id) { + this.visible(this.entity_id); } return this; @@ -36,12 +36,12 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entityId = this.entityId; - action.params[0].parentId = this.parentId; + action.params[0].entity_id = this.entity_id; + action.params[0].parent_id = this.parent_id; } else { action.params = [{ - entityId: this.entityId, - parentId: this.parentId + entity_id: this.entity_id, + parent_id: this.parent_id }]; } From 9ca93f97c170b26e0f90be10325cdcc5d296524f Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 8 Nov 2018 10:37:04 +0200 Subject: [PATCH 055/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to delete, mass delete address actions; --- .../Controller/Adminhtml/Address/Delete.php | 52 ++++++++++---- .../Adminhtml/Address/MassDelete.php | 70 ++++++++++++++----- .../Controller/Adminhtml/Address/Save.php | 6 +- .../Customer/Model/Address/DataProvider.php | 26 +++---- 4 files changed, 110 insertions(+), 44 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 7630dba780357..3caba47961af0 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,14 +8,16 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Framework\App\Action\HttpDeleteActionInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; +use Psr\Log\LoggerInterface; /** * Button for deletion of customer address in admin * */ -class Delete extends Action implements HttpPostActionInterface +class Delete extends Action implements HttpDeleteActionInterface { /** * Authorization level of a basic admin session @@ -29,39 +31,65 @@ class Delete extends Action implements HttpPostActionInterface */ private $addressRepository; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param Action\Context $context * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param JsonFactory $resultJsonFactory + * @param LoggerInterface $logger */ public function __construct( Action\Context $context, - AddressRepositoryInterface $addressRepository + AddressRepositoryInterface $addressRepository, + JsonFactory $resultJsonFactory, + LoggerInterface $logger ) { parent::__construct($context); $this->addressRepository = $addressRepository; + $this->resultJsonFactory = $resultJsonFactory; + $this->logger = $logger; } /** * Delete customer address action * - * @return \Magento\Framework\Controller\Result\Redirect + * @return Json * @throws \Magento\Framework\Exception\LocalizedException */ - public function execute(): Redirect + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('id', false); + $error = false; + $message = ''; if ($addressId && $this->addressRepository->getById($addressId)->getCustomerId() === $customerId) { try { $this->addressRepository->deleteById($addressId); - $this->messageManager->addSuccessMessage(__('You deleted the address.')); - } catch (\Exception $other) { - $this->messageManager->addExceptionMessage($other, __('We can\'t delete the address right now.')); + $message = __('You deleted the address.'); + } catch (\Exception $e) { + $error = true; + $message = __('We can\'t delete the address right now.'); + $this->logger->critical($e); } } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); + + return $resultJson; } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index b8df3fdf81599..09523f9e6a956 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -8,12 +8,15 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Controller\Result\Json; use Magento\Backend\App\Action\Context; +use Magento\Framework\Controller\Result\JsonFactory; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Ui\Component\MassAction\Filter; use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\Backend\Model\View\Result\Redirect; +use Psr\Log\LoggerInterface; /** * Class to delete selected customer addresses through massaction @@ -38,52 +41,85 @@ class MassDelete extends Action implements HttpPostActionInterface protected $collectionFactory; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Context $context * @param Filter $filter * @param CollectionFactory $collectionFactory * @param AddressRepositoryInterface $addressRepository + * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Context $context, Filter $filter, CollectionFactory $collectionFactory, - AddressRepositoryInterface $addressRepository + AddressRepositoryInterface $addressRepository, + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; $this->addressRepository = $addressRepository; + $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context); } /** * Delete specified customer addresses using grid massaction * - * @return Redirect - * @throws \Magento\Framework\Exception\LocalizedException|\Exception + * @return Json + * @throws LocalizedException */ - public function execute(): Redirect + public function execute(): Json { /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ $collection = $this->filter->getCollection($this->collectionFactory->create()); $collectionSize = $collection->getSize(); + $error = false; - // Get id of the first item from addresses collection for the ResultRedirect and build a correct redirect URL - $customerId = $collection->getFirstItem()->getParentId(); - - /** @var \Magento\Customer\Model\Address $address */ - foreach ($collection as $address) { - $this->addressRepository->deleteById($address->getId()); + try { + /** @var \Magento\Customer\Model\Address $address */ + foreach ($collection as $address) { + $this->addressRepository->deleteById($address->getId()); + } + $message = __('A total of %1 record(s) have been deleted.', $collectionSize); + } catch (NoSuchEntityException $e) { + $message = __('There is no such address entity to delete.'); + $error = true; + $this->logger->critical($e); + } catch (LocalizedException $e) { + $message = __($e->getMessage()); + $error = true; + $this->logger->critical($e); + } catch (\Exception $e) { + $message = __('We can\'t mass delete the addresses right now.'); + $error = true; + $this->logger->critical($e); } - $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been deleted.', $collectionSize)); - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + return $resultJson; } } diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 3bd49d038588c..855b8aedb1f73 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -8,8 +8,8 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; -use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Psr\Log\LoggerInterface; @@ -94,9 +94,9 @@ public function __construct( /** * Save customer address action * - * @return ResultInterface + * @return Json */ - public function execute(): ResultInterface + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('entity_id', false); diff --git a/app/code/Magento/Customer/Model/Address/DataProvider.php b/app/code/Magento/Customer/Model/Address/DataProvider.php index a7c0da08324d3..c41214b91b8c2 100644 --- a/app/code/Magento/Customer/Model/Address/DataProvider.php +++ b/app/code/Magento/Customer/Model/Address/DataProvider.php @@ -126,18 +126,20 @@ public function getData(): array if (null !== $this->loadedData) { return $this->loadedData; } - /** @var Address $address */ - $address = $this->collection->getFirstItem(); - $addressId = $address->getEntityId(); - $address->load($addressId); - $this->loadedData[$addressId] = $address->getData(); - $customerId = $this->loadedData[$addressId]['parent_id']; - /** @var \Magento\Customer\Model\Customer $customer */ - $customer = $this->customerRepository->getById($customerId); - $defaultBilling = $customer->getDefaultBilling(); - $defaultShipping = $customer->getDefaultShipping(); - $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); - $this->fileUploaderDataResolver->overrideFileUploaderData($address, $this->loadedData[$addressId]); + $items = $this->collection->getItems(); + /** @var Address $item */ + foreach ($items as $item) { + $addressId = $item->getEntityId(); + $item->load($addressId); + $this->loadedData[$addressId] = $item->getData(); + $customerId = $this->loadedData[$addressId]['parent_id']; + /** @var \Magento\Customer\Model\Customer $customer */ + $customer = $this->customerRepository->getById($customerId); + $defaultBilling = $customer->getDefaultBilling(); + $defaultShipping = $customer->getDefaultShipping(); + $this->prepareAddressData($addressId, $this->loadedData, $defaultBilling, $defaultShipping); + $this->fileUploaderDataResolver->overrideFileUploaderData($item, $this->loadedData[$addressId]); + } if (null === $this->loadedData) { $this->loadedData[''] = $this->getDefaultData(); From 14bc369dfce948a564a46178a7c2a413b3b71b1a Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Thu, 8 Nov 2018 11:40:51 +0200 Subject: [PATCH 056/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add json response to set default shipping, set default billing actions; --- .../Address/AbstractDefaultAddress.php | 53 +++++++++++++------ .../Controller/Adminhtml/Address/Delete.php | 10 ++-- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index 51e02e9ee096e..9ec38f4929a87 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -8,15 +8,17 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpPostActionInterface; -use Magento\Framework\Controller\Result\Redirect; +use Magento\Customer\Api\AddressRepositoryInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\Controller\Result\Json; +use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Phrase; use Psr\Log\LoggerInterface; /** * Abstract class for customer default addresses changing */ -abstract class AbstractDefaultAddress extends Action implements HttpPostActionInterface +abstract class AbstractDefaultAddress extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -26,7 +28,7 @@ abstract class AbstractDefaultAddress extends Action implements HttpPostActionIn public const ADMIN_RESOURCE = 'Magento_Customer::manage'; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; @@ -35,46 +37,63 @@ abstract class AbstractDefaultAddress extends Action implements HttpPostActionIn */ private $logger; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + /** * @param Action\Context $context - * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param AddressRepositoryInterface $addressRepository * @param LoggerInterface $logger + * @param JsonFactory $resultJsonFactory */ public function __construct( Action\Context $context, - \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, - LoggerInterface $logger + AddressRepositoryInterface $addressRepository, + LoggerInterface $logger, + JsonFactory $resultJsonFactory ) { parent::__construct($context); $this->addressRepository = $addressRepository; $this->logger = $logger; + $this->resultJsonFactory = $resultJsonFactory; } /** * Execute action to set customer default billing or shipping address * - * @return \Magento\Framework\Controller\Result\Redirect + * @return Json */ - public function execute(): Redirect + public function execute(): Json { $customerId = $this->getRequest()->getParam('parent_id', false); $addressId = $this->getRequest()->getParam('id', false); + $error = false; + $message = ''; + if ($addressId) { try { $address = $this->addressRepository->getById($addressId)->setCustomerId($customerId); $this->setAddressAsDefault($address); $this->addressRepository->save($address); - - $this->messageManager->addSuccessMessage($this->getSuccessMessage()); - } catch (\Exception $other) { - $this->logger->critical($other); - $this->messageManager->addExceptionMessage($other, $this->getExceptionMessage()); + $message = $this->getSuccessMessage(); + } catch (\Exception $e) { + $error = true; + $message = $this->getExceptionMessage(); + $this->logger->critical($e); } } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); - return $resultRedirect->setPath('customer/index/edit/id', ['id' => $customerId]); + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setData( + [ + 'message' => $message, + 'error' => $error, + ] + ); + + return $resultJson; } /** diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 3caba47961af0..65da3bca49e9b 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,16 +8,16 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpDeleteActionInterface; +use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; use Psr\Log\LoggerInterface; /** - * Button for deletion of customer address in admin * + * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpDeleteActionInterface +class Delete extends Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -27,7 +27,7 @@ class Delete extends Action implements HttpDeleteActionInterface public const ADMIN_RESOURCE = 'Magento_Customer::manage'; /** - * @var \Magento\Customer\Api\AddressRepositoryInterface + * @var AddressRepositoryInterface */ private $addressRepository; @@ -43,7 +43,7 @@ class Delete extends Action implements HttpDeleteActionInterface /** * @param Action\Context $context - * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository + * @param AddressRepositoryInterface $addressRepository * @param JsonFactory $resultJsonFactory * @param LoggerInterface $logger */ From e4f006090981154d5d404dca04f07ecbff54938a Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Thu, 8 Nov 2018 16:43:52 +0200 Subject: [PATCH 057/216] MAGETWO-96178: Customer addresses should be saved using Ajax --- .../Controller/Adminhtml/Address/Save.php | 2 +- .../Listing/Address/Column/Actions.php | 7 +- .../ui_component/customer_address_form.xml | 17 ++++ .../ui_component/customer_address_listing.xml | 31 ++++--- .../web/js/address/default-address.js | 36 +++---- .../web/js/form/components/insert-form.js | 55 +++++++++++ .../web/js/form/components/insert-listing.js | 53 +++++++++++ .../adminhtml/web/js/grid/columns/actions.js | 93 +++++++++++++++++++ .../view/adminhtml/web/js/grid/massactions.js | 92 ++++++++++++++++++ .../web/template/default-address.html | 7 +- .../view/base/ui_component/customer_form.xml | 33 ++++++- 11 files changed, 381 insertions(+), 45 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php index 855b8aedb1f73..0bdb0d44d29a9 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Save.php @@ -163,7 +163,7 @@ public function execute(): Json 'message' => $message, 'error' => $error, 'data' => [ - 'addressId' => $addressId + 'entity_id' => $addressId ] ] ); diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index e44dc7988761f..490a14169e7b7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -81,24 +81,26 @@ public function prepareDataSource(array $dataSource): array 'hidden' => false, ]; - $item[$name]['set_default_billing'] = [ + $item[$name]['setDefaultBilling'] = [ 'href' => $this->urlBuilder->getUrl( self::CUSTOMER_ADDRESS_PATH_DEFAULT_BILLING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Set as default billing'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Set address as default billing'), 'message' => __('Are you sure you want to set the address as default billing address?') ] ]; - $item[$name]['set_default_shipping'] = [ + $item[$name]['setDefaultShipping'] = [ 'href' => $this->urlBuilder->getUrl( self::CUSTOMER_ADDRESS_PATH_DEFAULT_SHIPPING, ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Set as default shipping'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Set address as default shipping'), 'message' => __('Are you sure you want to set the address as default shipping address?') @@ -111,6 +113,7 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), + 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), 'message' => __('Are you sure you want to delete the address?') diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index a2258d7380e24..bcc5b86c5e65d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -21,6 +21,8 @@ <button name="save" class="Magento\Customer\Block\Adminhtml\Edit\Address\SaveButton"/> </buttons> <namespace>customer_address_form</namespace> + <ajaxSave>true</ajaxSave> + <ajaxSaveType>simple</ajaxSaveType> <dataScope>data</dataScope> <deps> <dep>customer_address_form.customer_address_form_data_source</dep> @@ -44,6 +46,21 @@ </settings> </dataProvider> </dataSource> + <container name="messages" component="Magento_Ui/js/form/components/html"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="additionalClasses" xsi:type="string">message message-error</item> + <item name="visible" xsi:type="boolean">false</item> + <item name="imports" xsi:type="array"> + <item name="responseData" xsi:type="string">${ $.parentName }:responseData</item> + </item> + <item name="listens" xsi:type="array"> + <item name="responseData.error" xsi:type="string">visible</item> + <item name="responseData.messages" xsi:type="string">content</item> + </item> + </item> + </argument> + </container> <fieldset name="general"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 6c97a6da5e9e2..b48d53f9e8c5d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -62,18 +62,23 @@ </childDefaults> </settings> </filters> - <massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions"> - <action name="delete"> - <settings> - <confirm> - <message translate="true">Are you sure to delete selected address?</message> - <title translate="true">Delete items - - - delete - - - + + + + + + true + + Are you sure to delete selected address? + Delete items + + + delete + Delete + + + + @@ -157,7 +162,7 @@
- + entity_id diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js index b4ec734cb4033..2ca75d6149da4 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/address/default-address.js @@ -4,28 +4,18 @@ */ define([ - 'Magento_Ui/js/form/components/button' -], function (Button) { + 'Magento_Ui/js/form/components/button', + 'underscore' +], function (Button, _) { 'use strict'; return Button.extend({ defaults: { - entity_id: null, - parent_id: null - }, - - /** - * Initializes component. - * - * @returns {Button} - */ - initialize: function () { - this._super(); - if (!this.parent_id) { - this.visible(this.entity_id); + entityId: null, + parentId: null, + listens: { + entity: 'changeVisibility' } - - return this; }, /** @@ -36,16 +26,20 @@ define([ */ applyAction: function (action) { if (action.params && action.params[0]) { - action.params[0].entity_id = this.entity_id; - action.params[0].parent_id = this.parent_id; + action.params[0]['entity_id'] = this.entityId; + action.params[0]['parent_id'] = this.parentId; } else { action.params = [{ - entity_id: this.entity_id, - parent_id: this.parent_id + 'entity_id': this.entityId, + 'parent_id': this.parentId }]; } this._super(); + }, + + changeVisibility: function (entity) { + this.visible(!_.isEmpty(entity)); } }); }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js new file mode 100644 index 0000000000000..25303899894c4 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -0,0 +1,55 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-form' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + defaults: { + listens: { + responseData: 'onResponse' + }, + modules: { + addressListing: '${ $.addressListingProvider }', + addressModal: '${ $.addressModalProvider }' + } + }, + + onResponse: function (responseData) { + var data; + + if (!responseData.error) { + this.addressModal().closeModal(); + this.addressListing().reload({ + refresh: true + }); + data = this.externalSource().get('data'); + this.saveAddress(responseData, data); + } + }, + + saveAddress: function (responseData, data) { + data['entity_id'] = responseData.data['entity_id']; + + if (parseFloat(data['default_billing'])) { + this.source.set('data.default_billing_address', data); + } else if ( + parseFloat(this.source.get('data.default_billing_address')['entity_id']) === data['entity_id'] + ) { + this.source.set('data.default_billing_address', []); + } + + if (parseFloat(data['default_shipping'])) { + this.source.set('data.default_shipping_address', data); + } else if ( + parseFloat(this.source.get('data.default_shipping_address')['entity_id']) === data['entity_id'] + ) { + this.source.set('data.default_shipping_address', []); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js new file mode 100644 index 0000000000000..0dd828b03b419 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js @@ -0,0 +1,53 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'Magento_Ui/js/form/components/insert-listing' +], function (Insert) { + 'use strict'; + + return Insert.extend({ + onAction: function (data) { + this[data.action + 'Action'].call(this, data.data); + }, + onMassAction: function (data) { + this[data.action + 'Massaction'].call(this, data.data); + }, + + setDefaultBillingAction: function (data) { + this.source.set('data.default_billing_address', data); + }, + + setDefaultShippingAction: function (data) { + this.source.set('data.default_shipping_address', data); + }, + + deleteAction: function (data) { + var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), + defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); + + if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + this.source.set('data.default_shipping_address', []); + } + if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + this.source.set('data.default_billing_address', []); + } + }, + + //TODO: release logic with massaction + deleteMassaction: function (data) { + debugger; + // var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), + // defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); + // + // if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + // this.source.set('data.default_shipping_address', []); + // } + // if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + // this.source.set('data.default_billing_address', []); + // } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js new file mode 100644 index 0000000000000..43ab06c8014ee --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -0,0 +1,93 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/grid/columns/actions', + 'Magento_Ui/js/modal/alert', + 'underscore', + 'jquery', + 'mage/translate' +], function (Actions, uiAlert, _, $, $t) { + 'use strict'; + + return Actions.extend({ + defaults: { + ajaxSettings: { + method: 'GET', + dataType: 'json' + }, + listens: { + action: 'onAction' + } + }, + + onAction: function (data) { + if (data.action === 'delete') { + this.source().reload({ + refresh: true + }); + } + }, + + /** + * Default action callback. Redirects to + * the specified in action's data url. + * + * @param {String} actionIndex - Action's identifier. + * @param {(Number|String)} recordId - Id of the record associated + * with a specified action. + * @param {Object} action - Action's data. + */ + defaultCallback: function (actionIndex, recordId, action) { + if (action.isAjax) { + this.request(action.href).done(function (response) { + var data; + + if (!response.error) { + data = _.findWhere(this.rows, { + _rowIndex: action.rowIndex + }); + + this.trigger('action', { + action: actionIndex, + data: data + }); + } + }.bind(this)); + + } else { + this._super(); + } + }, + + request: function (href) { + var settings = _.extend({}, this.ajaxSettings, { + url: href + }); + + $('body').trigger('processStart'); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js new file mode 100644 index 0000000000000..1aefa2e249958 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js @@ -0,0 +1,92 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/grid/massactions', + 'Magento_Ui/js/modal/alert', + 'underscore', + 'jquery', + 'mage/translate' +], function (Massactions, uiAlert, _, $, $t) { + 'use strict'; + + return Massactions.extend({ + defaults: { + ajaxSettings: { + method: 'POST', + dataType: 'json' + }, + listens: { + massaction: 'onAction' + } + }, + + onAction: function (data) { + if (data.action === 'delete') { + this.source.reload({ + refresh: true + }); + } + }, + + defaultCallback: function (action, data) { + var itemsType, selections; + + if (action.isAjax) { + itemsType = data.excludeMode ? 'excluded' : 'selected'; + selections = {}; + + selections[itemsType] = data[itemsType]; + + if (!selections[itemsType].length) { + selections[itemsType] = false; + } + + _.extend(selections, data.params || {}); + + this.request(action.url, selections).done(function (response) { + if (!response.error) { + this.trigger('massaction', { + action: action.type, + data: selections + }); + } + }.bind(this)); + + } else { + this._super(); + } + }, + + request: function (href, data) { + var settings = _.extend({}, this.ajaxSettings, { + url: href, + data: data + }); + + $('body').trigger('processStart'); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 1ee5a4da81d2b..96158e9921e22 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -4,7 +4,7 @@
-
+
@@ -16,7 +16,8 @@
- + +
@@ -36,7 +37,7 @@
VAT:
- +
diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index 17d4e7aab5cd3..d6d61c892e00d 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -319,6 +319,9 @@ Default Billing Address customer-default-billing-address-content The customer does not have default billing address + + true +
@@ -353,7 +356,8 @@ Edit true - ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address.entity_id + ${ $.provider}:data.default_billing_address @@ -365,6 +369,9 @@ Default Shipping Address customer-default-shipping-address-content The customer does not have default shipping address + + true + @@ -399,7 +406,8 @@ Edit true - ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address @@ -427,7 +435,7 @@ Add New Address - ${ $.provider}:data.customer_id + ${ $.provider}:data.customer_id @@ -437,8 +445,15 @@ - + + + + ns = customer_address_listing, index = customer_address_listing + ${ $.parentName } + + + ajax customer_address_edit 1 @@ -447,10 +462,16 @@ ${ $.parentName } ${ $.ns }.customer_address_form_data_source customer_address_form + + ${ $.externalProvider }:data.parent_id + + + ${ $.provider}:data.customer_id + - + false @@ -466,6 +487,8 @@ ${ $.provider }:data.customer.entity_id + ns = ${ $.ns }, index = actions:action + ns = ${ $.ns }, index = listing_massaction:massaction From 9f9f5189286db7439973b52f15354e74363b4284 Mon Sep 17 00:00:00 2001 From: Veronika Kurochkina Date: Thu, 8 Nov 2018 18:30:07 +0300 Subject: [PATCH 058/216] MAGETWO-91639: Tax is added despite customer group changes - Update automated test --- .../AdminDeleteCustomerGroupActionGroup.xml | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml index fd5cf8d43d8fb..b62a647ebdf62 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminDeleteCustomerGroupActionGroup.xml @@ -7,26 +7,20 @@ --> + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - - - - - - - - - - - - - - - - + + + + + + + + + + From 97da50434f0577ae602dfd79493323793f91baee Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Fri, 9 Nov 2018 10:42:59 +0200 Subject: [PATCH 059/216] MAGETWO-95249: [Part 1] Implement handling of large number of addresses on admin edit customer page - Add custom DataProvider for customer addresses listing; --- .../Listing/Address/DataProvider.php | 52 +++++++++++++++++++ .../ui_component/customer_address_listing.xml | 2 +- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php new file mode 100644 index 0000000000000..df92e7c1c9421 --- /dev/null +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -0,0 +1,52 @@ +collection = $collectionFactory->create(); + } + + /** + * Add country key for default billing/shipping blocks on customer addresses tab + * + * @return array + */ + public function getData(): array + { + $collection = $this->getCollection(); + $data = $collection->toArray(); + foreach ($data['items'] as $key => $item) { + if (isset($item['country_id']) && !isset($item['country'])) { + $data['items'][$key]['country'] = $item['country_id']; + } + } + + return $data; + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 6c97a6da5e9e2..7fb8c49749f2d 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -28,7 +28,7 @@ Magento_Customer::manage - + id entity_id From ebfffe494247b4f49d2fb127b7823999202c2b7a Mon Sep 17 00:00:00 2001 From: Ravi Chandra Date: Mon, 12 Nov 2018 14:33:04 +0530 Subject: [PATCH 060/216] Fixed subscribe to newsletter if you already have an account issue #8952 --- .../Magento/Newsletter/Controller/Subscriber/NewAction.php | 5 +++-- .../Magento/Newsletter/Controller/SubscriberTest.php | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php index fd2a61702e909..a9ef89070c659 100644 --- a/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php +++ b/app/code/Magento/Newsletter/Controller/Subscriber/NewAction.php @@ -77,8 +77,9 @@ public function __construct( protected function validateEmailAvailable($email) { $websiteId = $this->_storeManager->getStore()->getWebsiteId(); - if ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email - && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId) + if ($this->_customerSession->isLoggedIn() + && ($this->_customerSession->getCustomerDataObject()->getEmail() !== $email + && !$this->customerAccountManagement->isEmailAvailable($email, $websiteId)) ) { throw new LocalizedException( __('This email address is already assigned to another user.') diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php index 5347881f5e7d4..9dbf5c4d2a2a9 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/SubscriberTest.php @@ -57,7 +57,7 @@ public function testNewActionUsedEmail() $this->dispatch('newsletter/subscriber/new'); $this->assertSessionMessages($this->equalTo([ - 'There was a problem with the subscription: This email address is already assigned to another user.', + 'Thank you for your subscription.', ])); $this->assertRedirect($this->anything()); } From 479a95f1e3fb58044d23f15e904f221b2e017574 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov Date: Mon, 12 Nov 2018 15:01:31 +0200 Subject: [PATCH 061/216] MAGETWO-96208: Mass action "Delete" removes all addresses --- .../Controller/Adminhtml/Address/MassDelete.php | 8 +++++++- .../ResourceModel/Address/Grid/Collection.php | 16 ---------------- .../Component/Listing/Address/DataProvider.php | 14 +++++++++++++- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php index 09523f9e6a956..10638739f2b0a 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/MassDelete.php @@ -87,12 +87,18 @@ public function __construct( */ public function execute(): Json { + $customerData = $this->_session->getData('customer_data'); /** @var \Magento\Customer\Model\ResourceModel\Address\Collection $collection */ $collection = $this->filter->getCollection($this->collectionFactory->create()); - $collectionSize = $collection->getSize(); $error = false; try { + if ($customerData && $customerData['customer_id']) { + $collection->addFieldToFilter('parent_id', $customerData['customer_id']); + } else { + throw new \Exception(); + } + $collectionSize = $collection->getSize(); /** @var \Magento\Customer\Model\Address $address */ foreach ($collection as $address) { $this->addressRepository->deleteById($address->getId()); diff --git a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php index 09aef78b6cebc..b0e4c3d8dcc24 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Address/Grid/Collection.php @@ -76,22 +76,6 @@ public function __construct( ); } - /** - * Resource initialization - * - * @return $this - */ - protected function _initSelect() - { - parent::_initSelect(); - $parentId = $this->context->getRequestParam('parent_id'); - if ($parentId !== null) { - $this->getSelect()->where('parent_id=?', $parentId); - } - - return $this; - } - /** * @inheritdoc * diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php index df92e7c1c9421..e034e5a894e96 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -12,11 +12,17 @@ */ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider { + /** + * @var \Magento\Framework\App\RequestInterface $request, + */ + private $request; + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName * @param CollectionFactory $collectionFactory + * @param \Magento\Framework\App\RequestInterface $request * @param array $meta * @param array $data */ @@ -25,11 +31,13 @@ public function __construct( $primaryFieldName, $requestFieldName, CollectionFactory $collectionFactory, + \Magento\Framework\App\RequestInterface $request, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); $this->collection = $collectionFactory->create(); + $this->request = $request; } /** @@ -40,7 +48,11 @@ public function __construct( public function getData(): array { $collection = $this->getCollection(); - $data = $collection->toArray(); + $data['items'] = []; + if ($this->request->getParam('parent_id')) { + $collection->addFieldToFilter('parent_id', $this->request->getParam('parent_id')); + $data = $collection->toArray(); + } foreach ($data['items'] as $key => $item) { if (isset($item['country_id']) && !isset($item['country'])) { $data['items'][$key]['country'] = $item['country_id']; From 36bc920210d45be31dbd724e3cff1675feae8b63 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Mon, 12 Nov 2018 19:32:01 +0200 Subject: [PATCH 062/216] MAGETWO-96182: Adopt integration and API tests for implemented changes --- .../ui_component/customer_address_listing.xml | 26 ++++---- .../Controller/Adminhtml/Address/SaveTest.php | 60 +------------------ 2 files changed, 13 insertions(+), 73 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index 4db5a7fb8d545..b138a81e395a3 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -63,22 +63,20 @@ - - - - - true - - Are you sure to delete selected address? - Delete items - - - delete - Delete + + + + true + + Are you sure to delete selected address? + Delete items + + delete + Delete - - + + diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php index 5a4a426b58cda..cbfa794f94dc0 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/Adminhtml/Address/SaveTest.php @@ -89,19 +89,9 @@ public function testSaveActionWithValidAddressData() $this->assertSessionMessages($this->isEmpty(), \Magento\Framework\Message\MessageInterface::TYPE_ERROR); - /** - * Check that customer data were cleaned after it was saved successfully - */ + /** Check that customer data were cleaned after it was saved successfully*/ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - $customer = $this->customerRepository->getById($customerId); $this->assertEquals('Firstname', $customer->getFirstname()); @@ -148,14 +138,6 @@ public function testSaveActionWithDefaultShippingAndBilling() */ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - /** * Remove stored customer from registry */ @@ -204,50 +186,10 @@ public function testSaveActionWithExistingAdresses() */ $this->assertEmpty($this->objectManager->get(\Magento\Backend\Model\Session::class)->getCustomerData()); - /** - * Check that success message is set - */ - $this->assertSessionMessages( - $this->logicalNot($this->isEmpty()), - \Magento\Framework\Message\MessageInterface::TYPE_SUCCESS - ); - $customer = $this->customerRepository->getById($customerId); $this->assertEquals('test firstname', $customer->getFirstname()); $addresses = $customer->getAddresses(); $this->assertCount(4, $addresses); } - - /** - * @magentoDataFixture Magento/Customer/_files/customer.php - * @magentoDataFixture Magento/Customer/_files/customer_address.php - */ - public function testValidateCustomerWithAddressFailure() - { - $customer = $this->customerRepository->get('customer@example.com'); - $customerId = $customer->getId(); - $post = [ - 'parent_id' => $customerId, - 'firstname' => '', - 'lastname' => '', - 'street' => ['update street'], - 'city' => 'update city', - 'postcode' => '01001', - 'telephone' => '', - ]; - $this->getRequest()->setPostValue($post)->setMethod(HttpRequest::METHOD_POST); - - $this->objectManager->get(\Magento\Backend\Model\Session::class)->setCustomerFormData($post); - - $this->customerAddress->execute(); - - /** - * Check that errors was generated and set to session - */ - $this->assertSessionMessages( - $this->equalTo(['One or more input exceptions have occurred.']), - \Magento\Framework\Message\MessageInterface::TYPE_ERROR - ); - } } From 329f4194904dc0da6be8958278f5c9ebad2b54d5 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Mon, 12 Nov 2018 13:23:06 -0600 Subject: [PATCH 063/216] MAGETWO-96178: Customer addresses should be saved using Ajax --- .../Listing/Address/DataProvider.php | 10 +++++- .../ui_component/customer_address_form.xml | 4 +-- .../web/js/form/components/insert-listing.js | 36 +++++++++---------- .../adminhtml/web/js/form/element/country.js | 27 ++++++++++++++ .../adminhtml/web/js/form/element/region.js | 27 ++++++++++++++ .../view/adminhtml/web/js/grid/massactions.js | 3 +- .../web/template/default-address.html | 4 +-- 7 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php index e034e5a894e96..75f9dca9fd6cf 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/DataProvider.php @@ -17,12 +17,18 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider */ private $request; + /** + * @var \Magento\Directory\Model\CountryFactory + */ + private $countryDirectory; + /** * @param string $name * @param string $primaryFieldName * @param string $requestFieldName * @param CollectionFactory $collectionFactory * @param \Magento\Framework\App\RequestInterface $request + * @param \Magento\Directory\Model\CountryFactory $countryFactory, * @param array $meta * @param array $data */ @@ -32,11 +38,13 @@ public function __construct( $requestFieldName, CollectionFactory $collectionFactory, \Magento\Framework\App\RequestInterface $request, + \Magento\Directory\Model\CountryFactory $countryFactory, array $meta = [], array $data = [] ) { parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); $this->collection = $collectionFactory->create(); + $this->countryDirectory = $countryFactory->create(); $this->request = $request; } @@ -55,7 +63,7 @@ public function getData(): array } foreach ($data['items'] as $key => $item) { if (isset($item['country_id']) && !isset($item['country'])) { - $data['items'][$key]['country'] = $item['country_id']; + $data['items'][$key]['country'] = $this->countryDirectory->loadByCode($item['country_id'])->getName(); } } diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index bcc5b86c5e65d..4aeb7d67ace68 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -181,7 +181,7 @@
- + true @@ -196,7 +196,7 @@ - + true diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js index 0dd828b03b419..4e8952e9e2a9d 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-listing.js @@ -4,8 +4,9 @@ */ define([ - 'Magento_Ui/js/form/components/insert-listing' -], function (Insert) { + 'Magento_Ui/js/form/components/insert-listing', + 'underscore' +], function (Insert, _) { 'use strict'; return Insert.extend({ @@ -25,29 +26,28 @@ define([ }, deleteAction: function (data) { + this._delete([parseFloat(data[data['id_field_name']])]); + }, + + deleteMassaction: function (data) { + var ids = _.map(data, function (val) { + return parseFloat(val); + }); + + this._delete(ids); + }, + + _delete: function (ids) { var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); - if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { + if (ids.indexOf(defaultShippingId) !== -1) { this.source.set('data.default_shipping_address', []); } - if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { + + if (ids.indexOf(defaultBillingId) !== -1) { this.source.set('data.default_billing_address', []); } - }, - - //TODO: release logic with massaction - deleteMassaction: function (data) { - debugger; - // var defaultShippingId = parseFloat(this.source.get('data.default_shipping_address.entity_id')), - // defaultBillingId = parseFloat(this.source.get('data.default_billing_address.entity_id')); - // - // if (parseFloat(data[data['id_field_name']]) === defaultShippingId) { - // this.source.set('data.default_shipping_address', []); - // } - // if (parseFloat(data[data['id_field_name']]) === defaultBillingId) { - // this.source.set('data.default_billing_address', []); - // } } }); }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js new file mode 100644 index 0000000000000..bc60cf7a08fda --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/country.js @@ -0,0 +1,27 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/country' +], function (Country) { + 'use strict'; + + return Country.extend({ + defaults: { + countryScope: 'data.country' + }, + + setDifferedFromDefault: function (value) { + this._super(); + + if (value) { + this.source.set(this.countryScope, this.indexedOptions[value].label); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js new file mode 100644 index 0000000000000..a9013577a1026 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/element/region.js @@ -0,0 +1,27 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/** + * @api + */ +define([ + 'Magento_Ui/js/form/element/region' +], function (Region) { + 'use strict'; + + return Region.extend({ + defaults: { + regionScope: 'data.region' + }, + + setDifferedFromDefault: function (value) { + this._super(); + + if (parseFloat(value)) { + this.source.set(this.regionScope, this.indexedOptions[value].label); + } + } + }); +}); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js index 1aefa2e249958..2477ef2672e68 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/massactions.js @@ -49,11 +49,12 @@ define([ _.extend(selections, data.params || {}); + console.log(selections); this.request(action.url, selections).done(function (response) { if (!response.error) { this.trigger('massaction', { action: action.type, - data: selections + data: this.selections().selected() }); } }.bind(this)); diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 96158e9921e22..96de88a1145f4 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -16,8 +16,8 @@
- - + +
From ccda9172c70ddf00435641624d3814061e23f791 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Mon, 12 Nov 2018 16:55:54 -0600 Subject: [PATCH 064/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added condition --- .../Catalog/Controller/Adminhtml/Category/Index.php | 1 + .../GroupedProduct/Model/Product/Type/Grouped.php | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php index 5089b37f90c58..47969a4eca9ec 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php @@ -7,6 +7,7 @@ namespace Magento\Catalog\Controller\Adminhtml\Category; use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; +use Magento\Framework\Url\EncoderInterface; class Index extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface { diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index afa94e2b0b7a2..e54cb79b7b4e7 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -208,9 +208,10 @@ public function getParentIdsByChild($childId) * Retrieve array of associated products * * @param \Magento\Catalog\Model\Product $product + * @param bool $includeOutOfStock * @return array */ - public function getAssociatedProducts($product) + public function getAssociatedProducts($product, bool $includeOutOfStock = true) { if (!$product->hasData($this->_keyAssociatedProducts)) { $associatedProducts = []; @@ -228,7 +229,9 @@ public function getAssociatedProducts($product) ['in' => $this->getStatusFilters($product)] ); - $this->stockHelper->addIsInStockFilterToCollection($collection); + if (!$includeOutOfStock) { + $this->stockHelper->addIsInStockFilterToCollection($collection); + } foreach ($collection as $item) { $associatedProducts[] = $item; @@ -349,7 +352,7 @@ public function getAssociatedProductCollection($product) protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $product, $isStrictProcessMode) { $productsInfo = $buyRequest->getSuperGroup() ?: []; - $associatedProducts = $this->getAssociatedProducts($product); + $associatedProducts = $this->getAssociatedProducts($product, !empty($productsInfo)); if (!is_array($productsInfo)) { return __('Please specify the quantity of product(s).')->render(); From ffa44b557173be5fec38dac0494c42925e2ae677 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy Date: Tue, 13 Nov 2018 10:50:09 +0200 Subject: [PATCH 065/216] MAGETWO-96182: Adopt integration and API tests for implemented changes - Change mass delete action in customer address listing structure; --- .../ui_component/customer_address_listing.xml | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml index b138a81e395a3..6d59977cda140 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_listing.xml @@ -63,20 +63,18 @@
- - - - true - - Are you sure to delete selected address? - Delete items - - - delete - Delete - - - + + + true + + Are you sure to delete selected address? + Delete items + + + delete + + + From 6afe3938708a4c166dfab30e60f7793e1b236963 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Tue, 13 Nov 2018 09:36:53 -0600 Subject: [PATCH 066/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Added test for admin grid --- .../Test/AdminGroupedProductsListTest.xml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml new file mode 100644 index 0000000000000..b59cf1e2175d8 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminGroupedProductsListTest.xml @@ -0,0 +1,73 @@ + + + + + + + + + + <description value="Products in group should show in admin list even when they are out of stock"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-93181"/> + <group value="GroupedProduct"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="category1"/> + <createData entity="SimpleProduct" stepKey="simpleProduct1"> + <requiredEntity createDataKey="category1"/> + </createData> + <!--Out of Stock--> + <createData entity="SimpleProduct4" stepKey="simpleProduct2"> + <requiredEntity createDataKey="category1"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <deleteData createDataKey="category1" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!-- Create product --> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageAdd"/> + <waitForPageLoad stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProductPage"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="fillGroupedProductForm" stepKey="fillMainProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <!-- Add two simple products to grouped product --> + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductSection"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> + <waitForElementVisible selector="{{AdminAddProductsToGroupPanel.filters}}" stepKey="waitForFilter"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku1"> + <argument name="product" value="$$simpleProduct1$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToGroupPanel.firstCheckbox}}" stepKey="checkOption1"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridBySku2"> + <argument name="product" value="$$simpleProduct2$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToGroupPanel.firstCheckbox}}" stepKey="checkOption2"/> + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="addSelectedProducts"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + + <!-- Save product --> + <actionGroup ref="saveProductForm" stepKey="saveProductForm"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToProducts"/> + + <waitForText userInput="$$simpleProduct1.name$$" stepKey="assertProductIsInTheList"/> + <waitForText userInput="$$simpleProduct2.name$$" stepKey="assertProduct2IsInTheList"/> + </test> +</tests> From 1cb7ad9ec01b3735485e8edbe298a535c600f1ca Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Tue, 13 Nov 2018 09:39:57 -0600 Subject: [PATCH 067/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Static fixed --- .../Magento/Catalog/Controller/Adminhtml/Category/Index.php | 4 +++- .../Magento/GroupedProduct/Model/Product/Type/Grouped.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php index 47969a4eca9ec..a5be6223bee75 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Index.php @@ -7,8 +7,10 @@ namespace Magento\Catalog\Controller\Adminhtml\Category; use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; -use Magento\Framework\Url\EncoderInterface; +/** + * Controller for category listing + */ class Index extends \Magento\Catalog\Controller\Adminhtml\Category implements HttpGetActionInterface { /** diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index e54cb79b7b4e7..2f8249397819a 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -230,7 +230,7 @@ public function getAssociatedProducts($product, bool $includeOutOfStock = true) ); if (!$includeOutOfStock) { - $this->stockHelper->addIsInStockFilterToCollection($collection); + $this->stockHelper->addIsInStockFilterToCollection($collection); } foreach ($collection as $item) { From 08ac92e88a9420e358818f29091723454d937f9c Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 13 Nov 2018 19:02:27 +0200 Subject: [PATCH 068/216] MAGETWO-96306: Customer address street data is displayed incorrectly on default billing/shipping blocks --- .../Customer/view/adminhtml/web/template/default-address.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html index 96de88a1145f4..1dd583b990202 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address.html @@ -17,7 +17,8 @@ </if> <if args="address.street"> <text args="address.street" if="_.isString(address.street)"/> - <text args="_.values(address.street).join(', ')" ifnot="_.isString(address.street)"/> + <text args="_.values(address.street).filter(value => _.isString(value)).join(', ')" + ifnot="_.isString(address.street)"/> <br/> </if> <text args="address.city + ', '" if="address.city"/> From ce1a7cec2053f19753c5b003fae74d538428a7ee Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Tue, 13 Nov 2018 19:31:29 +0200 Subject: [PATCH 069/216] MAGETWO-96209: Customer address grid actions send GET instead of POST request --- .../Magento/Customer/Controller/Adminhtml/Address/Delete.php | 4 ++-- .../Customer/Ui/Component/Listing/Address/Column/Actions.php | 1 + .../Customer/view/adminhtml/web/js/grid/columns/actions.js | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 65da3bca49e9b..711cd2473cdc5 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,7 +8,7 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; @@ -17,7 +17,7 @@ /** * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpGetActionInterface +class Delete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 490a14169e7b7..7da6d3a6a86c5 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -113,6 +113,7 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), + 'post' => true, 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js index 43ab06c8014ee..4a62ce2e6eccf 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -18,8 +18,9 @@ define([ return Actions.extend({ defaults: { ajaxSettings: { - method: 'GET', - dataType: 'json' + method: 'POST', + dataType: 'json', + formKey: $('input[name="form_key"]').val() }, listens: { action: 'onAction' From f6a6d11bc0219bc4847745d264f8991d04d5372e Mon Sep 17 00:00:00 2001 From: Graham Wharton <graham@gwharton.me.uk> Date: Tue, 13 Nov 2018 20:00:59 +0000 Subject: [PATCH 070/216] Made logo clickable on home page --- .../frontend/templates/html/header/logo.phtml | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml index 17f8d7c70f574..79b891b7e55e6 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/header/logo.phtml @@ -12,19 +12,11 @@ ?> <?php $storeName = $block->getThemeName() ? $block->getThemeName() : $block->getLogoAlt();?> <span data-action="toggle-nav" class="action nav-toggle"><span><?= /* @escapeNotVerified */ __('Toggle Nav') ?></span></span> -<?php if ($block->isHomePage()):?> - <strong class="logo"> -<?php else: ?> - <a class="logo" href="<?= $block->getUrl('') ?>" title="<?= /* @escapeNotVerified */ $storeName ?>"> -<?php endif ?> - <img src="<?= /* @escapeNotVerified */ $block->getLogoSrc() ?>" - title="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" - alt="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" - <?= $block->getLogoWidth() ? 'width="' . $block->getLogoWidth() . '"' : '' ?> - <?= $block->getLogoHeight() ? 'height="' . $block->getLogoHeight() . '"' : '' ?> - /> -<?php if ($block->isHomePage()):?> - </strong> -<?php else:?> - </a> -<?php endif?> +<a class="logo" href="<?= $block->getUrl('') ?>" title="<?= /* @escapeNotVerified */ $storeName ?>"> + <img src="<?= /* @escapeNotVerified */ $block->getLogoSrc() ?>" + title="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" + alt="<?= /* @escapeNotVerified */ $block->getLogoAlt() ?>" + <?= $block->getLogoWidth() ? 'width="' . $block->getLogoWidth() . '"' : '' ?> + <?= $block->getLogoHeight() ? 'height="' . $block->getLogoHeight() . '"' : '' ?> + /> +</a> From cefc00668a9ccf72308c17e5a38aa8349e0d9058 Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Wed, 14 Nov 2018 11:55:58 +0200 Subject: [PATCH 071/216] MAGETWO-96209: Customer address grid actions send GET instead of POST request - Pass form key parameter for post action in ajax request; - Add comments; --- .../Address/AbstractDefaultAddress.php | 4 ++-- .../Listing/Address/Column/Actions.php | 1 - .../adminhtml/web/js/grid/columns/actions.js | 18 +++++++++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php index 9ec38f4929a87..64062139ef0fb 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/AbstractDefaultAddress.php @@ -9,7 +9,7 @@ use Magento\Backend\App\Action; use Magento\Customer\Api\AddressRepositoryInterface; -use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Framework\Phrase; @@ -18,7 +18,7 @@ /** * Abstract class for customer default addresses changing */ -abstract class AbstractDefaultAddress extends Action implements HttpGetActionInterface +abstract class AbstractDefaultAddress extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php index 7da6d3a6a86c5..490a14169e7b7 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Address/Column/Actions.php @@ -113,7 +113,6 @@ public function prepareDataSource(array $dataSource): array ['parent_id' => $item['parent_id'], 'id' => $item['entity_id']] ), 'label' => __('Delete'), - 'post' => true, 'isAjax' => true, 'confirm' => [ 'title' => __('Delete address'), diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js index 4a62ce2e6eccf..405e3e4b0dc69 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/grid/columns/actions.js @@ -19,14 +19,18 @@ define([ defaults: { ajaxSettings: { method: 'POST', - dataType: 'json', - formKey: $('input[name="form_key"]').val() + dataType: 'json' }, listens: { action: 'onAction' } }, + /** + * Reload customer address listing data source after customer address delete action + * + * @param {Object} data + */ onAction: function (data) { if (data.action === 'delete') { this.source().reload({ @@ -66,9 +70,17 @@ define([ } }, + /** + * Send customer address listing ajax request + * + * @param {String} href + */ request: function (href) { var settings = _.extend({}, this.ajaxSettings, { - url: href + url: href, + data: { + 'form_key': window.FORM_KEY + } }); $('body').trigger('processStart'); From 7b6917c2ce5c19edc2d293a40a7c1b39b1aa1060 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Wed, 14 Nov 2018 16:48:20 +0200 Subject: [PATCH 072/216] MAGETWO-96222: Apply Category Permissions to Website 2 --- .../Test/Mftf/ActionGroup/AdminProductActionGroup.xml | 1 - .../Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml | 1 - .../Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml | 5 +++-- app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml | 1 + app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml index dce3c72106c51..4084a2871b62f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductActionGroup.xml @@ -121,7 +121,6 @@ <argument name="simpleProduct"/> </arguments> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> - <waitForPageLoad stepKey="waitForPageLoad"/> <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> <fillField userInput="{{simpleProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 1bd9bb4a09c86..94400b2208b8b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -172,7 +172,6 @@ </arguments> <!--TODO use other action group for filtering grid when MQE-539 is implemented --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> - <waitForPageLoad time="60" stepKey="waitForPageLoadInitial"/> <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{sku}}" stepKey="fillProductSkuFilter"/> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml index b21c79692a7cf..32e137c336cb3 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml @@ -10,14 +10,15 @@ <actionGroup name="AdminCreateStoreGroupActionGroup"> <arguments> <argument name="Website" defaultValue="_defaultWebsite"/> + <argument name="storeGroup" defaultValue="CustomStoreGroupCustomWebsite"/> </arguments> <amOnPage url="{{AdminSystemStoreGroupPage.url}}" stepKey="navigateToNewStoreGroup"/> <waitForPageLoad stepKey="waitForStoreGroupPageLoad" /> <comment userInput="Creating Store Group" stepKey="storeGroupCreationComment" /> <selectOption selector="{{AdminNewStoreGroupSection.storeGrpWebsiteDropdown}}" userInput="{{Website.name}}" stepKey="selectWebsite" /> - <fillField selector="{{AdminNewStoreGroupSection.storeGrpNameTextField}}" userInput="{{CustomStoreGroupCustomWebsite.name}}" stepKey="enterStoreGroupName" /> - <fillField selector="{{AdminNewStoreGroupSection.storeGrpCodeTextField}}" userInput="{{CustomStoreGroupCustomWebsite.code}}" stepKey="enterStoreGroupCode" /> + <fillField selector="{{AdminNewStoreGroupSection.storeGrpNameTextField}}" userInput="{{storeGroup.name}}" stepKey="enterStoreGroupName" /> + <fillField selector="{{AdminNewStoreGroupSection.storeGrpCodeTextField}}" userInput="{{storeGroup.code}}" stepKey="enterStoreGroupCode" /> <selectOption selector="{{AdminNewStoreGroupSection.storeRootCategoryDropdown}}" userInput="Default Category" stepKey="setRootCategory" /> <click selector="{{AdminNewStoreGroupActionsSection.saveButton}}" stepKey="clickSaveStoreGroup" /> <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" stepKey="waitForPageReload"/> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml index 7b31623f237e9..ce8336e23fc01 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml @@ -31,4 +31,5 @@ <data key="name">NewStore</data> <data key="code">Base1</data> </entity> + <entity name="customStoreGroup2" extends="customStoreGroup" type="group"/> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index ee137d78d7fd2..70b018907ee99 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,4 +19,5 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> + <entity name="customWebsite2" extends="customWebsite" type="website"/> </entities> From c9f4db3d2421f3b3b8b648e6c9aac129cd68330b Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Wed, 14 Nov 2018 16:58:11 +0200 Subject: [PATCH 073/216] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 32 +++++++++-- .../Controller/Adminhtml/Address/Delete.php | 3 +- .../ui_component/customer_address_form.xml | 2 +- .../adminhtml/web/js/form/components/form.js | 53 +++++++++++++++++++ 4 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 8375aa13fdeff..88392139d137e 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -23,14 +23,36 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface public function getButtonData() { $data = []; + $confirm = __('Are you sure you want to delete this address?'); if ($this->getAddressId()) { $data = [ 'label' => __('Delete'), - 'class' => 'delete', - 'on_click' => 'deleteConfirm(\'' . __( - 'Are you sure you want to delete this address?' - ) . '\', \'' . $this->getDeleteUrl() . '\')', - 'sort_order' => 15, + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'customer_address_form.customer_address_form', + 'actionName' => 'delete', + 'params' => [ + $this->getDeleteUrl(), + ], + + ], + [ + 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', + 'actionName' => 'closeModal' + ], + [ + 'targetName' => 'customer_address_listing.customer_address_listing', + 'actionName' => 'reload' + ] + ], + ], + ], + ], + 'sort_order' => 20 ]; } return $data; diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index 65da3bca49e9b..d14cf86e4084e 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -9,6 +9,7 @@ use Magento\Backend\App\Action; use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; use Magento\Customer\Api\AddressRepositoryInterface; @@ -17,7 +18,7 @@ /** * Button for deletion of customer address in admin */ -class Delete extends Action implements HttpGetActionInterface +class Delete extends Action implements HttpPostActionInterface { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 4aeb7d67ace68..8e61c458fb812 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -5,7 +5,7 @@ * See COPYING.txt for license details. */ --> -<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> +<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd" component="Magento_Customer/js/form/components/form"> <argument name="data" xsi:type="array"> <item name="js_config" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js new file mode 100644 index 0000000000000..893388a869090 --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -0,0 +1,53 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +define([ + 'jquery', + 'Magento_Ui/js/modal/alert', + 'Magento_Ui/js/form/form', + 'mage/translate' +], function ($, uiAlert, Form, $t) { + 'use strict'; + + return Form.extend({ + defaults: { + ajaxSettings: { + method: 'POST', + dataType: 'json' + } + }, + + /** + * Perform asynchronous DELETE request to server. + * @param {String} url - ajax url + * @returns {Deferred} + */ + delete: function (url) { + var settings = _.extend({}, this.ajaxSettings, { + url: url, + data: { + 'form_key': window.FORM_KEY + } + }); + + return $.ajax(settings) + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); + + } + }); +}); From 62fa0e82be34ad04bc0cc4308fd41bbd32ba34c6 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 09:50:24 -0600 Subject: [PATCH 074/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - converted change to be backwards compatible --- .../Model/Product/Type/Grouped.php | 94 +++++++++++++------ 1 file changed, 65 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 2f8249397819a..8fc0b856ca46d 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -10,6 +10,7 @@ use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Framework\App\ObjectManager; use Magento\CatalogInventory\Helper\Stock as StockHelper; +use \Magento\Catalog\Model\Product; /** * Grouped product type model @@ -29,6 +30,13 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $_keyAssociatedProducts = '_cache_instance_associated_products'; + /** + * Cache key for Associated Products that are in stock + * + * @var string + */ + protected $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; + /** * Cache key for Associated Product Ids * @@ -205,39 +213,15 @@ public function getParentIdsByChild($childId) } /** - * Retrieve array of associated products + * Retrieve array of associated products excluding those that are out of stock * * @param \Magento\Catalog\Model\Product $product - * @param bool $includeOutOfStock * @return array */ - public function getAssociatedProducts($product, bool $includeOutOfStock = true) + public function getAssociatedProducts($product) { if (!$product->hasData($this->_keyAssociatedProducts)) { - $associatedProducts = []; - - $this->setSaleableStatus($product); - - $collection = $this->getAssociatedProductCollection( - $product - )->addAttributeToSelect( - ['name', 'price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'] - )->addFilterByRequiredOptions()->setPositionOrder()->addStoreFilter( - $this->getStoreFilter($product) - )->addAttributeToFilter( - 'status', - ['in' => $this->getStatusFilters($product)] - ); - - if (!$includeOutOfStock) { - $this->stockHelper->addIsInStockFilterToCollection($collection); - } - - foreach ($collection as $item) { - $associatedProducts[] = $item; - } - - $product->setData($this->_keyAssociatedProducts, $associatedProducts); + $this->assignAssociatedProducts($product, true); } return $product->getData($this->_keyAssociatedProducts); } @@ -352,7 +336,9 @@ public function getAssociatedProductCollection($product) protected function getProductInfo(\Magento\Framework\DataObject $buyRequest, $product, $isStrictProcessMode) { $productsInfo = $buyRequest->getSuperGroup() ?: []; - $associatedProducts = $this->getAssociatedProducts($product, !empty($productsInfo)); + $associatedProducts = empty($productsInfo) + ? $this->getInStockAssociatedProducts($product) + : $this->getAssociatedProducts($product); if (!is_array($productsInfo)) { return __('Please specify the quantity of product(s).')->render(); @@ -391,7 +377,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p return $productsInfo; } $associatedProducts = !$isStrictProcessMode || !empty($productsInfo) - ? $this->getAssociatedProducts($product) + ? $this->getInStockAssociatedProducts($product) : false; foreach ($associatedProducts as $subProduct) { @@ -524,4 +510,54 @@ public function getChildrenMsrp(\Magento\Catalog\Model\Product $product) } return $prices ? min($prices) : 0; } + + /** + * Retrieve array of associated products that are out in stock + * + * @param \Magento\Catalog\Model\Product $product + * @return array + */ + private function getInStockAssociatedProducts($product) + { + if (!$product->hasData($this->_keyInStockAssociatedProducts)) { + $this->assignAssociatedProducts($product, false); + } + return $product->getData($this->_keyInStockAssociatedProducts); + } + + /** + * Caches associated products to the product optionally including out of stock items + * + * @param Product $product + * @param bool $includeOutOfStock + */ + private function assignAssociatedProducts(Product $product, bool $includeOutOfStock = true): void + { + $associatedProducts = []; + + $this->setSaleableStatus($product); + + $collection = $this->getAssociatedProductCollection( + $product + )->addAttributeToSelect( + ['name', 'price', 'special_price', 'special_from_date', 'special_to_date', 'tax_class_id'] + )->addFilterByRequiredOptions()->setPositionOrder()->addStoreFilter( + $this->getStoreFilter($product) + )->addAttributeToFilter( + 'status', + ['in' => $this->getStatusFilters($product)] + ); + + if (!$includeOutOfStock) { + $this->stockHelper->addIsInStockFilterToCollection($collection); + } + + foreach ($collection as $item) { + $associatedProducts[] = $item; + } + + $cacheKey = $includeOutOfStock ? $this->_keyAssociatedProducts : $this->_keyInStockAssociatedProducts; + + $product->setData($cacheKey, $associatedProducts); + } } From ea3f224f63215e9ad1d109cae71243a043cb0b52 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 09:56:26 -0600 Subject: [PATCH 075/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Fixed description --- app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 8fc0b856ca46d..399309c9c2f19 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -213,7 +213,7 @@ public function getParentIdsByChild($childId) } /** - * Retrieve array of associated products excluding those that are out of stock + * Retrieve array of associated products including those that are out of stock * * @param \Magento\Catalog\Model\Product $product * @return array From e9e2551c43ff513d28350ba4dbeb7c89f036b781 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko <omiroshnichenko@magento.com> Date: Wed, 14 Nov 2018 10:39:47 -0600 Subject: [PATCH 076/216] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 10 +-- .../ui_component/customer_address_form.xml | 3 + .../adminhtml/web/js/form/components/form.js | 69 ++++++++++++------- .../web/js/form/components/insert-form.js | 8 +++ .../view/base/ui_component/customer_form.xml | 1 + 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 88392139d137e..7296a5167622a 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -34,19 +34,11 @@ public function getButtonData() 'actions' => [ [ 'targetName' => 'customer_address_form.customer_address_form', - 'actionName' => 'delete', + 'actionName' => 'deleteAddress', 'params' => [ $this->getDeleteUrl(), ], - ], - [ - 'targetName' => 'customer_form.areas.address.address.customer_address_update_modal', - 'actionName' => 'closeModal' - ], - [ - 'targetName' => 'customer_address_listing.customer_address_listing', - 'actionName' => 'reload' ] ], ], diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index 8e61c458fb812..afe2396a9062f 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -10,6 +10,9 @@ <item name="js_config" xsi:type="array"> <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> </item> + <item name="config" xsi:type="array"> + <item name="confirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> + </item> <item name="label" xsi:type="string" translate="true">Update Address</item> <item name="reverseMetadataMerge" xsi:type="boolean">true</item> <item name="template" xsi:type="string">templates/form/collapsible</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js index 893388a869090..34cbbfefce368 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -5,48 +5,69 @@ define([ 'jquery', 'Magento_Ui/js/modal/alert', + 'Magento_Ui/js/modal/confirm', 'Magento_Ui/js/form/form', 'mage/translate' -], function ($, uiAlert, Form, $t) { +], function ($, uiAlert, uiConfirm, Form, $t) { 'use strict'; return Form.extend({ defaults: { + confirmationMessage: '', ajaxSettings: { - method: 'POST', - dataType: 'json' + method: 'POST', + dataType: 'json' } }, + deleteAddress: function (url) { + var that = this; + + uiConfirm({ + content: this.confirmationMessage, + actions: { + /** @inheritdoc */ + confirm: function () { + that._delete(url); + } + } + }); + }, + /** * Perform asynchronous DELETE request to server. * @param {String} url - ajax url * @returns {Deferred} */ - delete: function (url) { + _delete: function (url) { var settings = _.extend({}, this.ajaxSettings, { - url: url, - data: { - 'form_key': window.FORM_KEY - } - }); + url: url, + data: { + 'form_key': window.FORM_KEY + } + }), + that = this; + + $('body').trigger('processStart'); return $.ajax(settings) - .done(function (response) { - if (response.error) { - uiAlert({ - content: response.message - }); - } - }) - .fail(function () { - uiAlert({ - content: $t('Sorry, there has been an error processing your request. Please try again later.') - }); - }) - .always(function () { - $('body').trigger('processStop'); - }); + .done(function (response) { + if (response.error) { + uiAlert({ + content: response.message + }); + } else { + that.trigger('deleteAddressAction', that.source.get('data.entity_id')); + } + }) + .fail(function () { + uiAlert({ + content: $t('Sorry, there has been an error processing your request. Please try again later.') + }); + }) + .always(function () { + $('body').trigger('processStop'); + }); } }); diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js index 25303899894c4..59c3e8e4b8b0b 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -50,6 +50,14 @@ define([ ) { this.source.set('data.default_shipping_address', []); } + }, + + onAddressDelete: function (id) { + this.addressModal().closeModal(); + this.addressListing().reload({ + refresh: true + }); + this.addressListing()._delete([parseFloat(id)]); } }); }); diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index d6d61c892e00d..a7c55da2cca2f 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -467,6 +467,7 @@ </exports> <imports> <link name="parentId">${ $.provider}:data.customer_id</link> + <link name="onAddressDelete">${ $.ns }.${ $.ns }:deleteAddressAction</link> </imports> </settings> </insertForm> From b05611c12ee10bfc2268a1dd14398fe756dc8a04 Mon Sep 17 00:00:00 2001 From: Nathan Smith <nathsmit@adobe.com> Date: Wed, 14 Nov 2018 12:07:28 -0600 Subject: [PATCH 077/216] MAGETWO-93181: Grouped product doesn't take care about his Linked Products when SalableQuantity < ProductLink.ExtensionAttributes.Qty after Source Deduction - Marked new property as private --- .../GroupedProduct/Model/Product/Type/Grouped.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php index 399309c9c2f19..0bbadaa1ba869 100644 --- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php @@ -30,13 +30,6 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ protected $_keyAssociatedProducts = '_cache_instance_associated_products'; - /** - * Cache key for Associated Products that are in stock - * - * @var string - */ - protected $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; - /** * Cache key for Associated Product Ids * @@ -101,6 +94,13 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType */ private $stockHelper; + /** + * Cache key for Associated Products that are in stock + * + * @var string + */ + private $_keyInStockAssociatedProducts = '_cache_instance_in_stock_associated_products'; + /** * @param \Magento\Catalog\Model\Product\Option $catalogProductOption * @param \Magento\Eav\Model\Config $eavConfig From bd5456f00d2458c5a9f1f6a6446bec66f3ea7f2e Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 08:49:48 +0200 Subject: [PATCH 078/216] MAGETWO-96222: Apply Category Permissions to Website 2 --- ...upActionGroup.xml => AdminStoreGroupCreateActionGroup.xml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename app/code/Magento/Store/Test/Mftf/ActionGroup/{AdminCreateStoreGroupActionGroup.xml => AdminStoreGroupCreateActionGroup.xml} (91%) diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml similarity index 91% rename from app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml rename to app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml index 32e137c336cb3..023d5fc3587fb 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreGroupActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminStoreGroupCreateActionGroup.xml @@ -7,10 +7,10 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateStoreGroupActionGroup"> + <actionGroup name="AdminStoreGroupCreateActionGroup"> <arguments> <argument name="Website" defaultValue="_defaultWebsite"/> - <argument name="storeGroup" defaultValue="CustomStoreGroupCustomWebsite"/> + <argument name="storeGroup"/> </arguments> <amOnPage url="{{AdminSystemStoreGroupPage.url}}" stepKey="navigateToNewStoreGroup"/> <waitForPageLoad stepKey="waitForStoreGroupPageLoad" /> From 4ad77022371d7572dfb8944f46e5c1dab11722e2 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 02:52:34 -0800 Subject: [PATCH 079/216] MAGETWO-96222: Apply Category Permissions to Website 2 --- .../Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml | 2 +- app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml | 1 - app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 5 ++++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml index 9349e188430f4..f7d8abf8b2fea 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryPage.xml @@ -8,7 +8,7 @@ <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> - <page name="AdminCategoryPage" url="catalog/category/" area="admin" module="Catalog"> + <page name="AdminCategoryPage" url="catalog/category/" area="admin" module="Magento_Catalog"> <section name="AdminCategorySidebarActionSection"/> <section name="AdminCategoryMainActionsSection"/> <section name="AdminCategorySidebarTreeSection"/> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml index ce8336e23fc01..7b31623f237e9 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml @@ -31,5 +31,4 @@ <data key="name">NewStore</data> <data key="code">Base1</data> </entity> - <entity name="customStoreGroup2" extends="customStoreGroup" type="group"/> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index 70b018907ee99..c1a8a552c3a97 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,5 +19,8 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> - <entity name="customWebsite2" extends="customWebsite" type="website"/> + <entity name="secondCustomWebsite" extends="customWebsite" type="website"> + <data key="name" unique="suffix">Second Custom Website</data> + <data key="code" unique="suffix">second_custom_website</data> + </entity> </entities> From 715ae96da3204d41be0590c9dcada03b8f8892f3 Mon Sep 17 00:00:00 2001 From: DmytroPaidych <dimonovp@gmail.com> Date: Thu, 15 Nov 2018 06:10:19 -0800 Subject: [PATCH 080/216] MAGETWO-96222: Apply Category Permissions to Website 2 --- app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml index c1a8a552c3a97..f636336524f01 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/WebsiteData.xml @@ -19,8 +19,8 @@ <data key="store_type">website</data> <data key="website_id">null</data> </entity> - <entity name="secondCustomWebsite" extends="customWebsite" type="website"> - <data key="name" unique="suffix">Second Custom Website</data> - <data key="code" unique="suffix">second_custom_website</data> + <entity name="secondCustomWebsite" extends="customWebsite"> + <data key="name" unique="suffix">Custom Website</data> + <data key="code" unique="suffix">custom_website</data> </entity> </entities> From d15cca6755976100b4559351594bd5fa8f22d832 Mon Sep 17 00:00:00 2001 From: Leonid Poluyanov <lpoluyanov@magento.com> Date: Thu, 15 Nov 2018 15:32:22 +0200 Subject: [PATCH 081/216] MAGETWO-96312: Delete Address button on customer address modal does not close and returns json --- .../Adminhtml/Edit/Address/DeleteButton.php | 3 +- .../Controller/Adminhtml/Address/Delete.php | 1 - .../Edit/Address/DeleteButtonTest.php | 106 ++++++++++++++++++ .../ui_component/customer_address_form.xml | 2 +- .../adminhtml/web/js/form/components/form.js | 11 +- .../web/js/form/components/insert-form.js | 6 + .../js/view/form/components/form.test.js | 71 ++++++++++++ 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js diff --git a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php index 7296a5167622a..da589a25df28e 100644 --- a/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php +++ b/app/code/Magento/Customer/Block/Adminhtml/Edit/Address/DeleteButton.php @@ -23,7 +23,6 @@ class DeleteButton extends GenericButton implements ButtonProviderInterface public function getButtonData() { $data = []; - $confirm = __('Are you sure you want to delete this address?'); if ($this->getAddressId()) { $data = [ 'label' => __('Delete'), @@ -56,7 +55,7 @@ public function getButtonData() * @return string * @throws \Magento\Framework\Exception\LocalizedException */ - public function getDeleteUrl(): string + private function getDeleteUrl(): string { return $this->getUrl( Actions::CUSTOMER_ADDRESS_PATH_DELETE, diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php index d14cf86e4084e..711cd2473cdc5 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Delete.php @@ -8,7 +8,6 @@ namespace Magento\Customer\Controller\Adminhtml\Address; use Magento\Backend\App\Action; -use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\Result\Json; use Magento\Framework\Controller\Result\JsonFactory; diff --git a/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php b/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php new file mode 100644 index 0000000000000..7b0da3bd422a6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Block/Adminhtml/Edit/Address/DeleteButtonTest.php @@ -0,0 +1,106 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Customer\Test\Unit\Block\Adminhtml\Edit\Address; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Class for \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton unit tests + */ +class DeleteButtonTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Customer\Model\AddressFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressFactory; + + /** + * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $urlBuilder; + + /** + * @var \Magento\Customer\Model\ResourceModel\Address|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressResourceModel; + + /** + * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $request; + + /** + * @var \Magento\Customer\Model\ResourceModel\AddressRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $addressRepository; + + /** + * @var \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton + */ + private $deleteButton; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->addressFactory = $this->getMockBuilder(\Magento\Customer\Model\AddressFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->urlBuilder = $this->getMockForAbstractClass(\Magento\Framework\UrlInterface::class); + $this->addressResourceModel = $this->getMockBuilder(\Magento\Customer\Model\ResourceModel\Address::class) + ->disableOriginalConstructor() + ->getMock(); + $this->request = $this->getMockForAbstractClass(\Magento\Framework\App\RequestInterface::class); + $this->addressRepository = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\AddressRepository::class + ) + ->disableOriginalConstructor() + ->getMock(); + $objectManagerHelper = new ObjectManagerHelper($this); + + $this->deleteButton = $objectManagerHelper->getObject( + \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton::class, + [ + 'addressFactory' => $this->addressFactory, + 'urlBuilder' => $this->urlBuilder, + 'addressResourceModel' => $this->addressResourceModel, + 'request' => $this->request, + 'addressRepository' => $this->addressRepository, + ] + ); + } + + /** + * Unit test for \Magento\Customer\Block\Adminhtml\Edit\Address\DeleteButton::getButtonData() method + */ + public function testGetButtonData() + { + $addressId = 1; + $customerId = 2; + + /** @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->disableOriginalConstructor() + ->getMock(); + $address->expects($this->atLeastOnce())->method('getEntityId')->willReturn($addressId); + $address->expects($this->atLeastOnce())->method('getCustomerId')->willReturn($customerId); + $this->addressFactory->expects($this->atLeastOnce())->method('create')->willReturn($address); + $this->request->expects($this->atLeastOnce())->method('getParam')->with('entity_id') + ->willReturn($addressId); + $this->addressResourceModel->expects($this->atLeastOnce())->method('load')->with($address, $addressId); + $this->addressRepository->expects($this->atLeastOnce())->method('getById')->with($addressId) + ->willReturn($address); + $this->urlBuilder->expects($this->atLeastOnce())->method('getUrl') + ->with( + \Magento\Customer\Ui\Component\Listing\Address\Column\Actions::CUSTOMER_ADDRESS_PATH_DELETE, + ['parent_id' => $customerId, 'id' => $addressId] + )->willReturn('url'); + + $buttonData = $this->deleteButton->getButtonData(); + $this->assertEquals('Delete', (string)$buttonData['label']); + } +} diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index afe2396a9062f..fdef0e959443b 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -11,7 +11,7 @@ <item name="provider" xsi:type="string">customer_address_form.customer_address_form_data_source</item> </item> <item name="config" xsi:type="array"> - <item name="confirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> + <item name="deleteConfirmationMessage" translate="true" xsi:type="string">Are you sure you want to delete this address?</item> </item> <item name="label" xsi:type="string" translate="true">Update Address</item> <item name="reverseMetadataMerge" xsi:type="boolean">true</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js index 34cbbfefce368..e1c5f01c731a0 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/form.js @@ -13,18 +13,25 @@ define([ return Form.extend({ defaults: { - confirmationMessage: '', + deleteConfirmationMessage: '', ajaxSettings: { method: 'POST', dataType: 'json' } }, + /** + * Delete customer address by provided url. + * Will call confirmation message to be sure that user is really wants to delete this address + * + * @param {String} url - ajax url + */ deleteAddress: function (url) { + console.log(url); var that = this; uiConfirm({ - content: this.confirmationMessage, + content: this.deleteConfirmationMessage, actions: { /** @inheritdoc */ confirm: function () { diff --git a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js index 59c3e8e4b8b0b..45d0ff112f096 100644 --- a/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js +++ b/app/code/Magento/Customer/view/adminhtml/web/js/form/components/insert-form.js @@ -52,6 +52,12 @@ define([ } }, + /** + * Event method that closes "Edit customer address" modal and refreshes grid after customer address + * was removed through "Delete" button on the "Edit customer address" modal + * + * @param {string} id - customer address ID to delete + */ onAddressDelete: function (id) { this.addressModal().closeModal(); this.addressListing().reload({ diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js new file mode 100644 index 0000000000000..99ce913e87390 --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Customer/adminhtml/js/view/form/components/form.test.js @@ -0,0 +1,71 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'uiRegistry', + 'Magento_Customer/js/form/components/form', + 'jquery' +], function (_, registry, Constr, $) { + 'use strict'; + + describe('Magento_Customer/js/form/components/form', function () { + + var obj, + originaljQueryAjax; + + beforeEach (function () { + originaljQueryAjax = $.ajax; + obj = new Constr({ + provider: 'provName', + name: '', + index: '' + }); + }); + + afterEach(function () { + $.ajax = originaljQueryAjax; + }); + + registry.set('provName', { + /** Stub */ + on: function () {}, + + /** Stub */ + get: function () {}, + + /** Stub */ + set: function () {} + }); + + describe('"deleteAddress" method', function () { + it('Check for defined ', function () { + expect(obj.hasOwnProperty('deleteAddress')).toBeDefined(); + }); + it('Check method type', function () { + var type = typeof obj.deleteAddress; + + expect(type).toEqual('function'); + }); + it('Check returned value if method called without arguments', function () { + expect(obj.deleteAddress()).toBeUndefined(); + }); + it('Check returned value type if method called without arguments', function () { + var type = typeof obj.deleteAddress(); + + expect(type).toEqual('undefined'); + }); + it('Should call not call ajax if arguments are empty', function () { + $.ajax = jasmine.createSpy(); + + spyOn(obj, 'deleteAddress'); + + expect(obj.deleteAddress()).toBeUndefined(); + + expect($.ajax).not.toHaveBeenCalled(); + }); + }); + }); +}); From 408c1350a829b52f7996ce9694fa2d0f56dc6710 Mon Sep 17 00:00:00 2001 From: Dzmitry Tabusheu <dzmitry_tabusheu@epam.com> Date: Fri, 16 Nov 2018 10:53:13 +0300 Subject: [PATCH 082/216] MAGETWO-91769: Credit Memo - Wrong tax calculation! #10982 - Fixed functional test --- .../Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml index 1063f2aa5bf5b..272ab1dceb484 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/CheckCreditMemoTotalsTest.xml @@ -74,7 +74,6 @@ <amOnPage url="{{AdminTaxConfigurationPage.url}}" stepKey="goToTaxConfigPage"/> <conditionalClick stepKey="clickOrdersInvoicesCreditSales" selector="{{AdminConfigureTaxSection.taxClasses}}" dependentSelector="{{AdminConfigureTaxSection.taxClassesCondition}}" visible="false"/> <selectOption selector="{{AdminConfigureTaxSection.productTaxClass}}" userInput="Taxable Goods" stepKey="selectClass"/> - <click selector="{{AdminConfigureTaxSection.useSystemValue}}" stepKey="UncheckUseSystemValue"/> <click selector="{{AdminConfigureTaxSection.save}}" stepKey="saveConfig"/> <!-- Go to the tax rule page and delete the row we created--> <amOnPage url="{{AdminTaxRuleGridPage.url}}" stepKey="goToTaxRulesPage"/> From ef2cf53a60cc7a60895685230c8ad52181de0c3e Mon Sep 17 00:00:00 2001 From: Dmytro Poperechnyy <dpoperechnyy@magento.com> Date: Fri, 16 Nov 2018 16:26:41 +0200 Subject: [PATCH 083/216] MAGETWO-96330: Default Shipping Address Edit button is displayed incorrectly --- .../ui_component/customer_address_form.xml | 4 +- .../web/template/default-address-wrapper.html | 7 + .../view/base/ui_component/customer_form.xml | 185 +++++++++--------- .../web/css/source/_module.less | 27 +-- 4 files changed, 111 insertions(+), 112 deletions(-) create mode 100644 app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml index fdef0e959443b..e07c5d97a30a6 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_address_form.xml @@ -80,7 +80,7 @@ <dataType>text</dataType> </settings> </field> - <field name="default_billing" sortOrder="6" formElement="checkbox"> + <field name="default_billing" sortOrder="5" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> @@ -103,7 +103,7 @@ </checkbox> </formElements> </field> - <field name="default_shipping" sortOrder="5" formElement="checkbox"> + <field name="default_shipping" sortOrder="7" formElement="checkbox"> <argument name="data" xsi:type="array"> <item name="config" xsi:type="array"> <item name="default" xsi:type="number">0</item> diff --git a/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html b/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html new file mode 100644 index 0000000000000..2af366b03342c --- /dev/null +++ b/app/code/Magento/Customer/view/adminhtml/web/template/default-address-wrapper.html @@ -0,0 +1,7 @@ +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<div class="customer-default-address-wrapper" each="data: elems, as: 'element'" render=""/> diff --git a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml index a7c55da2cca2f..aabbbc09de1fb 100644 --- a/app/code/Magento/Customer/view/base/ui_component/customer_form.xml +++ b/app/code/Magento/Customer/view/base/ui_component/customer_form.xml @@ -312,105 +312,106 @@ <class name="customer-address-form">true</class> </additionalClasses> </settings> - <component name="customer_default_billing_address_content" template="Magento_Customer/default-address"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="defaultAddressClass" xsi:type="string">billing-address</item> - <item name="title" translate="true" xsi:type="string">Default Billing Address</item> - <item name="contentClass" xsi:type="string">customer-default-billing-address-content</item> - <item name="notExistsMessage" xsi:type="string" translate="true">The customer does not have default billing address</item> - <item name="tracks" xsi:type="array"> - <item name="address" xsi:type="boolean">true</item> - </item> - </item> - </argument> - <settings> - <imports> - <link name="address">${ $.provider}:data.default_billing_address</link> - </imports> - </settings> - </component> - - <button name="edit_billing_address" component="Magento_Customer/js/address/default-address"> - <argument name="data" xsi:type="array"> - <item name="config" xsi:type="array"> - <item name="buttonClasses" xsi:type="string">edit-default-billing-address-button</item> - <item name="actions" xsi:type="array"> - <item name="0" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal.update_customer_address_form_loader</item> - <item name="actionName" xsi:type="string">destroyInserted</item> - </item> - <item name="1" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal</item> - <item name="actionName" xsi:type="string">openModal</item> - </item> - <item name="2" xsi:type="array"> - <item name="targetName" xsi:type="string">${ $.parentName}.customer_address_update_modal.update_customer_address_form_loader</item> - <item name="actionName" xsi:type="string">render</item> + <component name="customer_default_billing_address_wrapper" template="Magento_Customer/default-address-wrapper"> + <component name="customer_default_billing_address_content" template="Magento_Customer/default-address"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="defaultAddressClass" xsi:type="string">billing-address</item> + <item name="title" translate="true" xsi:type="string">Default Billing Address</item> + <item name="contentClass" xsi:type="string">customer-default-billing-address-content</item> + <item name="notExistsMessage" xsi:type="string" translate="true">The customer does not have default billing address</item> + <item name="tracks" xsi:type="array"> + <item name="address" xsi:type="boolean">true</item> </item> </item> - </item> - </argument> - <settings> - <componentType>button</componentType> - <title translate="true">Edit - true - - ${ $.provider}:data.default_billing_address.entity_id - ${ $.provider}:data.default_billing_address - - - - - - - - shipping-address - Default Shipping Address - customer-default-shipping-address-content - The customer does not have default shipping address - - true + + + + ${ $.provider}:data.default_billing_address + + + + - - + + + button + Edit + true + + ${ $.provider}:data.default_shipping_address.entity_id + ${ $.provider}:data.default_shipping_address + + + +