From f74460631c7feabb72c7ca3dec76a7bb92a17a41 Mon Sep 17 00:00:00 2001 From: Yaroslav Rogoza Date: Sun, 2 Sep 2018 16:11:02 +0200 Subject: [PATCH 01/49] Fixed child items showing on My Account order view --- app/code/Magento/Sales/Block/Order/Items.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Block/Order/Items.php b/app/code/Magento/Sales/Block/Order/Items.php index 028544cd56219..0b67e9a0746d3 100644 --- a/app/code/Magento/Sales/Block/Order/Items.php +++ b/app/code/Magento/Sales/Block/Order/Items.php @@ -71,7 +71,6 @@ protected function _prepareLayout() $this->itemCollection = $this->itemCollectionFactory->create(); $this->itemCollection->setOrderFilter($this->getOrder()); - $this->itemCollection->filterByParent(null); /** @var \Magento\Theme\Block\Html\Pager $pagerBlock */ $pagerBlock = $this->getChildBlock('sales_order_item_pager'); From 10fb01f3702c16411808ae6a24db57ad2413ea83 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun Date: Fri, 5 Oct 2018 10:22:48 +0300 Subject: [PATCH 02/49] MAGETWO-86121: [Backport] Cannot ship remaining items in an order for several of one product if credit memo is made for some - 2.1 --- app/code/Magento/Sales/Model/Order.php | 8 +- app/code/Magento/Sales/Model/Order/Item.php | 2 +- .../ActionGroup/AdminOrderActionGroup.xml | 16 ++ .../Test/Mftf/Page/AdminCreditMemoNewPage.xml | 1 + .../Test/Mftf/Page/AdminInvoiceNewPage.xml | 1 + .../Test/Mftf/Page/AdminOrderDetailsPage.xml | 4 + .../Section/AdminCreditMemoItemsSection.xml | 15 ++ .../Section/AdminCreditMemoTotalSection.xml | 1 + .../Mftf/Section/AdminInvoiceItemsSection.xml | 16 ++ .../AdminOrderCreditMemosTabSection.xml | 14 ++ .../AdminOrderDetailsOrderViewSection.xml | 16 ++ .../Section/AdminOrderInvoicesTabSection.xml | 14 ++ .../Section/AdminOrderShipmentsTabSection.xml | 14 ++ ...inAbleToShipPartiallyInvoicedItemsTest.xml | 173 ++++++++++++++++++ .../Sales/Test/Unit/Model/Order/ItemTest.php | 110 +++++++++++ .../Sales/Test/Unit/Model/OrderTest.php | 122 +++++++++++- .../Test/Mftf/Page/AdminShipmentNewPage.xml | 15 ++ .../Section/AdminShipmentItemsSection.xml | 15 ++ .../AdminShipmentMainActionsSection.xml | 14 ++ .../Service/V1/CreditMemoCreateRefundTest.php | 3 +- .../Sales/Service/V1/RefundOrderTest.php | 5 +- ...AssertOrderCancelMassActionFailMessage.php | 2 +- .../Test/TestCase/MassOrdersUpdateTest.xml | 8 +- .../Magento/Paypal/Model/IpnTest.php | 4 +- 24 files changed, 580 insertions(+), 13 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderCreditMemosTabSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderShipmentsTabSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index a1bbd4856df16..6cbf168316c3d 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -541,7 +541,13 @@ public function canCancel() break; } } - if ($allInvoiced) { + + $allRefunded = true; + foreach ($this->getAllItems() as $orderItem) { + $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() == (float)$orderItem->getQtyInvoiced()); + } + + if ($allInvoiced && !$allRefunded) { return false; } diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php index da2a06c2db25a..c202c5d0a643f 100644 --- a/app/code/Magento/Sales/Model/Order/Item.php +++ b/app/code/Magento/Sales/Model/Order/Item.php @@ -232,7 +232,7 @@ public function getQtyToShip() */ public function getSimpleQtyToShip() { - $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyRefunded() - $this->getQtyCanceled(); + $qty = $this->getQtyOrdered() - $this->getQtyShipped() - $this->getQtyCanceled(); return max($qty, 0); } diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index 9884f35227863..54e22fd851c53 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -210,4 +210,20 @@ + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoNewPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoNewPage.xml index e78cfc28c4469..a9e37bc3a9df2 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoNewPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoNewPage.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd">
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml index 1f8291c0c2d2f..cfd5c5794a2de 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml @@ -12,5 +12,6 @@
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml index f217caa49a1e9..fd400c78ec123 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml @@ -15,5 +15,9 @@
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml new file mode 100644 index 0000000000000..d835bfe069683 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoItemsSection.xml @@ -0,0 +1,15 @@ + + + + +
+ + +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml index 446186d5da8a3..5fa5584fa8824 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminCreditMemoTotalSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml new file mode 100644 index 0000000000000..dbae8042b6554 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml @@ -0,0 +1,16 @@ + + + + +
+ + + +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderCreditMemosTabSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderCreditMemosTabSection.xml new file mode 100644 index 0000000000000..1e801dab4b134 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderCreditMemosTabSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml new file mode 100644 index 0000000000000..e8b5e3a00e315 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml @@ -0,0 +1,16 @@ + + + + +
+ + + +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml new file mode 100644 index 0000000000000..264b57733eea7 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderInvoicesTabSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderShipmentsTabSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderShipmentsTabSection.xml new file mode 100644 index 0000000000000..f71b603a40b7d --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderShipmentsTabSection.xml @@ -0,0 +1,14 @@ + + + + +
+ +
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml new file mode 100644 index 0000000000000..04c662dbe59d1 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -0,0 +1,173 @@ + + + + + + + <description value="Admin should be able to ship remaining ordered items if some of them are already refunded"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-95524"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--login to Admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <!--Create new order--> + <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> + <actionGroup ref="navigateToNewOrderPageNewCustomerSingleStore" stepKey="startToCreateNewOrder"/> + <actionGroup ref="addSimpleProductToOrderWithCustomQuantity" stepKey="addSimpleProductToOrderWithUserDefinedQty"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="quantity" value="10"/> + </actionGroup> + + <!--Fill customer group and customer email which both are now required fields--> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" after="addSimpleProductToOrderWithUserDefinedQty" stepKey="selectCustomerGroup"/> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" after="selectCustomerGroup" stepKey="fillCustomerEmail"/> + <!--Fill customer address information--> + <actionGroup ref="fillOrderCustomerInformation" after="fillCustomerEmail" stepKey="fillCustomerAddress"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + <!-- Select shipping --> + <actionGroup ref="orderSelectFlatRateShipping" after="fillCustomerAddress" stepKey="selectFlatRateShipping"/> + <!--Verify totals on Order page--> + <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="$1,230.00" after="selectFlatRateShipping" stepKey="seeOrderSubTotal"/> + <see selector="{{AdminOrderFormTotalSection.total('Shipping')}}" userInput="$50.00" after="seeOrderSubTotal" stepKey="seeOrderShippingAmount"/> + <scrollTo selector="{{AdminOrderFormTotalSection.grandTotal}}" stepKey="scrollToOrderGrandTotal"/> + <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="$1,280.00" after="scrollToOrderGrandTotal" stepKey="seeCorrectGrandTotal"/> + <!--Submit Order and verify information--> + <click selector="{{AdminOrderFormActionSection.submitOrder}}" after="seeCorrectGrandTotal" stepKey="clickSubmitOrder"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskTodisappear"/> + <waitForPageLoad stepKey="waitForOrderSubmitted"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" after="clickSubmitOrder" stepKey="seeViewOrderPage"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You created the order." after="seeViewOrderPage" stepKey="seeSuccessMessage"/> + <grabTextFrom selector="|Order # (\d+)|" after="seeSuccessMessage" stepKey="getOrderId"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.qtyColumn}}" after="getOrderId" stepKey="scrollToItemsOrdered"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Ordered 10" after="scrollToItemsOrdered" stepKey="seeQtyOfItemsOrdered"/> + + <!--Create order invoice for first half of ordered items--> + <comment userInput="Admin creates invoice for order" stepKey="adminCreateInvoiceComment" /> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionButton"/> + <seeInCurrentUrl url="{{AdminInvoiceNewPage.url}}" after="clickInvoiceActionButton" stepKey="seeNewInvoicePageUrl"/> + <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> + <!--Change invoiced items count--> + <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> + <waitForLoadingMaskToDisappear stepKey="waitForQtyToUpdate"/> + <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> + <!--Submit Invoice--> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice"/> + <waitForLoadingMaskToDisappear stepKey="waitForInvoiceToSubmit"/> + <!--Invoice created successfully--> + <see selector="{{AdminMessagesSection.success}}" userInput="The invoice has been created." stepKey="seeInvoiceSuccessMessage"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Invoiced 5" stepKey="see5itemsInvoiced"/> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage"/> + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab"/> + <waitForLoadingMaskToDisappear after="clickInvoicesTab" stepKey="waitForInvoiceGridToLoad"/> + <see selector="{{AdminOrderInvoicesTabSection.gridRow('1')}}" userInput="$665.00" after="waitForInvoiceGridToLoad" stepKey="seeOrderInvoiceTabInGrid"/> + + <!--Ship Order--> + <comment userInput="Admin creates shipment" stepKey="adminCreatesShipmentComment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" after="adminCreatesShipmentComment" stepKey="clickShip"/> + <seeInCurrentUrl url="{{AdminShipmentNewPage.url}}" after="clickShip" stepKey="seeOrderShipmentUrl" /> + <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip"/> + <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 5" stepKey="see5ItemsInvoiced"/> + <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillQtyOfItemsToShip"/> + <!--Submit Shipment--> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" after="fillQtyOfItemsToShip" stepKey="submitShipment"/> + <waitForLoadingMaskToDisappear stepKey="waitForShipmentToSubmit"/> + <!--Verify shipment created successfully--> + <see selector="{{AdminMessagesSection.success}}" userInput="The shipment has been created." after="submitShipment" stepKey="successfullShipmentCreation"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="$getOrderId" stepKey="seeOrderIdInPageTitleAfterShip"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems1"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 5" stepKey="see5itemsShipped"/> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage1"/> + <click selector="{{AdminOrderDetailsOrderViewSection.shipments}}" stepKey="clickShipmentsTab"/> + <waitForLoadingMaskToDisappear after="clickShipmentsTab" stepKey="waitForShipmentsGridToLoad"/> + <see selector="{{AdminOrderShipmentsTabSection.gridRow('1')}}" userInput="5.0000" after="waitForShipmentsGridToLoad" stepKey="seeOrderShipmentsTabInGrid"/> + + <!--Create Credit Memo--> + <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" after="createCreditMemoComment" stepKey="clickCreateCreditMemo"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle"/> + <!--Submit refund--> + <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> + <fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" after="scrollToItemsToRefund" stepKey="fillQtyOfItemsToRefund"/> + <click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/> + <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> + <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="submitRefundOffline"/> + <!--Verify Credit Memo created successfully--> + <see selector="{{AdminMessagesSection.success}}" userInput="You created the credit memo." after="submitRefundOffline" stepKey="seeCreditMemoSuccessMsg"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems2"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Refunded 5" stepKey="see5itemsRefunded"/> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage2"/> + <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickCreditMemosTab"/> + <waitForLoadingMaskToDisappear after="clickCreditMemosTab" stepKey="waitForCreditMemosGridToLoad"/> + <see selector="{{AdminOrderCreditMemosTabSection.gridRow('1')}}" userInput="$665.00" after="waitForCreditMemosGridToLoad" stepKey="seeOrderCreditMemoTabInGrid"/> + + <!--Create invoice for rest of the ordered items--> + <comment userInput="Admin creates invoice for rest of the items" stepKey="adminCreateInvoiceComment2" /> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceActionForRestOfItems"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" after="clickInvoiceActionForRestOfItems" stepKey="seePageNameNewInvoicePage2"/> + <comment userInput="Qty To Invoice is 5" stepKey="seeRemainderInQtyToInvoice"/> + <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced2"/> + <seeInField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="see5InTheQtyToInvoice"/> + <!--Verify items invoiced information--> + <see selector="{{AdminInvoiceItemsSection.itemQty('1')}}" userInput="Refunded 5" stepKey="seeQtyOfItemsRefunded"/> + <!--Submit Invoice--> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="submitInvoice2" /> + <!--Invoice created successfully for the rest of the ordered items--> + <see selector="{{AdminMessagesSection.success}}" userInput="The invoice has been created." after="submitInvoice2" stepKey="seeInvoiceSuccessMessage2"/> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems3"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Invoiced 10" stepKey="see10itemsInvoiced"/> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage3"/> + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab1"/> + <waitForLoadingMaskToDisappear after="clickInvoicesTab1" stepKey="waitForInvoiceGridToLoad1"/> + <see selector="{{AdminOrderInvoicesTabSection.gridRow('2')}}" userInput="$615.00" after="waitForInvoiceGridToLoad1" stepKey="seeOrderInvoiceTabInGrid1"/> + + <!--Verify Ship Action can be done for the rest of the invoiced items --> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage4"/> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" after="seeOrderInvoiceTabInGrid1" stepKey="clickShipActionForRestOfItems"/> + + <!--Verify Items in Ship section --> + <scrollTo selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" stepKey="scrollToItemsToShip2"/> + <see selector="{{AdminShipmentItemsSection.itemQty('1')}}" userInput="Invoiced 10" stepKey="seeAll10ItemsInvoiced"/> + <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="5" stepKey="fillRestOfItemsToShip"/> + <!--Submit Shipment--> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" after="fillRestOfItemsToShip" stepKey="submitShipment2" /> + <see selector="{{AdminMessagesSection.success}}" userInput="The shipment has been created." after="submitShipment2" stepKey="successfullyCreatedShipment"/> + + <!--Verify Items Status and Shipped Qty in the Items Ordered section--> + <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsOrdered2"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 10" stepKey="seeAllItemsShipped"/> + <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage5"/> + <click selector="{{AdminOrderDetailsOrderViewSection.shipments}}" stepKey="clickShipmentsTab1"/> + <waitForLoadingMaskToDisappear after="clickShipmentsTab1" stepKey="waitForShipmentsGridToLoad1"/> + <see selector="{{AdminOrderShipmentsTabSection.gridRow('2')}}" userInput="5.0000" after="waitForShipmentsGridToLoad1" stepKey="seeOrderShipmentsTabInGrid1"/> + + <!--Remove created customer--> + <actionGroup ref="RemoveCustomerFromAdminActionGroup" stepKey="removeCustomer"> + <argument name="customer" value="Simple_US_Customer"/> + </actionGroup> + </test> +</tests> + diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php index aea234959cea0..144beb10f3c81 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php @@ -238,4 +238,114 @@ public function getProductOptionsDataProvider() ] ]; } + + /** + * Test different combinations of item qty setups + * + * @param array $options + * @param float $expectedResult + * + * @dataProvider getItemQtyVariants + */ + public function testGetSimpleQtyToMethods(array $options, $expectedResult) + { + $this->model->setData($options); + $this->assertSame($this->model->getSimpleQtyToShip(), $expectedResult['to_ship']); + $this->assertSame($this->model->getQtyToInvoice(), $expectedResult['to_invoice']); + } + + /** + * Provides different combinations of qty options for an item and the + * expected qtys pending shipment and invoice + * + * @return array + */ + public function getItemQtyVariants() + { + return [ + 'empty_item' => [ + 'options' => [ + 'qty_ordered' => 0, 'qty_invoiced' => 0, 'qty_refunded' => 0, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 0, 'to_invoice' => 0], + ], + 'ordered_item' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 0, 'qty_refunded' => 0, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 12, 'to_invoice' => 12], + ], + 'partially_invoiced' => [ + 'options' => ['qty_ordered' => 12, 'qty_invoiced' => 4, 'qty_refunded' => 0, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 12, 'to_invoice' => 8], + ], + 'completely_invoiced' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 0, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 12, 'to_invoice' => 0], + ], + 'partially_invoiced_refunded' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 5, 'qty_refunded' => 5, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 12, 'to_invoice' => 7], + ], + 'partially_refunded' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 0, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 12, 'to_invoice' => 0], + ], + 'partially_shipped' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 0, 'qty_refunded' => 0, 'qty_shipped' => 4, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 8, 'to_invoice' => 12], + ], + 'partially_refunded_partially_shipped' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 5, 'qty_shipped' => 4, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 8, 'to_invoice' => 0], + ], + 'complete' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 12, 'qty_refunded' => 0, 'qty_shipped' => 12, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 0, 'to_invoice' => 0], + ], + 'canceled' => [ + 'options' => [ + 'qty_ordered' => 12, 'qty_invoiced' => 0, 'qty_refunded' => 0, 'qty_shipped' => 0, + 'qty_canceled' => 12, + ], + 'expectedResult' => ['to_ship' => 0, 'to_invoice' => 0], + ], + 'completely_shipped_using_decimals' => [ + 'options' => [ + 'qty_ordered' => 4.4, 'qty_invoiced' => 0.4, 'qty_refunded' => 0.4, 'qty_shipped' => 4, + 'qty_canceled' => 0, + ], + 'expectedResult' => ['to_ship' => 0.4, 'to_invoice' => 4.0], + ], + 'completely_invoiced_using_decimals' => [ + 'options' => [ + 'qty_ordered' => 4.4, 'qty_invoiced' => 4, 'qty_refunded' => 0, 'qty_shipped' => 4, + 'qty_canceled' => 0.4, + ], + 'expectedResult' => ['to_ship' => 0.0, 'to_invoice' => 0.0], + ], + ]; + } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 7f6363346872c..6f96db301f77e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -114,7 +114,9 @@ protected function setUp() 'getParentItemId', 'getQuoteItemId', 'getLockedDoInvoice', - 'getProductId' + 'getProductId', + 'getQtyRefunded', + 'getQtyInvoiced', ]); $this->salesOrderCollectionMock = $this->getMockBuilder( \Magento\Sales\Model\ResourceModel\Order\Collection::class @@ -619,6 +621,124 @@ public function testCanCancelAllInvoiced() $this->item->expects($this->any()) ->method('getQtyToInvoice') ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(1); + + $this->assertFalse($this->order->canCancel()); + } + + /** + * @return void + */ + public function testCanCancelAllRefunded() + { + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($collectionMock); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->once()) + ->method('getQtyRefunded') + ->willReturn(10); + $this->item->expects($this->once()) + ->method('getQtyInvoiced') + ->willReturn(10); + + $this->assertTrue($this->order->canCancel()); + } + + /** + * Test that order can be canceled if some items were partially invoiced with certain qty + * and then refunded for this qty. + * Sample: + * - ordered qty = 20 + * - invoiced = 10 + * - refunded = 10 + */ + public function testCanCancelPartiallyInvoicedAndRefunded() + { + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($collectionMock); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->once()) + ->method('getQtyToInvoice') + ->willReturn(10); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(10); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(10); + + $this->assertTrue($this->order->canCancel()); + } + + /** + * Test that order CAN NOT be canceled if some items were partially invoiced with certain qty + * and then refunded for less than that qty. + * Sample: + * - ordered qty = 10 + * - invoiced = 10 + * - refunded = 5 + */ + public function testCanCancelPartiallyInvoicedAndNotFullyRefunded() + { + $collectionMock = $this->createPartialMock( + \Magento\Sales\Model\ResourceModel\Order\Item\Collection::class, + ['getItems', 'setOrderFilter'] + ); + $this->orderItemCollectionFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($collectionMock); + $collectionMock->expects($this->any()) + ->method('setOrderFilter') + ->willReturnSelf(); + + $this->order->setActionFlag(\Magento\Sales\Model\Order::ACTION_FLAG_UNHOLD, false); + $this->order->setState(\Magento\Sales\Model\Order::STATE_NEW); + + $this->item->expects($this->any()) + ->method('isDeleted') + ->willReturn(false); + $this->item->expects($this->any()) + ->method('getQtyToInvoice') + ->willReturn(0); + $this->item->expects($this->any()) + ->method('getQtyRefunded') + ->willReturn(5); + $this->item->expects($this->any()) + ->method('getQtyInvoiced') + ->willReturn(10); $this->assertFalse($this->order->canCancel()); } diff --git a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml new file mode 100644 index 0000000000000..4520e69652cb1 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml @@ -0,0 +1,15 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminShipmentNewPage" url="order_shipment/new/order_id/" area="admin" module="Shipping"> + <section name="AdminShipmentMainActionsSection"/> + <section name="AdminShipmentItemsSection"/> + </page> +</pages> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml new file mode 100644 index 0000000000000..740cae14f8bc5 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml @@ -0,0 +1,15 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentItemsSection"> + <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-ordered-qty .qty-table" parameterized="true"/> + <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-qty input.qty-item" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml new file mode 100644 index 0000000000000..d79748d1e20cc --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentMainActionsSection"> + <element name="submitShipment" type="button" selector="button.action-default.save.submit-button"/> + </section> +</sections> diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php index 8262a7e41543e..eae0e600434a6 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditMemoCreateRefundTest.php @@ -115,7 +115,8 @@ public function testInvoke() ); $this->assertNotEmpty($result); $order = $this->objectManager->get(OrderRepositoryInterface::class)->get($order->getId()); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()); + //Totally refunded orders still can be processed and shipped. + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()); } private function getItemsForRest($order) diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php index 12cbe1ca0e5e2..aacda763ca2aa 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/RefundOrderTest.php @@ -86,10 +86,11 @@ public function testShortRequest() 'Failed asserting that proper shipping amount of the Order was refunded' ); - $this->assertNotEquals( + //Totally refunded orders can be processed. + $this->assertEquals( $existingOrder->getStatus(), $updatedOrder->getStatus(), - 'Failed asserting that order status was changed' + 'Failed asserting that order status has not changed' ); } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { $this->fail('Failed asserting that Creditmemo was created'); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php index f8c3d8da399cd..6d3b99ce81a04 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php @@ -18,7 +18,7 @@ class AssertOrderCancelMassActionFailMessage extends AbstractConstraint /** * Text value to be checked */ - const FAIL_CANCEL_MESSAGE = 'You cannot cancel the order(s).'; + const FAIL_CANCEL_MESSAGE = '1 order(s) cannot be canceled.'; /** * Assert cancel fail message is displayed on order index page diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml index d4b9856c5e319..eddc321e9ca52 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/TestCase/MassOrdersUpdateTest.xml @@ -18,11 +18,11 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation2"> - <data name="description" xsi:type="string">try to cancel orders in status Complete, Closed</data> + <data name="description" xsi:type="string">try to cancel orders in status Complete, Canceled</data> <data name="steps" xsi:type="string">invoice, shipment|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Complete,Closed</data> + <data name="resultStatuses" xsi:type="string">Complete,Canceled</data> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> @@ -31,7 +31,7 @@ <data name="steps" xsi:type="string">invoice|invoice, credit memo</data> <data name="action" xsi:type="string">Cancel</data> <data name="ordersCount" xsi:type="string">2</data> - <data name="resultStatuses" xsi:type="string">Processing,Closed</data> + <data name="resultStatuses" xsi:type="string">Processing,Canceled</data> <constraint name="Magento\Sales\Test\Constraint\AssertOrderCancelMassActionFailMessage" /> <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> @@ -55,7 +55,7 @@ <constraint name="Magento\Sales\Test\Constraint\AssertOrdersInOrdersGrid" /> </variation> <variation name="MassOrdersUpdateTestVariation6"> - <data name="description" xsi:type="string">Release order in statuse On Hold</data> + <data name="description" xsi:type="string">Release order in status On Hold</data> <data name="steps" xsi:type="string">on hold</data> <data name="action" xsi:type="string">Unhold</data> <data name="ordersCount" xsi:type="string">1</data> diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php index 3c126bcdc2c5b..6b92338e9932a 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/IpnTest.php @@ -64,7 +64,7 @@ public function testProcessIpnRequestFullRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); $creditmemo = current($creditmemoItems); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()); + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()); $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(Creditmemo::STATE_REFUNDED, $creditmemo->getState()); $this->assertEquals(10, $order->getSubtotalRefunded()); @@ -146,7 +146,7 @@ public function testProcessIpnRequestRestRefund() $creditmemoItems = $order->getCreditmemosCollection()->getItems(); - $this->assertEquals(Order::STATE_CLOSED, $order->getState()); + $this->assertEquals(Order::STATE_PROCESSING, $order->getState()); $this->assertEquals(1, count($creditmemoItems)); $this->assertEquals(10, $order->getSubtotalRefunded()); $this->assertEquals(10, $order->getBaseSubtotalRefunded()); From 8032681ace040b74c33414afc68e906ffec0605a Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 5 Oct 2018 10:55:14 +0300 Subject: [PATCH 03/49] MAGETWO-86121: [Backport] Cannot ship remaining items in an order for several of one product if credit memo is made for some - 2.1 --- app/code/Magento/Sales/Test/Unit/Model/OrderTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 6f96db301f77e..65492073a9ff7 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -17,6 +17,7 @@ * Test class for \Magento\Sales\Model\Order * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class OrderTest extends \PHPUnit\Framework\TestCase { From cf8f34c72ba4d897c6f504869d4126ebb301ebc6 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 5 Oct 2018 11:32:22 +0300 Subject: [PATCH 04/49] MAGETWO-86121: [Backport] Cannot ship remaining items in an order for several of one product if credit memo is made for some - 2.1 --- app/code/Magento/Sales/Test/Unit/Model/OrderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 65492073a9ff7..3a6b917f4743e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -17,7 +17,7 @@ * Test class for \Magento\Sales\Model\Order * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - * @SuppressWarnings(PHPMD.TooManyPublicMethods) + * @SuppressWarnings(PHPMD.ExcessivePublicCount) */ class OrderTest extends \PHPUnit\Framework\TestCase { From 46ae3269db136b2ad037a99f6912c8f1f1edf8da Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Mon, 8 Oct 2018 13:41:05 +0300 Subject: [PATCH 05/49] MAGETWO-86121: [Backport] Cannot ship remaining items in an order for several of one product if credit memo is made for some - 2.1 --- app/code/Magento/Sales/Model/Order.php | 2 +- .../ActionGroup/AdminOrderActionGroup.xml | 19 ++----------------- .../Test/Mftf/Page/AdminOrderDetailsPage.xml | 2 +- ...tion.xml => AdminOrderViewTabsSection.xml} | 2 +- ...inAbleToShipPartiallyInvoicedItemsTest.xml | 12 ++++++------ .../Sales/Test/Unit/Model/Order/ItemTest.php | 7 ++++--- .../Test/Mftf/Page/AdminShipmentNewPage.xml | 2 +- 7 files changed, 16 insertions(+), 30 deletions(-) rename app/code/Magento/Sales/Test/Mftf/Section/{AdminOrderDetailsOrderViewSection.xml => AdminOrderViewTabsSection.xml} (93%) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index 6cbf168316c3d..efbab56dcc778 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -544,7 +544,7 @@ public function canCancel() $allRefunded = true; foreach ($this->getAllItems() as $orderItem) { - $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() == (float)$orderItem->getQtyInvoiced()); + $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() === (float)$orderItem->getQtyInvoiced()); } if ($allInvoiced && !$allRefunded) { diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index 5fa3a378a92f8..2ea935efef2e9 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -77,13 +77,14 @@ <actionGroup name="addSimpleProductToOrder"> <arguments> <argument name="product" defaultValue="_defaultProduct"/> + <argument name="quantity" type="string" defaultValue="1"/> </arguments> <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilter"/> <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearch"/> <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> - <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="1" stepKey="fillProductQty"/> + <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="{{quantity}}" stepKey="fillProductQty"/> <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> </actionGroup> @@ -193,20 +194,4 @@ </arguments> <see selector="{{AdminOrderItemsOrderedSection.productSkuColumn}}" userInput="{{product.sku}}" stepKey="seeSkuInItemsOrdered"/> </actionGroup> - - <!--Add a simple product to order with user defined quantity--> - <actionGroup name="addSimpleProductToOrderWithCustomQuantity"> - <arguments> - <argument name="product" defaultValue="_defaultProduct"/> - <argument name="quantity" type="string"/> - </arguments> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMastToDisappear"/> - <waitForElementVisible selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="waitForAddProductButton"/> - <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> - <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilter"/> - <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearch"/> - <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> - <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="{{quantity}}" stepKey="fillProductQty"/> - <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> - </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml index fd400c78ec123..4280356278a88 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderDetailsPage.xml @@ -15,7 +15,7 @@ <section name="OrderDetailsMessagesSection"/> <section name="AdminOrderItemsOrderedSection"/> <section name="AdminOrderTotalSection"/> - <section name="AdminOrderDetailsOrderViewSection"/> + <section name="AdminOrderViewTabsSection"/> <section name="AdminOrderInvoicesTabSection"/> <section name="AdminOrderShipmentsTabSection"/> <section name="AdminOrderCreditMemosTabSection"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderViewTabsSection.xml similarity index 93% rename from app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml rename to app/code/Magento/Sales/Test/Mftf/Section/AdminOrderViewTabsSection.xml index e8b5e3a00e315..78d0a45bce460 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderDetailsOrderViewSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderViewTabsSection.xml @@ -8,7 +8,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="AdminOrderDetailsOrderViewSection"> + <section name="AdminOrderViewTabsSection"> <element name="invoices" type="button" selector="#sales_order_view_tabs_order_invoices"/> <element name="creditMemos" type="button" selector="#sales_order_view_tabs_order_creditmemos"/> <element name="shipments" type="button" selector="#sales_order_view_tabs_order_shipments"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 04c662dbe59d1..66a9709473623 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -32,7 +32,7 @@ <!--Create new order--> <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> <actionGroup ref="navigateToNewOrderPageNewCustomerSingleStore" stepKey="startToCreateNewOrder"/> - <actionGroup ref="addSimpleProductToOrderWithCustomQuantity" stepKey="addSimpleProductToOrderWithUserDefinedQty"> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrderWithUserDefinedQty"> <argument name="product" value="$$createSimpleProduct$$"/> <argument name="quantity" value="10"/> </actionGroup> @@ -80,7 +80,7 @@ <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Invoiced 5" stepKey="see5itemsInvoiced"/> <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage"/> - <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab"/> + <click selector="{{AdminOrderViewTabsSection.invoices}}" stepKey="clickInvoicesTab"/> <waitForLoadingMaskToDisappear after="clickInvoicesTab" stepKey="waitForInvoiceGridToLoad"/> <see selector="{{AdminOrderInvoicesTabSection.gridRow('1')}}" userInput="$665.00" after="waitForInvoiceGridToLoad" stepKey="seeOrderInvoiceTabInGrid"/> @@ -100,7 +100,7 @@ <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems1"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 5" stepKey="see5itemsShipped"/> <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage1"/> - <click selector="{{AdminOrderDetailsOrderViewSection.shipments}}" stepKey="clickShipmentsTab"/> + <click selector="{{AdminOrderViewTabsSection.shipments}}" stepKey="clickShipmentsTab"/> <waitForLoadingMaskToDisappear after="clickShipmentsTab" stepKey="waitForShipmentsGridToLoad"/> <see selector="{{AdminOrderShipmentsTabSection.gridRow('1')}}" userInput="5.0000" after="waitForShipmentsGridToLoad" stepKey="seeOrderShipmentsTabInGrid"/> @@ -120,7 +120,7 @@ <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems2"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Refunded 5" stepKey="see5itemsRefunded"/> <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage2"/> - <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickCreditMemosTab"/> + <click selector="{{AdminOrderViewTabsSection.creditMemos}}" stepKey="clickCreditMemosTab"/> <waitForLoadingMaskToDisappear after="clickCreditMemosTab" stepKey="waitForCreditMemosGridToLoad"/> <see selector="{{AdminOrderCreditMemosTabSection.gridRow('1')}}" userInput="$665.00" after="waitForCreditMemosGridToLoad" stepKey="seeOrderCreditMemoTabInGrid"/> @@ -140,7 +140,7 @@ <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToOrderItems3"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Invoiced 10" stepKey="see10itemsInvoiced"/> <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage3"/> - <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoicesTab1"/> + <click selector="{{AdminOrderViewTabsSection.invoices}}" stepKey="clickInvoicesTab1"/> <waitForLoadingMaskToDisappear after="clickInvoicesTab1" stepKey="waitForInvoiceGridToLoad1"/> <see selector="{{AdminOrderInvoicesTabSection.gridRow('2')}}" userInput="$615.00" after="waitForInvoiceGridToLoad1" stepKey="seeOrderInvoiceTabInGrid1"/> @@ -160,7 +160,7 @@ <scrollTo selector="{{AdminOrderItemsOrderedSection.itemStatus('1')}}" stepKey="scrollToItemsOrdered2"/> <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 10" stepKey="seeAllItemsShipped"/> <scrollTo selector="{{AdminHeaderSection.pageTitle}}" stepKey="scrollToTopOfPage5"/> - <click selector="{{AdminOrderDetailsOrderViewSection.shipments}}" stepKey="clickShipmentsTab1"/> + <click selector="{{AdminOrderViewTabsSection.shipments}}" stepKey="clickShipmentsTab1"/> <waitForLoadingMaskToDisappear after="clickShipmentsTab1" stepKey="waitForShipmentsGridToLoad1"/> <see selector="{{AdminOrderShipmentsTabSection.gridRow('2')}}" userInput="5.0000" after="waitForShipmentsGridToLoad1" stepKey="seeOrderShipmentsTabInGrid1"/> diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php index 144beb10f3c81..ce7fcca42ccb4 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemTest.php @@ -243,11 +243,12 @@ public function getProductOptionsDataProvider() * Test different combinations of item qty setups * * @param array $options - * @param float $expectedResult + * @param array $expectedResult + * @return void * * @dataProvider getItemQtyVariants */ - public function testGetSimpleQtyToMethods(array $options, $expectedResult) + public function testGetSimpleQtyToMethods(array $options, array $expectedResult) { $this->model->setData($options); $this->assertSame($this->model->getSimpleQtyToShip(), $expectedResult['to_ship']); @@ -260,7 +261,7 @@ public function testGetSimpleQtyToMethods(array $options, $expectedResult) * * @return array */ - public function getItemQtyVariants() + public function getItemQtyVariants(): array { return [ 'empty_item' => [ diff --git a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml index 4520e69652cb1..d7b91f68d21a2 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml @@ -8,7 +8,7 @@ <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="AdminShipmentNewPage" url="order_shipment/new/order_id/" area="admin" module="Shipping"> + <page name="AdminShipmentNewPage" url="order_shipment/new/order_id/" area="admin" module="Magento_Shipping"> <section name="AdminShipmentMainActionsSection"/> <section name="AdminShipmentItemsSection"/> </page> From 1d8c4263cea92ce1f9cbe8762ba41a1b13a2a281 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Mon, 8 Oct 2018 13:54:20 +0300 Subject: [PATCH 06/49] MAGETWO-86121: [Backport] Cannot ship remaining items in an order for several of one product if credit memo is made for some - 2.1 --- app/code/Magento/Sales/Model/Order.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index efbab56dcc778..520833b3c30cc 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -544,7 +544,8 @@ public function canCancel() $allRefunded = true; foreach ($this->getAllItems() as $orderItem) { - $allRefunded = $allRefunded && ((float)$orderItem->getQtyRefunded() === (float)$orderItem->getQtyInvoiced()); + $allRefunded = $allRefunded + && ((float)$orderItem->getQtyRefunded() === (float)$orderItem->getQtyInvoiced()); } if ($allInvoiced && !$allRefunded) { From 767245a1c98481dcc107a83df3ca2a5b3ca19457 Mon Sep 17 00:00:00 2001 From: Iurii Ivashchenko <iivashchenko@magento.com> Date: Sat, 20 Oct 2018 12:53:29 +0300 Subject: [PATCH 07/49] MAGETWO-94235: Images added through wysiwyg are broken on frontend --- lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js index ed105bd2c18f5..fee0104efe87a 100755 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/setup.js @@ -408,7 +408,9 @@ define([ * @param {String} directive */ makeDirectiveUrl: function (directive) { - return this.config['directives_url'].replace('directive', 'directive/___directive/' + directive); + var directivesUrl = this.config['directives_url'].split('?')[0]; + + return directivesUrl.replace('directive', 'directive/___directive/' + directive); }, /** From 94d4d980e32877a7f8e9fc784b59ecf12bdeb226 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Tue, 30 Oct 2018 08:49:33 +0200 Subject: [PATCH 08/49] MAGETWO-72877: Zero Subtotal Orders have incorrect status --- ...SubtotalOrdersWithProcessingStatusTest.xml | 99 +++++++++++++++++++ .../ZeroSubtotalCheckoutPaymentMethodData.xml | 33 +++++++ .../Mftf/Metadata/payment_method-meta.xml | 25 +++++ app/code/Magento/Payment/etc/config.xml | 1 + 4 files changed, 158 insertions(+) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml create mode 100644 app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml create mode 100644 app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml new file mode 100644 index 0000000000000..3110256e274e7 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml @@ -0,0 +1,99 @@ +<?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="ZeroSubtotalOrdersWithProcessingStatusTest"> + <annotations> + <features value="Checkout"/> + <stories value="MAGETWO-72877: Zero Subtotal Orders have incorrect status"/> + <title value="Checking status of Zero Subtotal Orders with 'Processing' New Order Status"/> + <description value="Created order should be in Processing status"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-95994"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="simpleSubCategory"/> + <createData entity="SimpleProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="simpleSubCategory"/> + </createData> + <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> + <createData entity="ZeroSubtotalCheckoutPaymentMethodConfig" stepKey="enableZeroSubtotalCheckout"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearAdminOrdersGridFilters"/> + <actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteCartPriceRule"> + <argument name="ruleName" value="{{ApiSalesRule.name}}"/> + </actionGroup> + <createData entity="ZeroSubtotalCheckoutPaymentMethodDefault" stepKey="disableZeroSubtotalCheckout"/> + <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShipping"/> + <deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="simpleSubCategory" stepKey="deleteSimpleSubCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Add New Rule--> + <amOnPage url="{{AdminCartPriceRulesPage.url}}" stepKey="amOnCartPriceRulesPage"/> + <waitForPageLoad stepKey="waitForCartPriceRulesPage"/> + <click selector="{{AdminCartPriceRulesSection.addNewRuleButton}}" stepKey="clickAddNewRuleButton"/> + <fillField selector="{{AdminCartPriceRulesFormSection.ruleName}}" userInput="{{ApiSalesRule.name}}" + stepKey="fillRuleName"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.websites}}" userInput="Main Website" + stepKey="selectWebsite"/> + <actionGroup ref="selectNotLoggedInCustomerGroup" stepKey="selectNotLoggedInCustomerGroup"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.coupon}}" userInput="Specific Coupon" + stepKey="selectCouponType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.couponCode}}" userInput="{{_defaultCoupon.code}}" + stepKey="fillCouponCode"/> + <fillField selector="{{AdminCartPriceRulesFormSection.userPerCoupon}}" userInput="99" + stepKey="fillUserPerCoupon"/> + <click selector="{{AdminCartPriceRulesFormSection.actionsHeader}}" stepKey="clickToExpandActions"/> + <selectOption selector="{{AdminCartPriceRulesFormSection.apply}}" userInput="Percent of product price discount" + stepKey="selectActionType"/> + <fillField selector="{{AdminCartPriceRulesFormSection.discountAmount}}" userInput="100" + stepKey="fillDiscountAmount"/> + <click selector="{{AdminCartPriceRulesFormSection.save}}" stepKey="clickSaveButton"/> + <see selector="{{AdminCartPriceRulesSection.messages}}" userInput="You saved the rule." + stepKey="seeSuccessMessageSavedRule"/> + + <!--Open Product Page--> + <amOnPage url="{{StorefrontProductPage.url($$simpleProduct.name$$)}}" stepKey="openProductPage"/> + <waitForPageLoad time="30" stepKey="waitForProductPageIsOpened"/> + + <!--Apply Cart Rule On Storefront--> + <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartRule"> + <argument name="product" value="$$simpleProduct$$"/> + <argument name="couponCode" value="{{_defaultCoupon.code}}"/> + </actionGroup> + <waitForText userInput='You used coupon code "{{_defaultCoupon.code}}"' stepKey="waitForSuccessMessage"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput='You used coupon code "{{_defaultCoupon.code}}"' + stepKey="seeSuccessMessageUsedCouponCode"/> + <waitForElementVisible selector="{{StorefrontCheckoutCartSummarySection.discountAmount}}" time="30" + stepKey="waitForElementVisible"/> + + <!--Navigate to Checkout--> + <actionGroup ref="NavigateToCheckoutActionGroup" stepKey="navigateToCheckout"/> + + <!--Place Order with Free Shipping--> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> + <argument name="shippingMethod" value="Free Shipping"/> + </actionGroup> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="checkoutPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + + <!--Verify that Created order is in Processing status--> + <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> + <argument name="orderId" value="$grabOrderNumber"/> + </actionGroup> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Processing" + stepKey="seeOrderStatus"/> + </test> +</tests> diff --git a/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml b/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml new file mode 100644 index 0000000000000..67f13f624760f --- /dev/null +++ b/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml @@ -0,0 +1,33 @@ +<?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="ZeroSubtotalCheckoutPaymentMethodConfig" type="zero_subtotal_checkout_payment_method"> + <requiredEntity type="active">active</requiredEntity> + <requiredEntity type="order_status">orderStatus</requiredEntity> + </entity> + + <entity name="active" type="active"> + <data key="value">1</data> + </entity> + <entity name="orderStatus" type="order_status"> + <data key="value">processing</data> + </entity> + + <entity name="ZeroSubtotalCheckoutPaymentMethodDefault" type="zero_subtotal_checkout_payment_method"> + <requiredEntity type="active">ZeroSubtotalCheckoutEnable</requiredEntity> + <requiredEntity type="order_status">ZeroSubtotalCheckoutOrderStatus</requiredEntity> + </entity> + + <entity name="ZeroSubtotalCheckoutEnable" type="active"> + <data key="value">1</data> + </entity> + <entity name="ZeroSubtotalCheckoutOrderStatus" type="order_status"> + <data key="value">pending</data> + </entity> +</entities> diff --git a/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml b/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml new file mode 100644 index 0000000000000..7f57f278b3ab9 --- /dev/null +++ b/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml @@ -0,0 +1,25 @@ +<?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="ZeroSubtotalCheckoutPaymentMethodSetup" dataType="zero_subtotal_checkout_payment_method" + type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> + <object key="groups" dataType="zero_subtotal_checkout_payment_method"> + <object key="free" dataType="zero_subtotal_checkout_payment_method"> + <object key="fields" dataType="zero_subtotal_checkout_payment_method"> + <object key="active" dataType="active"> + <field key="value">string</field> + </object> + <object key="order_status" dataType="order_status"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Payment/etc/config.xml b/app/code/Magento/Payment/etc/config.xml index 9fe859c96a941..663734fb066c7 100644 --- a/app/code/Magento/Payment/etc/config.xml +++ b/app/code/Magento/Payment/etc/config.xml @@ -13,6 +13,7 @@ <model>Magento\Payment\Model\Method\Free</model> <order_status>pending</order_status> <title>No Payment Information Required + authorize 0 1 From 3fc1a5891c0b82ee06fa0f617b71895c0ae45c2b Mon Sep 17 00:00:00 2001 From: Viktor Petryk Date: Wed, 31 Oct 2018 11:04:26 +0200 Subject: [PATCH 09/49] MAGETWO-72877: Zero Subtotal Orders have incorrect status --- ...SubtotalOrdersWithProcessingStatusTest.xml | 30 ++++--------------- ...CartPriceRuleSpecificCouponActionGroup.xml | 23 ++++++++++++++ .../SalesRule/Test/Mftf/Data/CouponData.xml | 2 +- .../Test/Mftf/Data/SalesRuleData.xml | 3 ++ 4 files changed, 33 insertions(+), 25 deletions(-) create mode 100644 app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleSpecificCouponActionGroup.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml index 3110256e274e7..30b1b3bfadcf4 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml @@ -29,7 +29,7 @@ - + @@ -39,28 +39,10 @@ - - - - - - - - - - - - - - + + + + @@ -89,7 +71,7 @@ - + diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleSpecificCouponActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleSpecificCouponActionGroup.xml new file mode 100644 index 0000000000000..4801a033dfc6e --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminCreateCartPriceRuleSpecificCouponActionGroup.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/CouponData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/CouponData.xml index a99c15a1f2dd9..d06903d5fd5d9 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/CouponData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/CouponData.xml @@ -11,7 +11,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> 4 - FREESHIPPING123 + FREESHIPPING123 0 false diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index 35ad7f96bd18d..28d61e34339ef 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -82,4 +82,7 @@ 2 1 + + 100 + From 194efb28b304614dfb1b77a34d04772924bbd84a Mon Sep 17 00:00:00 2001 From: Viktor Sevch Date: Wed, 31 Oct 2018 12:08:34 +0200 Subject: [PATCH 10/49] MAGETWO-89377: Cannot set Phone Number not required --- .../AdminCheckCustomerInGridActionGroup.xml | 27 +++++++++++++++++++ .../Test/Mftf/Page/AdminEditCustomerPage.xml | 2 ++ .../Test/Mftf/Page/AdminNewCustomerPage.xml | 3 +++ .../AdminCustomerAccountAddressSection.xml | 13 +++++++++ ...AdminCustomerAccountEditAddressSection.xml | 18 +++++++++++++ .../view/base/ui_component/customer_form.xml | 3 --- 6 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml new file mode 100644 index 0000000000000..5aa73c6483ab5 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml index 9a28bad4e0d6a..72d5d90bdc05f 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml @@ -10,5 +10,7 @@
+
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerPage.xml index b508409d37a01..1b73441dd149d 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminNewCustomerPage.xml @@ -11,5 +11,8 @@
+
+
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml new file mode 100644 index 0000000000000..db9619dde671f --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml @@ -0,0 +1,13 @@ + + +
+ + +
+
diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml new file mode 100644 index 0000000000000..bb9ef486cfd6c --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml @@ -0,0 +1,18 @@ + + +
+ + + + + + + +
+
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 4de6644b948fb..d2a9b3f44624d 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 @@ -486,9 +486,6 @@ - - true - text From b0604ecdb18c0af24595081b45ed352cf6511f9c Mon Sep 17 00:00:00 2001 From: Dmytro Drozd Date: Wed, 31 Oct 2018 16:23:42 +0200 Subject: [PATCH 11/49] MAGETWO-96027: Invalid element declared for AdminProductGridSection section --- .../AdminProductGridActionGroup.xml | 23 +++++++++++++ .../Mftf/Section/AdminProductGridSection.xml | 1 + ...atusProductUsingProductGridActionGroup.xml | 33 ------------------- .../Mftf/Section/AdminProductGridSection.xml | 14 -------- 4 files changed, 24 insertions(+), 47 deletions(-) delete mode 100644 app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml delete mode 100644 app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml index 408586d603835..3c4e83aabd047 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductGridActionGroup.xml @@ -51,4 +51,27 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml index 569b20a9c1479..6ffecc341123d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductGridSection.xml @@ -26,5 +26,6 @@ +
diff --git a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml b/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml deleted file mode 100644 index dba4a94f3db2a..0000000000000 --- a/app/code/Magento/Quote/Test/Mftf/ActionGroup/ChangeStatusProductUsingProductGridActionGroup.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml b/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml deleted file mode 100644 index 32ac73aca7c03..0000000000000 --- a/app/code/Magento/Quote/Test/Mftf/Section/AdminProductGridSection.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - -
- -
-
From e5a90d843bcfe70cb92e8ed3c7d08313049ce9e8 Mon Sep 17 00:00:00 2001 From: Viktor Sevch Date: Wed, 31 Oct 2018 17:14:53 +0200 Subject: [PATCH 12/49] MAGETWO-89377: Cannot set Phone Number not required --- .../AdminCheckCustomerInGridActionGroup.xml | 13 +++++-------- .../AdminCustomerAccountEditAddressSection.xml | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml index 5aa73c6483ab5..59925da01a7ad 100644 --- a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminCheckCustomerInGridActionGroup.xml @@ -6,22 +6,19 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - - - + + - - + - - + diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml index bb9ef486cfd6c..0f64c675ead49 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountEditAddressSection.xml @@ -7,9 +7,9 @@
- - - + + + From 6940d20efb565077c18402f2e4d9e0e29274b973 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun Date: Thu, 1 Nov 2018 11:54:03 +0200 Subject: [PATCH 13/49] MAGETWO-73528: Out of stock associated products to configurable are not full page cache cleaned #8009 --- .../Catalog/Test/Mftf/Data/ProductData.xml | 4 + .../Data/ProductExtensionAttributeData.xml | 3 + .../Catalog/Test/Mftf/Data/StockItemData.xml | 4 + .../Model/Indexer/Stock/CacheCleaner.php | 40 +++++++- ...tedProductToConfigurableOutOfStockTest.xml | 91 +++++++++++++++++++ .../Model/Indexer/Stock/CacheCleanerTest.php | 22 ++++- .../Mftf/ActionGroup/CheckoutActionGroup.xml | 7 ++ ...reateApiConfigurableProductActionGroup.xml | 10 ++ .../StorefrontProductInfoMainSection.xml | 1 + 9 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 007529a06d9f4..298b51d7fbac0 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -263,4 +263,8 @@ EavStockItem CustomAttributeCategoryIds + + 1 + EavStock1 + diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml index 0f6b383c3b743..5424e48261085 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml @@ -11,4 +11,7 @@ Qty_1000 + + Qty_1 + diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml index 46a3fa3657f2c..99e072b91c3a9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml @@ -12,4 +12,8 @@ 1000 true + + 1 + true + diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php index a32faa4640a86..b3fa07479a712 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php @@ -10,8 +10,10 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Indexer\CacheContext; use Magento\CatalogInventory\Model\Stock; use Magento\Catalog\Model\Product; @@ -46,25 +48,35 @@ class CacheCleaner */ private $connection; + /** + * @var MetadataPool + */ + private $metadataPool; + /** * @param ResourceConnection $resource * @param StockConfigurationInterface $stockConfiguration * @param CacheContext $cacheContext * @param ManagerInterface $eventManager + * @param MetadataPool|null $metadataPool */ public function __construct( ResourceConnection $resource, StockConfigurationInterface $stockConfiguration, CacheContext $cacheContext, - ManagerInterface $eventManager + ManagerInterface $eventManager, + MetadataPool $metadataPool = null ) { $this->resource = $resource; $this->stockConfiguration = $stockConfiguration; $this->cacheContext = $cacheContext; $this->eventManager = $eventManager; + $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class); } /** + * Clean cache by product ids. + * * @param array $productIds * @param callable $reindex * @return void @@ -76,22 +88,37 @@ public function clean(array $productIds, callable $reindex) $productStatusesAfter = $this->getProductStockStatuses($productIds); $productIds = $this->getProductIdsForCacheClean($productStatusesBefore, $productStatusesAfter); if ($productIds) { - $this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds); + $this->cacheContext->registerEntities(Product::CACHE_TAG, array_unique($productIds)); $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]); } } /** + * Get current stock statuses for product ids. + * * @param array $productIds * @return array */ private function getProductStockStatuses(array $productIds) { + $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); $select = $this->getConnection()->select() ->from( - $this->resource->getTableName('cataloginventory_stock_status'), + ['css' => $this->resource->getTableName('cataloginventory_stock_status')], ['product_id', 'stock_status', 'qty'] - )->where('product_id IN (?)', $productIds) + ) + ->joinLeft( + ['cpr' => $this->resource->getTableName('catalog_product_relation')], + 'css.product_id = cpr.child_id', + [] + ) + ->joinLeft( + ['cpe' => $this->resource->getTableName('catalog_product_entity')], + 'cpr.parent_id = cpe.' . $linkField, + ['parent_id' => 'cpe.entity_id'] + ) + ->where('product_id IN (?)', $productIds) ->where('stock_id = ?', Stock::DEFAULT_STOCK_ID) ->where('website_id = ?', $this->stockConfiguration->getDefaultScopeId()); @@ -125,6 +152,9 @@ private function getProductIdsForCacheClean(array $productStatusesBefore, array if ($statusBefore['stock_status'] !== $statusAfter['stock_status'] || ($stockThresholdQty && $statusAfter['qty'] <= $stockThresholdQty)) { $productIds[] = $productId; + if (isset($statusAfter['parent_id'])) { + $productIds[] = $statusAfter['parent_id']; + } } } @@ -132,6 +162,8 @@ private function getProductIdsForCacheClean(array $productStatusesBefore, array } /** + * Get database connection. + * * @return AdapterInterface */ private function getConnection() diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml new file mode 100644 index 0000000000000..9a5ad027da600 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml @@ -0,0 +1,91 @@ + + + + + + + + + + <description value="After last configurable product was ordered it becomes out of stock"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-96031"/> + <group value="CatalogInventory"/> + </annotations> + + <before> + <!--Create Configurable product--> + <actionGroup ref="AdminCreateConfigurableProductChildQty1ActionGroup" stepKey="createConfigurableProduct"> + <argument name="productName" value="ApiConfigurableProduct"/> + </actionGroup> + <!-- Create customer --> + <createData entity="Simple_US_Customer" stepKey="createSimpleUsCustomer"> + <field key="group_id">1</field> + </createData> + <!--Update index mode, reindex, flush cache--> + <magentoCLI command="indexer:set-mode schedule" stepKey="setScheduleIndexMode"/> + <magentoCLI command="indexer:reindex" stepKey="reindexBefore"/> + <magentoCLI command="cache:flush" stepKey="cacheFlushBefore"/> + </before> + + <after> + <!--Delete configurable product--> + <deleteData createDataKey="createConfigProductCreateConfigurableProduct" stepKey="deleteConfigProduct"/> + <deleteData createDataKey="createConfigChildProduct1CreateConfigurableProduct" stepKey="deleteConfigChildProduct"/> + <deleteData createDataKey="createConfigChildProduct2CreateConfigurableProduct" stepKey="deleteConfigChildProduct1"/> + <deleteData createDataKey="createConfigProductAttributeCreateConfigurableProduct" stepKey="deleteConfigProductAttribute"/> + <!--Delete customer--> + <deleteData createDataKey="createSimpleUsCustomer" stepKey="deleteCustomer"/> + <!--Update index mode, reindex, flush cache--> + <magentoCLI command="indexer:set-mode realtime" stepKey="setRealTimeIndexMode"/> + <magentoCLI command="indexer:reindex" stepKey="reindexAfter"/> + <magentoCLI command="cache:flush" stepKey="cacheFlushAfter"/> + </after> + + <!-- Login as a customer --> + <actionGroup ref="CustomerLoginOnStorefront" stepKey="signUpNewUser"> + <argument name="customer" value="$$createSimpleUsCustomer$$"/> + </actionGroup> + + <!-- Go to configurable product page --> + <amOnPage url="{{StorefrontProductPage.url('apiconfigurableproduct')}}" stepKey="goToConfigurableProductPage"/> + + <!-- Order product with single quantity --> + <selectOption userInput="$$createConfigProductAttributeOption1CreateConfigurableProduct.option[store_labels][1][label]$$" + selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttributeCreateConfigurableProduct.attribute_id$$)}}" + stepKey="configProductFillOption" + /> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectShippingMehod"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeorder"> + <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage" /> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> + </actionGroup> + + <!--Run cron to reindex products--> + <magentoCLI command="cron:run --group='index'" stepKey="runCron"/> + <magentoCLI command="cron:run --group='index'" stepKey="runCron1"/> + + <!-- Go to configurable product page --> + <amOnPage url="{{StorefrontProductPage.url('apiconfigurableproduct')}}" stepKey="goToConfigurableProductPage1"/> + + <!-- Assert that ordered product with single quantity is not available for order --> + <dontSee userInput="$$createConfigProductAttributeOption1CreateConfigurableProduct.option[store_labels][1][label]$$" + selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttributeCreateConfigurableProduct.attribute_id$$)}}" + stepKey="assertOptionNotAvailable" + /> + + <!-- Logout customer on Storefront--> + <actionGroup ref="CustomerLogoutStorefrontActionGroup" stepKey="customerLogoutStorefront"/> + </test> +</tests> diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php index 5e4249685f8d3..a1282c45ce1fc 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php @@ -12,6 +12,7 @@ use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Select; use Magento\Framework\Event\ManagerInterface; +use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Indexer\CacheContext; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Catalog\Model\Product; @@ -43,6 +44,11 @@ class CacheCleanerTest extends \PHPUnit\Framework\TestCase */ private $cacheContextMock; + /** + * @var MetadataPool |\PHPUnit_Framework_MockObject_MockObject + */ + private $metadataPoolMock; + /** * @var StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject */ @@ -61,6 +67,8 @@ protected function setUp() ->setMethods(['getStockThresholdQty'])->getMockForAbstractClass(); $this->cacheContextMock = $this->getMockBuilder(CacheContext::class)->disableOriginalConstructor()->getMock(); $this->eventManagerMock = $this->getMockBuilder(ManagerInterface::class)->getMock(); + $this->metadataPoolMock = $this->getMockBuilder(MetadataPool::class) + ->setMethods(['getMetadata', 'getLinkField'])->disableOriginalConstructor()->getMock(); $this->selectMock = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock(); $this->resourceMock->expects($this->any()) @@ -73,7 +81,8 @@ protected function setUp() 'resource' => $this->resourceMock, 'stockConfiguration' => $this->stockConfigurationMock, 'cacheContext' => $this->cacheContextMock, - 'eventManager' => $this->eventManagerMock + 'eventManager' => $this->eventManagerMock, + 'metadataPool' => $this->metadataPoolMock, ] ); } @@ -90,6 +99,7 @@ public function testClean($stockStatusBefore, $stockStatusAfter, $qtyAfter, $sto $productId = 123; $this->selectMock->expects($this->any())->method('from')->willReturnSelf(); $this->selectMock->expects($this->any())->method('where')->willReturnSelf(); + $this->selectMock->expects($this->any())->method('joinLeft')->willReturnSelf(); $this->connectionMock->expects($this->exactly(2))->method('select')->willReturn($this->selectMock); $this->connectionMock->expects($this->exactly(2))->method('fetchAll')->willReturnOnConsecutiveCalls( [ @@ -105,7 +115,10 @@ public function testClean($stockStatusBefore, $stockStatusAfter, $qtyAfter, $sto ->with(Product::CACHE_TAG, [$productId]); $this->eventManagerMock->expects($this->once())->method('dispatch') ->with('clean_cache_by_tags', ['object' => $this->cacheContextMock]); - + $this->metadataPoolMock->expects($this->exactly(2))->method('getMetadata') + ->willReturnSelf(); + $this->metadataPoolMock->expects($this->exactly(2))->method('getLinkField') + ->willReturn('row_id'); $callback = function () { }; $this->unit->clean([], $callback); @@ -136,6 +149,7 @@ public function testNotCleanCache($stockStatusBefore, $stockStatusAfter, $qtyAft $productId = 123; $this->selectMock->expects($this->any())->method('from')->willReturnSelf(); $this->selectMock->expects($this->any())->method('where')->willReturnSelf(); + $this->selectMock->expects($this->any())->method('joinLeft')->willReturnSelf(); $this->connectionMock->expects($this->exactly(2))->method('select')->willReturn($this->selectMock); $this->connectionMock->expects($this->exactly(2))->method('fetchAll')->willReturnOnConsecutiveCalls( [ @@ -149,6 +163,10 @@ public function testNotCleanCache($stockStatusBefore, $stockStatusAfter, $qtyAft ->willReturn($stockThresholdQty); $this->cacheContextMock->expects($this->never())->method('registerEntities'); $this->eventManagerMock->expects($this->never())->method('dispatch'); + $this->metadataPoolMock->expects($this->exactly(2))->method('getMetadata') + ->willReturnSelf(); + $this->metadataPoolMock->expects($this->exactly(2))->method('getLinkField') + ->willReturn('row_id'); $callback = function () { }; diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index db747dbdba657..aa168899ddb02 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> <!-- Checkout select Check/Money Order payment --> <actionGroup name="CheckoutSelectCheckMoneyOrderPaymentActionGroup"> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> <conditionalClick selector="{{CheckoutPaymentSection.checkMoneyOrderPayment}}" dependentSelector="{{CheckoutPaymentSection.checkMoneyOrderPayment}}" visible="true" stepKey="clickCheckMoneyOrderPayment"/> </actionGroup> @@ -66,4 +67,10 @@ <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <see selector="{{CheckoutSuccessMainSection.successTitle}}" userInput="Thank you for your purchase!" stepKey="waitForLoadSuccessPage"/> </actionGroup> + + <!-- Checkout select Flat Rate shipping method --> + <actionGroup name="CheckoutSelectFlatRateShippingMethodActionGroup"> + <conditionalClick selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" dependentSelector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" visible="true" stepKey="selectFlatRateShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForNextButton"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml index 75686d23a11b9..fafbe84fe568e 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -62,4 +62,14 @@ <requiredEntity createDataKey="createConfigChildProduct2"/> </createData> </actionGroup> + + <actionGroup name="AdminCreateConfigurableProductChildQty1ActionGroup" extends="AdminCreateApiConfigurableProductActionGroup"> + <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"> + <field key="name">{{productName}}</field> + </createData> + <createData entity="ApiSimpleSingleQty" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml index 996a392230eea..be0c2b05e48ba 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -13,5 +13,6 @@ <element name="productAttributeOptions" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> <element name="stockIndication" type="block" selector=".stock" /> <element name="productAttributeOptionsSelectButton" type="select" selector="#product-options-wrapper .super-attribute-select"/> + <element name="optionByAttributeId" type="input" selector="#attribute{{var1}}" parameterized="true"/> </section> </sections> From e6149ffcb653f105fe24c7a29374ba875570bc08 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Thu, 1 Nov 2018 14:17:25 +0200 Subject: [PATCH 14/49] MAGETWO-72877: Zero Subtotal Orders have incorrect status --- ...ubtotalOrdersWithProcessingStatusTest.xml} | 5 ++--- .../ZeroSubtotalCheckoutPaymentMethodData.xml | 22 ++++++++----------- .../Mftf/Metadata/payment_method-meta.xml | 3 ++- 3 files changed, 13 insertions(+), 17 deletions(-) rename app/code/Magento/Checkout/Test/Mftf/Test/{ZeroSubtotalOrdersWithProcessingStatusTest.xml => AdminZeroSubtotalOrdersWithProcessingStatusTest.xml} (95%) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml similarity index 95% rename from app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml rename to app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml index 30b1b3bfadcf4..4188b1b1d2443 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/ZeroSubtotalOrdersWithProcessingStatusTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="ZeroSubtotalOrdersWithProcessingStatusTest"> + <test name="AdminZeroSubtotalOrdersWithProcessingStatusTest"> <annotations> <features value="Checkout"/> <stories value="MAGETWO-72877: Zero Subtotal Orders have incorrect status"/> @@ -46,7 +46,6 @@ <!--Open Product Page--> <amOnPage url="{{StorefrontProductPage.url($$simpleProduct.name$$)}}" stepKey="openProductPage"/> - <waitForPageLoad time="30" stepKey="waitForProductPageIsOpened"/> <!--Apply Cart Rule On Storefront--> <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartRule"> @@ -73,7 +72,7 @@ <actionGroup ref="filterOrderGridById" stepKey="filterOrderGridById"> <argument name="orderId" value="{$grabOrderNumber}"/> </actionGroup> - <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <click selector="{{AdminDataGridTableSection.firstRow}}" stepKey="clickOrderRow"/> <waitForPageLoad stepKey="waitForCreatedOrderPageOpened"/> <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderStatus"/> diff --git a/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml b/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml index 67f13f624760f..0a9d6b66af6f9 100644 --- a/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml +++ b/app/code/Magento/Payment/Test/Mftf/Data/ZeroSubtotalCheckoutPaymentMethodData.xml @@ -8,26 +8,22 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="ZeroSubtotalCheckoutPaymentMethodConfig" type="zero_subtotal_checkout_payment_method"> - <requiredEntity type="active">active</requiredEntity> - <requiredEntity type="order_status">orderStatus</requiredEntity> + <requiredEntity type="active">Active</requiredEntity> + <requiredEntity type="order_status">OrderStatusProcessing</requiredEntity> </entity> - <entity name="active" type="active"> + <entity name="Active" type="active"> <data key="value">1</data> </entity> - <entity name="orderStatus" type="order_status"> + <entity name="OrderStatusProcessing" type="order_status"> <data key="value">processing</data> </entity> - - <entity name="ZeroSubtotalCheckoutPaymentMethodDefault" type="zero_subtotal_checkout_payment_method"> - <requiredEntity type="active">ZeroSubtotalCheckoutEnable</requiredEntity> - <requiredEntity type="order_status">ZeroSubtotalCheckoutOrderStatus</requiredEntity> + <entity name="OrderStatusPending" type="order_status"> + <data key="value">pending</data> </entity> - <entity name="ZeroSubtotalCheckoutEnable" type="active"> - <data key="value">1</data> - </entity> - <entity name="ZeroSubtotalCheckoutOrderStatus" type="order_status"> - <data key="value">pending</data> + <entity name="ZeroSubtotalCheckoutPaymentMethodDefault" type="zero_subtotal_checkout_payment_method"> + <requiredEntity type="active">Active</requiredEntity> + <requiredEntity type="order_status">OrderStatusPending</requiredEntity> </entity> </entities> diff --git a/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml b/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml index 7f57f278b3ab9..b1e3577b9ccad 100644 --- a/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml +++ b/app/code/Magento/Payment/Test/Mftf/Metadata/payment_method-meta.xml @@ -8,7 +8,8 @@ <operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> <operation name="ZeroSubtotalCheckoutPaymentMethodSetup" dataType="zero_subtotal_checkout_payment_method" - type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST"> + type="create" auth="adminFormKey" url="/admin/system_config/save/section/payment/" method="POST" + successRegex="/messages-message-success/"> <object key="groups" dataType="zero_subtotal_checkout_payment_method"> <object key="free" dataType="zero_subtotal_checkout_payment_method"> <object key="fields" dataType="zero_subtotal_checkout_payment_method"> From 0ac1a493fdf265746d865f17d54e234d0d8789f0 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Thu, 1 Nov 2018 17:39:11 +0200 Subject: [PATCH 15/49] MAGETWO-72877: Zero Subtotal Orders have incorrect status --- .../Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml index 4188b1b1d2443..b5d3d55194dd3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminZeroSubtotalOrdersWithProcessingStatusTest.xml @@ -65,6 +65,8 @@ <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> <argument name="shippingMethod" value="Free Shipping"/> </actionGroup> + <see selector="{{CheckoutPaymentSection.notAvailablePaymentSolutions}}" + userInput="No Payment Information Required" stepKey="seePaymentInformation"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="checkoutPlaceOrder"/> <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> From 7e7faa3f0daa42ad06a25bbdf6943a52625f5056 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 2 Nov 2018 11:25:31 +0200 Subject: [PATCH 16/49] MAGETWO-73528: Out of stock associated products to configurable are not full page cache cleaned #8009 --- .../Test/AssociatedProductToConfigurableOutOfStockTest.xml | 6 +++--- .../AdminCreateApiConfigurableProductActionGroup.xml | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml index 9a5ad027da600..735b7fe4f00d0 100644 --- a/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml +++ b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml @@ -11,8 +11,8 @@ <test name="AssociatedProductToConfigurableOutOfStockTest"> <annotations> <features value="CatalogInventory"/> - <stories value="Add/remove images and videos for all product types and category"/> - <title value="Out of stock associated products to configurable are not full page cache cleaned "/> + <stories value="MAGETWO-73528: Out of stock associated products to configurable are not full page cache cleaned"/> + <title value="Checking out of stock associated products to configurable after checkout - full page cache cleaned"/> <description value="After last configurable product was ordered it becomes out of stock"/> <severity value="MAJOR"/> <testCaseId value="MAGETWO-96031"/> @@ -67,7 +67,7 @@ <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectShippingMehod"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> - <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeorder"> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeOrder"> <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage" /> <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml index fafbe84fe568e..d918649ed4914 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml @@ -64,9 +64,6 @@ </actionGroup> <actionGroup name="AdminCreateConfigurableProductChildQty1ActionGroup" extends="AdminCreateApiConfigurableProductActionGroup"> - <createData entity="ApiConfigurableProductWithOutCategory" stepKey="createConfigProduct"> - <field key="name">{{productName}}</field> - </createData> <createData entity="ApiSimpleSingleQty" stepKey="createConfigChildProduct1"> <requiredEntity createDataKey="createConfigProductAttribute"/> <requiredEntity createDataKey="getConfigAttributeOption1"/> From 7443dc3194040e9ce2f7baf902470deb975b97c6 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Mon, 5 Nov 2018 14:28:12 +0200 Subject: [PATCH 17/49] MAGETWO-96079: Cannot update password using received link --- app/code/Magento/Customer/Model/AccountManagement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index 8f2565189ef4c..b5b1905e68d8d 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -670,8 +670,8 @@ public function resetPassword($email, $resetToken, $newPassword) $customerSecure->setRpTokenCreatedAt(null); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); $this->getAuthentication()->unlock($customer->getId()); - $this->sessionManager->destroy(); $this->destroyCustomerSessions($customer->getId()); + $this->sessionManager->destroy(); $this->customerRepository->save($customer); return true; From a7f1c7d1df5e8575366b6743d77b2a6528ab7197 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 5 Nov 2018 14:35:47 +0200 Subject: [PATCH 18/49] MAGETWO-95781: The value Quantity of Advenced Pricing isn't saved correctly --- .../Backend/TierPrice/AbstractHandler.php | 97 +++++++++++++++++++ .../Backend/TierPrice/SaveHandler.php | 63 +----------- .../Backend/TierPrice/UpdateHandler.php | 81 +++------------- 3 files changed, 113 insertions(+), 128 deletions(-) create mode 100644 app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php new file mode 100644 index 0000000000000..2501c466fc57c --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Model\Product\Attribute\Backend\TierPrice; + +use Magento\Framework\EntityManager\Operation\ExtensionInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Customer\Api\GroupManagementInterface; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice; + +/** + * Tier price data abstract handler. + */ +abstract class AbstractHandler implements ExtensionInterface +{ + /** + * @var \Magento\Customer\Api\GroupManagementInterface + */ + protected $groupManagement; + + /** + * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement + */ + public function __construct( + GroupManagementInterface $groupManagement + ) { + $this->groupManagement = $groupManagement; + } + + /** + * Get additional tier price fields. + * + * @return array + */ + protected function getAdditionalFields(array $objectArray): array + { + $percentageValue = $this->getPercentage($objectArray); + + return [ + 'value' => $percentageValue ? null : $objectArray['price'], + 'percentage_value' => $percentageValue ?: null, + ]; + } + + /** + * Check whether price has percentage value. + * + * @param array $priceRow + * @return integer|null + */ + protected function getPercentage(array $priceRow) + { + return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value']) + ? (int)$priceRow['percentage_value'] + : null; + } + + /** + * Prepare tier price data by provided price row data. + * + * @param array $data + * @return array + */ + protected function prepareTierPrice(array $data): array + { + $useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId(); + $customerGroupId = $useForAllGroups ? 0 : $data['cust_group']; + $tierPrice = array_merge( + $this->getAdditionalFields($data), + [ + 'website_id' => $data['website_id'], + 'all_groups' => (int)$useForAllGroups, + 'customer_group_id' => $customerGroupId, + 'value' => $data['price'] ?? null, + 'qty' => $this->parseQty($data['price_qty']), + ] + ); + + return $tierPrice; + } + + /** + * Parse quantity value into float. + * + * @param mixed $value + * @return float + */ + protected function parseQty($value): float + { + return floatval($value); + } +} diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php index 587865414129a..81811f1a90ba0 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php @@ -16,7 +16,7 @@ /** * Process tier price data for handled new product */ -class SaveHandler implements ExtensionInterface +class SaveHandler extends AbstractHandler { /** * @var \Magento\Store\Model\StoreManagerInterface @@ -28,11 +28,6 @@ class SaveHandler implements ExtensionInterface */ private $attributeRepository; - /** - * @var \Magento\Customer\Api\GroupManagementInterface - */ - private $groupManagement; - /** * @var \Magento\Framework\EntityManager\MetadataPool */ @@ -62,6 +57,8 @@ public function __construct( $this->groupManagement = $groupManagement; $this->metadataPoll = $metadataPool; $this->tierPriceResource = $tierPriceResource; + + parent::__construct($groupManagement); } /** @@ -70,8 +67,6 @@ public function __construct( * @param \Magento\Catalog\Api\Data\ProductInterface|object $entity * @param array $arguments * @return \Magento\Catalog\Api\Data\ProductInterface|object - * @throws \Magento\Framework\Exception\NoSuchEntityException - * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\InputException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -113,56 +108,4 @@ public function execute($entity, $arguments = []) return $entity; } - - /** - * Get additional tier price fields - * - * @return array - */ - private function getAdditionalFields(array $objectArray): array - { - $percentageValue = $this->getPercentage($objectArray); - return [ - 'value' => $percentageValue ? null : $objectArray['price'], - 'percentage_value' => $percentageValue ?: null, - ]; - } - - /** - * Check whether price has percentage value. - * - * @param array $priceRow - * @return integer|null - */ - private function getPercentage(array $priceRow) - { - return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value']) - ? (int)$priceRow['percentage_value'] - : null; - } - - /** - * Prepare tier price data by provided price row data - * - * @param array $data - * @return array - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function prepareTierPrice(array $data): array - { - $useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId(); - $customerGroupId = $useForAllGroups ? 0 : $data['cust_group']; - $tierPrice = array_merge( - $this->getAdditionalFields($data), - [ - 'website_id' => $data['website_id'], - 'all_groups' => (int)$useForAllGroups, - 'customer_group_id' => $customerGroupId, - 'value' => $data['price'] ?? null, - 'qty' => (int)$data['price_qty'] - ] - ); - - return $tierPrice; - } } diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php index b23dc6f30f8fa..249da7fd8949b 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php @@ -14,9 +14,9 @@ use Magento\Catalog\Model\ResourceModel\Product\Attribute\Backend\Tierprice; /** - * Process tier price data for handled existing product + * Process tier price data for handled existing product. */ -class UpdateHandler implements ExtensionInterface +class UpdateHandler extends AbstractHandler { /** * @var \Magento\Store\Model\StoreManagerInterface @@ -28,11 +28,6 @@ class UpdateHandler implements ExtensionInterface */ private $attributeRepository; - /** - * @var \Magento\Customer\Api\GroupManagementInterface - */ - private $groupManagement; - /** * @var \Magento\Framework\EntityManager\MetadataPool */ @@ -59,17 +54,17 @@ public function __construct( ) { $this->storeManager = $storeManager; $this->attributeRepository = $attributeRepository; - $this->groupManagement = $groupManagement; $this->metadataPoll = $metadataPool; $this->tierPriceResource = $tierPriceResource; + + parent::__construct($groupManagement); } /** * @param \Magento\Catalog\Api\Data\ProductInterface|object $entity * @param array $arguments * @return \Magento\Catalog\Api\Data\ProductInterface|object - * @throws \Magento\Framework\Exception\NoSuchEntityException - * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\InputException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute($entity, $arguments = []) @@ -110,34 +105,6 @@ public function execute($entity, $arguments = []) return $entity; } - /** - * Get additional tier price fields - * - * @param array $objectArray - * @return array - */ - private function getAdditionalFields(array $objectArray): array - { - $percentageValue = $this->getPercentage($objectArray); - return [ - 'value' => $percentageValue ? null : $objectArray['price'], - 'percentage_value' => $percentageValue ?: null, - ]; - } - - /** - * Check whether price has percentage value. - * - * @param array $priceRow - * @return integer|null - */ - private function getPercentage(array $priceRow) - { - return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value']) - ? (int)$priceRow['percentage_value'] - : null; - } - /** * Update existing tier prices for processed product * @@ -168,7 +135,7 @@ private function updateValues(array $valuesToUpdate, array $oldValues): bool } /** - * Insert new tier prices for processed product + * Insert new tier prices for processed product. * * @param int $productId * @param array $valuesToInsert @@ -192,7 +159,7 @@ private function insertValues(int $productId, array $valuesToInsert): bool } /** - * Delete tier price values for processed product + * Delete tier price values for processed product. * * @param int $productId * @param array $valuesToDelete @@ -210,48 +177,24 @@ private function deleteValues(int $productId, array $valuesToDelete): bool } /** - * Get generated price key based on price data + * Get generated price key based on price data. * * @param array $priceData * @return string */ private function getPriceKey(array $priceData): string { + $qty = $this->parseQty($priceData['price_qty']); $key = implode( '-', - array_merge([$priceData['website_id'], $priceData['cust_group']], [(int)$priceData['price_qty']]) + array_merge([$priceData['website_id'], $priceData['cust_group']], [$qty]) ); return $key; } /** - * Prepare tier price data by provided price row data - * - * @param array $data - * @return array - * @throws \Magento\Framework\Exception\LocalizedException - */ - private function prepareTierPrice(array $data): array - { - $useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId(); - $customerGroupId = $useForAllGroups ? 0 : $data['cust_group']; - $tierPrice = array_merge( - $this->getAdditionalFields($data), - [ - 'website_id' => $data['website_id'], - 'all_groups' => (int)$useForAllGroups, - 'customer_group_id' => $customerGroupId, - 'value' => $data['price'] ?? null, - 'qty' => (int)$data['price_qty'] - ] - ); - - return $tierPrice; - } - - /** - * Check by id is website global + * Check by id is website global. * * @param int $websiteId * @return bool @@ -282,6 +225,8 @@ private function prepareOriginalDataToCompare($origPrices, $isGlobal = true): ar } /** + * Prepare new data for save. + * * @param array $priceRows * @param bool $isGlobal * @return array From f7028c29ddd197add07d36f64d15fa079aa349af Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 5 Nov 2018 16:33:24 +0200 Subject: [PATCH 19/49] MAGETWO-95781: The value Quantity of Advenced Pricing isn't saved correctly --- .../Backend/TierPrice/AbstractHandler.php | 6 +- .../Attribute/Backend/TierpriceTest.php | 66 ++++++++++++++----- .../Magento/Catalog/_files/product_simple.php | 10 +++ 3 files changed, 61 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php index 2501c466fc57c..6439374accec7 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/AbstractHandler.php @@ -88,10 +88,10 @@ protected function prepareTierPrice(array $data): array * Parse quantity value into float. * * @param mixed $value - * @return float + * @return float|int */ - protected function parseQty($value): float + protected function parseQty($value) { - return floatval($value); + return $value * 1; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php index 9e41b61efff38..ec8de0b18fcf5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php @@ -66,27 +66,46 @@ public function testValidate() [ ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 5.6, 'price' => 4], ] ); $this->assertTrue($this->_model->validate($product)); } /** + * Test that duplicated tier price values issues exception during validation. + * * @expectedException \Magento\Framework\Exception\LocalizedException */ - public function testValidateDuplicate() + public function testValidateDuplicate(array $tierPricesData) { $product = new \Magento\Framework\DataObject(); - $product->setTierPrice( - [ - ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], - ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], - ] - ); + $product->setTierPrice($tierPricesData); $this->_model->validate($product); } + /** + * @return array + */ + public function testValidateDuplicateDataProvider(): array + { + return [ + [ + [ + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], + ], + ], + [ + [ + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2.2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2.2, 'price' => 8], + ], + ], + ]; + } + /** * @expectedException \Magento\Framework\Exception\LocalizedException */ @@ -95,9 +114,9 @@ public function testValidateDuplicateWebsite() $product = new \Magento\Framework\DataObject(); $product->setTierPrice( [ - ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], - ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 5, 'price' => 5], - ['website_id' => 1, 'cust_group' => 1, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2.2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 5.3, 'price' => 5], + ['website_id' => 1, 'cust_group' => 1, 'price_qty' => 5.3, 'price' => 5], ] ); @@ -125,12 +144,17 @@ public function testPreparePriceData() ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 2, 'price' => 8], ['website_id' => 0, 'cust_group' => 1, 'price_qty' => 5, 'price' => 5], ['website_id' => 1, 'cust_group' => 1, 'price_qty' => 5, 'price' => 5], + ['website_id' => 1, 'cust_group' => 1, 'price_qty' => 5.3, 'price' => 4], + ['website_id' => 1, 'cust_group' => 1, 'price_qty' => 5.4, 'price' => 3], + ['website_id' => 1, 'cust_group' => 1, 'price_qty' => '5.40', 'price' => 2], ]; $newData = $this->_model->preparePriceData($data, \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE, 1); - $this->assertEquals(2, count($newData)); + $this->assertEquals(4, count($newData)); $this->assertArrayHasKey('1-2', $newData); $this->assertArrayHasKey('1-5', $newData); + $this->assertArrayHasKey('1-5.3', $newData); + $this->assertArrayHasKey('1-5.4', $newData); } public function testAfterLoad() @@ -146,7 +170,7 @@ public function testAfterLoad() $this->_model->afterLoad($product); $price = $product->getTierPrice(); $this->assertNotEmpty($price); - $this->assertEquals(4, count($price)); + $this->assertEquals(5, count($price)); } /** @@ -185,6 +209,7 @@ public function saveExistingProductDataProvider(): array ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8], ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5], ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3.2, 'value' => 6], [ 'website_id' => 0, 'customer_group_id' => 0, @@ -192,13 +217,14 @@ public function saveExistingProductDataProvider(): array 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) ], ], - 4, + 5, ], 'update one' => [ [ ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8], ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5], ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => '3.2', 'value' => 6], [ 'website_id' => 0, 'customer_group_id' => 0, @@ -206,12 +232,13 @@ public function saveExistingProductDataProvider(): array 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 10]) ], ], - 4, + 5, ], 'delete one' => [ [ ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5], ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => '3.2', 'value' => 6], [ 'website_id' => 0, 'customer_group_id' => 0, @@ -219,13 +246,14 @@ public function saveExistingProductDataProvider(): array 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) ], ], - 3, + 4, ], 'add one' => [ [ ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8], ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5], ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3.2, 'value' => 6], [ 'website_id' => 0, 'customer_group_id' => 32000, @@ -239,7 +267,7 @@ public function saveExistingProductDataProvider(): array 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) ], ], - 5, + 6, ], 'delete all' => [[], 0,], ]; @@ -268,7 +296,7 @@ public function testSaveNewProduct(array $tierPricesData, $tierPriceCount) $tierPrices = []; foreach ($tierPricesData as $tierPrice) { $tierPrices[] = $this->tierPriceFactory->create([ - 'data' => $tierPrice + 'data' => $tierPrice, ]); } $product->setTierPrices($tierPrices); @@ -288,6 +316,8 @@ public function saveNewProductDataProvider(): array ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8], ['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5], ['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => '3.2', 'value' => 4], + ['website_id' => 0, 'customer_group_id' => 0, 'qty' => '3.3', 'value' => 3], [ 'website_id' => 0, 'customer_group_id' => 0, @@ -295,7 +325,7 @@ public function saveNewProductDataProvider(): array 'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50]) ], ], - 4, + 6, ], ]; } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php index 0d07b8c913e14..dd43b403749d7 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php @@ -60,6 +60,16 @@ ] )->setExtensionAttributes($tierPriceExtensionAttributes1); +$tierPrices[] = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID, + 'qty' => 3.2, + 'value' => 6 + ] + ] +)->setExtensionAttributes($tierPriceExtensionAttributes1); + $tierPriceExtensionAttributes2 = $tpExtensionAttributesFactory->create() ->setWebsiteId($adminWebsite->getId()) ->setPercentageValue(50); From 53571e6ea024c3548a40aa886bd4eaf29baa0f88 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 5 Nov 2018 18:39:20 +0200 Subject: [PATCH 20/49] MAGETWO-96076: In field "Street Address" not present require icon --- .../Magento/Catalog/Api/ProductTierPriceManagementTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php index 7df0aede46b26..f08107626663f 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductTierPriceManagementTest.php @@ -51,7 +51,7 @@ public function testGetList($customerGroupId, $count, $value, $qty) public function getListDataProvider() { return [ - [0, 2, 5, 3], + [0, 3, 5, 3], [1, 0, null, null], ['all', 2, 8, 2], ]; From 3d8b8d2b056e173f7a47e21d832ed2afeb3f7f6c Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 5 Nov 2018 18:55:19 +0200 Subject: [PATCH 21/49] MAGETWO-95781: The value Quantity of Advenced Pricing isn't saved correctly --- .../Catalog/Model/Product/Attribute/Backend/TierpriceTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php index ec8de0b18fcf5..5651d1658fed8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php @@ -75,6 +75,7 @@ public function testValidate() /** * Test that duplicated tier price values issues exception during validation. * + * @dataProvider testValidateDuplicateDataProvider * @expectedException \Magento\Framework\Exception\LocalizedException */ public function testValidateDuplicate(array $tierPricesData) @@ -86,6 +87,8 @@ public function testValidateDuplicate(array $tierPricesData) } /** + * testValidateDuplicate data provider. + * * @return array */ public function testValidateDuplicateDataProvider(): array From 9fe5066481ba9aee47c921d8e1ac64b18ee7b8c7 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Tue, 6 Nov 2018 11:15:28 +0200 Subject: [PATCH 22/49] MAGETWO-86292: Unable to create Credit memo for order with no payment required - Credit memo fix - Add automated test - Fix static tests - Fix integration tests --- app/code/Magento/Sales/Model/Order.php | 656 ++++++++++-------- .../Magento/Sales/Model/Order/Creditmemo.php | 151 ++-- .../ActionGroup/AdminOrderActionGroup.xml | 11 +- .../Section/AdminOrderFormItemsSection.xml | 3 +- .../Section/AdminOrderFormPaymentSection.xml | 2 +- ...vailabilityCreditMemoWithNoPaymentTest.xml | 90 +++ .../Adminhtml/Order/Creditmemo/SaveTest.php | 8 +- .../Test/Unit/Model/Order/CreditmemoTest.php | 76 +- .../Sales/Test/Unit/Model/OrderTest.php | 15 + .../Magento/Sales/etc/adminhtml/system.xml | 7 + app/code/Magento/Sales/etc/config.xml | 3 + .../Authorizenet/Model/DirectpostTest.php | 6 +- .../Adminhtml/Order/PaymentReviewTest.php | 4 +- .../Controller/Payflow/SilentPostTest.php | 2 +- 14 files changed, 675 insertions(+), 359 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index a1bbd4856df16..c0eb3d5e5edb1 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -559,6 +559,7 @@ public function canCancel() /** * Getter whether the payment can be voided + * * @return bool */ public function canVoidPayment() @@ -615,11 +616,11 @@ public function canCreditmemo() return $this->getForcedCanCreditmemo(); } - if ($this->canUnhold() || $this->isPaymentReview()) { - return false; - } - - if ($this->isCanceled() || $this->getState() === self::STATE_CLOSED) { + if ($this->canUnhold() + || $this->isPaymentReview() + || $this->isCanceled() + || $this->getState() === self::STATE_CLOSED + ) { return false; } @@ -629,17 +630,55 @@ public function canCreditmemo() * TotalPaid - contains amount, that were not rounded. */ $totalRefunded = $this->priceCurrency->round($this->getTotalPaid()) - $this->getTotalRefunded(); - if (abs($totalRefunded) < .0001) { - return false; + if (abs($this->getGrandTotal()) < .0001) { + return $this->canCreditmemoForZeroTotal($totalRefunded); } + + return $this->canCreditmemoForZeroTotalRefunded($totalRefunded); + } + + /** + * Retrieve credit memo for zero total refunded availability. + * + * @param float $totalRefunded + * @return bool + */ + private function canCreditmemoForZeroTotalRefunded(float $totalRefunded): bool + { + $isRefundZero = abs($totalRefunded) < .0001; // Case when Adjustment Fee (adjustment_negative) has been used for first creditmemo - if (abs($totalRefunded - $this->getAdjustmentNegative()) < .0001) { + $hasAdjustmentFee = abs($totalRefunded - $this->getAdjustmentNegative()) < .0001; + $hasActinFlag = $this->getActionFlag(self::ACTION_FLAG_EDIT) === false; + if ($isRefundZero || $hasAdjustmentFee || $hasActinFlag) { return false; } - if ($this->getActionFlag(self::ACTION_FLAG_EDIT) === false) { + return true; + } + + /** + * Retrieve credit memo for zero total availability. + * + * @param float $totalRefunded + * @return bool + */ + private function canCreditmemoForZeroTotal(float $totalRefunded): bool + { + $totalPaid = $this->getTotalPaid(); + //check if total paid is less than grandtotal + $checkAmtTotalPaid = $totalPaid <= $this->getGrandTotal(); + //case when amount is due for invoice + $dueAmountCondition = $this->canInvoice() && $checkAmtTotalPaid; + //case when paid amount is refunded and order has creditmemo created + $creditmemos = ($this->getCreditmemosCollection() === false) ? + true : (count($this->getCreditmemosCollection()) > 0); + $paidAmtIsRefunded = $this->getTotalRefunded() == $totalPaid && $creditmemos; + if (($dueAmountCondition || $paidAmtIsRefunded) + || (!$checkAmtTotalPaid && abs($totalRefunded - $this->getAdjustmentNegative()) < .0001) + ) { return false; } + return true; } @@ -875,7 +914,7 @@ protected function _placePayment() } /** - * {@inheritdoc} + * @inheritdoc */ public function getPayment() { @@ -1083,6 +1122,8 @@ public function place() } /** + * Hold order. + * * @return $this * @throws \Magento\Framework\Exception\LocalizedException */ @@ -1228,6 +1269,8 @@ public function getShippingMethod($asObject = false) /*********************** ADDRESSES ***************************/ /** + * Get addresses collection. + * * @return Collection */ public function getAddressesCollection() @@ -1242,6 +1285,8 @@ public function getAddressesCollection() } /** + * Get address by id. + * * @param mixed $addressId * @return false */ @@ -1256,6 +1301,8 @@ public function getAddressById($addressId) } /** + * Add address. + * * @param \Magento\Sales\Model\Order\Address $address * @return $this */ @@ -1270,6 +1317,8 @@ public function addAddress(\Magento\Sales\Model\Order\Address $address) } /** + * Get items collection. + * * @param array $filterByTypes * @param bool $nonChildrenOnly * @return ItemCollection @@ -1342,6 +1391,8 @@ protected function _getItemsRandomCollection($limit, $nonChildrenOnly = false) } /** + * Get all items. + * * @return \Magento\Sales\Model\Order\Item[] */ public function getAllItems() @@ -1356,6 +1407,8 @@ public function getAllItems() } /** + * Get all visible items. + * * @return array */ public function getAllVisibleItems() @@ -1387,6 +1440,8 @@ public function getItemById($itemId) } /** + * Get item by quote item id. + * * @param mixed $quoteItemId * @return \Magento\Framework\DataObject|null */ @@ -1401,6 +1456,8 @@ public function getItemByQuoteItemId($quoteItemId) } /** + * Add item. + * * @param \Magento\Sales\Model\Order\Item $item * @return $this */ @@ -1416,6 +1473,8 @@ public function addItem(\Magento\Sales\Model\Order\Item $item) /*********************** PAYMENTS ***************************/ /** + * Get payments collection. + * * @return PaymentCollection */ public function getPaymentsCollection() @@ -1430,6 +1489,8 @@ public function getPaymentsCollection() } /** + * Get all payments. + * * @return array */ public function getAllPayments() @@ -1444,6 +1505,8 @@ public function getAllPayments() } /** + * Get payment by id. + * * @param mixed $paymentId * @return Payment|false */ @@ -1458,7 +1521,7 @@ public function getPaymentById($paymentId) } /** - * {@inheritdoc} + * @inheritdoc */ public function setPayment(\Magento\Sales\Api\Data\OrderPaymentInterface $payment = null) { @@ -1525,6 +1588,8 @@ public function getVisibleStatusHistory() } /** + * Get status history by id. + * * @param mixed $statusId * @return string|false */ @@ -1559,6 +1624,8 @@ public function addStatusHistory(\Magento\Sales\Model\Order\Status\History $hist } /** + * Get real order id. + * * @return string */ public function getRealOrderId() @@ -1587,9 +1654,9 @@ public function getOrderCurrency() /** * Get formatted price value including order currency rate to order website currency * - * @param float $price - * @param bool $addBrackets - * @return string + * @param float $price + * @param bool $addBrackets + * @return string */ public function formatPrice($price, $addBrackets = false) { @@ -1597,6 +1664,8 @@ public function formatPrice($price, $addBrackets = false) } /** + * Format price precision. + * * @param float $price * @param int $precision * @param bool $addBrackets @@ -1610,8 +1679,8 @@ public function formatPricePrecision($price, $precision, $addBrackets = false) /** * Retrieve text formatted price value including order rate * - * @param float $price - * @return string + * @param float $price + * @return string */ public function formatPriceTxt($price) { @@ -1632,6 +1701,8 @@ public function getBaseCurrency() } /** + * Format base price. + * * @param float $price * @return string */ @@ -1641,6 +1712,8 @@ public function formatBasePrice($price) } /** + * Format Base Price Precision. + * * @param float $price * @param int $precision * @return string @@ -1651,6 +1724,8 @@ public function formatBasePricePrecision($price, $precision) } /** + * Is currency different. + * * @return bool */ public function isCurrencyDifferent() @@ -1683,6 +1758,8 @@ public function getBaseTotalDue() } /** + * Get data. + * * @param string $key * @param null|string|int $index * @return mixed @@ -1823,6 +1900,8 @@ public function getRelatedObjects() } /** + * Get customer name. + * * @return string */ public function getCustomerName() @@ -1850,8 +1929,8 @@ public function addRelatedObject(\Magento\Framework\Model\AbstractModel $object) /** * Get formatted order created date in store timezone * - * @param string $format date format type (short|medium|long|full) - * @return string + * @param string $format date format type (short|medium|long|full) + * @return string */ public function getCreatedAtFormatted($format) { @@ -1865,6 +1944,8 @@ public function getCreatedAtFormatted($format) } /** + * Get email customer note. + * * @return string */ public function getEmailCustomerNote() @@ -1876,6 +1957,8 @@ public function getEmailCustomerNote() } /** + * Get store group name. + * * @return string */ public function getStoreGroupName() @@ -1888,8 +1971,7 @@ public function getStoreGroupName() } /** - * Resets all data in object - * so after another load it will be complete new object + * Reset all data in object so after another load it will be complete new object. * * @return $this */ @@ -1913,6 +1995,8 @@ public function reset() } /** + * Get order is not virtual. + * * @return bool * @SuppressWarnings(PHPMD.BooleanGetMethodName) */ @@ -1943,7 +2027,7 @@ public function isCanceled() } /** - * Returns increment id + * Return increment id * * @codeCoverageIgnore * @@ -1955,6 +2039,8 @@ public function getIncrementId() } /** + * Get Items. + * * @return \Magento\Sales\Api\Data\OrderItemInterface[] */ public function getItems() @@ -1969,7 +2055,7 @@ public function getItems() } /** - * {@inheritdoc} + * @inheritdoc * @codeCoverageIgnore */ public function setItems($items) @@ -1978,6 +2064,8 @@ public function setItems($items) } /** + * Get addresses. + * * @return \Magento\Sales\Api\Data\OrderAddressInterface[] */ public function getAddresses() @@ -1992,6 +2080,8 @@ public function getAddresses() } /** + * Get status History. + * * @return \Magento\Sales\Api\Data\OrderStatusHistoryInterface[]|null */ public function getStatusHistories() @@ -2006,7 +2096,7 @@ public function getStatusHistories() } /** - * {@inheritdoc} + * @inheritdoc * * @return \Magento\Sales\Api\Data\OrderExtensionInterface|null */ @@ -2016,7 +2106,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} + * @inheritdoc * * @param \Magento\Sales\Api\Data\OrderExtensionInterface $extensionAttributes * @return $this @@ -2029,7 +2119,7 @@ public function setExtensionAttributes(\Magento\Sales\Api\Data\OrderExtensionInt //@codeCoverageIgnoreStart /** - * Returns adjustment_negative + * Return adjustment_negative. * * @return float|null */ @@ -2039,7 +2129,7 @@ public function getAdjustmentNegative() } /** - * Returns adjustment_positive + * Return adjustment_positive. * * @return float|null */ @@ -2049,7 +2139,7 @@ public function getAdjustmentPositive() } /** - * Returns applied_rule_ids + * Return applied_rule_ids. * * @return string|null */ @@ -2059,7 +2149,7 @@ public function getAppliedRuleIds() } /** - * Returns base_adjustment_negative + * Return base_adjustment_negative. * * @return float|null */ @@ -2069,7 +2159,7 @@ public function getBaseAdjustmentNegative() } /** - * Returns base_adjustment_positive + * Return base_adjustment_positive. * * @return float|null */ @@ -2079,7 +2169,7 @@ public function getBaseAdjustmentPositive() } /** - * Returns base_currency_code + * Return base_currency_code. * * @return string|null */ @@ -2089,7 +2179,7 @@ public function getBaseCurrencyCode() } /** - * Returns base_discount_amount + * Return base_discount_amount. * * @return float|null */ @@ -2099,7 +2189,7 @@ public function getBaseDiscountAmount() } /** - * Returns base_discount_canceled + * Return base_discount_canceled. * * @return float|null */ @@ -2109,7 +2199,7 @@ public function getBaseDiscountCanceled() } /** - * Returns base_discount_invoiced + * Return base_discount_invoiced. * * @return float|null */ @@ -2119,7 +2209,7 @@ public function getBaseDiscountInvoiced() } /** - * Returns base_discount_refunded + * Return base_discount_refunded. * * @return float|null */ @@ -2129,7 +2219,7 @@ public function getBaseDiscountRefunded() } /** - * Returns base_grand_total + * Return base_grand_total. * * @return float */ @@ -2139,7 +2229,7 @@ public function getBaseGrandTotal() } /** - * Returns base_discount_tax_compensation_amount + * Return base_discount_tax_compensation_amount. * * @return float|null */ @@ -2149,7 +2239,7 @@ public function getBaseDiscountTaxCompensationAmount() } /** - * Returns base_discount_tax_compensation_invoiced + * Return base_discount_tax_compensation_invoiced. * * @return float|null */ @@ -2159,7 +2249,7 @@ public function getBaseDiscountTaxCompensationInvoiced() } /** - * Returns base_discount_tax_compensation_refunded + * Return base_discount_tax_compensation_refunded. * * @return float|null */ @@ -2169,7 +2259,7 @@ public function getBaseDiscountTaxCompensationRefunded() } /** - * Returns base_shipping_amount + * Return base_shipping_amount. * * @return float|null */ @@ -2179,7 +2269,7 @@ public function getBaseShippingAmount() } /** - * Returns base_shipping_canceled + * Return base_shipping_canceled. * * @return float|null */ @@ -2189,7 +2279,7 @@ public function getBaseShippingCanceled() } /** - * Returns base_shipping_discount_amount + * Return base_shipping_discount_amount. * * @return float|null */ @@ -2199,7 +2289,7 @@ public function getBaseShippingDiscountAmount() } /** - * Returns base_shipping_discount_tax_compensation_amnt + * Return base_shipping_discount_tax_compensation_amnt. * * @return float|null */ @@ -2209,7 +2299,7 @@ public function getBaseShippingDiscountTaxCompensationAmnt() } /** - * Returns base_shipping_incl_tax + * Return base_shipping_incl_tax. * * @return float|null */ @@ -2219,7 +2309,7 @@ public function getBaseShippingInclTax() } /** - * Returns base_shipping_invoiced + * Return base_shipping_invoiced. * * @return float|null */ @@ -2229,7 +2319,7 @@ public function getBaseShippingInvoiced() } /** - * Returns base_shipping_refunded + * Return base_shipping_refunded. * * @return float|null */ @@ -2239,7 +2329,7 @@ public function getBaseShippingRefunded() } /** - * Returns base_shipping_tax_amount + * Return base_shipping_tax_amount. * * @return float|null */ @@ -2249,7 +2339,7 @@ public function getBaseShippingTaxAmount() } /** - * Returns base_shipping_tax_refunded + * Return base_shipping_tax_refunded. * * @return float|null */ @@ -2259,7 +2349,7 @@ public function getBaseShippingTaxRefunded() } /** - * Returns base_subtotal + * Return base_subtotal. * * @return float|null */ @@ -2269,7 +2359,7 @@ public function getBaseSubtotal() } /** - * Returns base_subtotal_canceled + * Return base_subtotal_canceled. * * @return float|null */ @@ -2279,7 +2369,7 @@ public function getBaseSubtotalCanceled() } /** - * Returns base_subtotal_incl_tax + * Return base_subtotal_incl_tax. * * @return float|null */ @@ -2289,7 +2379,7 @@ public function getBaseSubtotalInclTax() } /** - * Returns base_subtotal_invoiced + * Return base_subtotal_invoiced. * * @return float|null */ @@ -2299,7 +2389,7 @@ public function getBaseSubtotalInvoiced() } /** - * Returns base_subtotal_refunded + * Return base_subtotal_refunded. * * @return float|null */ @@ -2309,7 +2399,7 @@ public function getBaseSubtotalRefunded() } /** - * Returns base_tax_amount + * Return base_tax_amount. * * @return float|null */ @@ -2319,7 +2409,7 @@ public function getBaseTaxAmount() } /** - * Returns base_tax_canceled + * Return base_tax_canceled. * * @return float|null */ @@ -2329,7 +2419,7 @@ public function getBaseTaxCanceled() } /** - * Returns base_tax_invoiced + * Return base_tax_invoiced. * * @return float|null */ @@ -2339,7 +2429,7 @@ public function getBaseTaxInvoiced() } /** - * Returns base_tax_refunded + * Return base_tax_refunded. * * @return float|null */ @@ -2349,7 +2439,7 @@ public function getBaseTaxRefunded() } /** - * Returns base_total_canceled + * Return base_total_canceled. * * @return float|null */ @@ -2359,7 +2449,7 @@ public function getBaseTotalCanceled() } /** - * Returns base_total_invoiced + * Return base_total_invoiced. * * @return float|null */ @@ -2369,7 +2459,7 @@ public function getBaseTotalInvoiced() } /** - * Returns base_total_invoiced_cost + * Return base_total_invoiced_cost. * * @return float|null */ @@ -2379,7 +2469,7 @@ public function getBaseTotalInvoicedCost() } /** - * Returns base_total_offline_refunded + * Return base_total_offline_refunded. * * @return float|null */ @@ -2389,7 +2479,7 @@ public function getBaseTotalOfflineRefunded() } /** - * Returns base_total_online_refunded + * Return base_total_online_refunded. * * @return float|null */ @@ -2399,7 +2489,7 @@ public function getBaseTotalOnlineRefunded() } /** - * Returns base_total_paid + * Return base_total_paid. * * @return float|null */ @@ -2409,7 +2499,7 @@ public function getBaseTotalPaid() } /** - * Returns base_total_qty_ordered + * Return base_total_qty_ordered. * * @return float|null */ @@ -2419,7 +2509,7 @@ public function getBaseTotalQtyOrdered() } /** - * Returns base_total_refunded + * Return base_total_refunded. * * @return float|null */ @@ -2429,7 +2519,7 @@ public function getBaseTotalRefunded() } /** - * Returns base_to_global_rate + * Return base_to_global_rate. * * @return float|null */ @@ -2439,7 +2529,7 @@ public function getBaseToGlobalRate() } /** - * Returns base_to_order_rate + * Return base_to_order_rate. * * @return float|null */ @@ -2449,7 +2539,7 @@ public function getBaseToOrderRate() } /** - * Returns billing_address_id + * Return billing_address_id. * * @return int|null */ @@ -2459,7 +2549,7 @@ public function getBillingAddressId() } /** - * Returns can_ship_partially + * Return can_ship_partially. * * @return int|null */ @@ -2469,7 +2559,7 @@ public function getCanShipPartially() } /** - * Returns can_ship_partially_item + * Return can_ship_partially_item. * * @return int|null */ @@ -2479,7 +2569,7 @@ public function getCanShipPartiallyItem() } /** - * Returns coupon_code + * Return coupon_code. * * @return string|null */ @@ -2489,7 +2579,7 @@ public function getCouponCode() } /** - * Returns created_at + * Return created_at. * * @return string|null */ @@ -2499,7 +2589,7 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -2507,7 +2597,7 @@ public function setCreatedAt($createdAt) } /** - * Returns customer_dob + * Return customer_dob. * * @return string|null */ @@ -2517,7 +2607,7 @@ public function getCustomerDob() } /** - * Returns customer_email + * Return customer_email. * * @return string */ @@ -2527,7 +2617,7 @@ public function getCustomerEmail() } /** - * Returns customer_firstname + * Return customer_firstname. * * @return string|null */ @@ -2537,7 +2627,7 @@ public function getCustomerFirstname() } /** - * Returns customer_gender + * Return customer_gender. * * @return int|null */ @@ -2547,7 +2637,7 @@ public function getCustomerGender() } /** - * Returns customer_group_id + * Return customer_group_id. * * @return int|null */ @@ -2557,7 +2647,7 @@ public function getCustomerGroupId() } /** - * Returns customer_id + * Return customer_id. * * @return int|null */ @@ -2567,7 +2657,7 @@ public function getCustomerId() } /** - * Returns customer_is_guest + * Return customer_is_guest. * * @return int|null */ @@ -2577,7 +2667,7 @@ public function getCustomerIsGuest() } /** - * Returns customer_lastname + * Return customer_lastname. * * @return string|null */ @@ -2587,7 +2677,7 @@ public function getCustomerLastname() } /** - * Returns customer_middlename + * Return customer_middlename. * * @return string|null */ @@ -2597,7 +2687,7 @@ public function getCustomerMiddlename() } /** - * Returns customer_note + * Return customer_note. * * @return string|null */ @@ -2607,7 +2697,7 @@ public function getCustomerNote() } /** - * Returns customer_note_notify + * Return customer_note_notify. * * @return int|null */ @@ -2617,7 +2707,7 @@ public function getCustomerNoteNotify() } /** - * Returns customer_prefix + * Return customer_prefix. * * @return string|null */ @@ -2627,7 +2717,7 @@ public function getCustomerPrefix() } /** - * Returns customer_suffix + * Return customer_suffix. * * @return string|null */ @@ -2637,7 +2727,7 @@ public function getCustomerSuffix() } /** - * Returns customer_taxvat + * Return customer_taxvat. * * @return string|null */ @@ -2647,7 +2737,7 @@ public function getCustomerTaxvat() } /** - * Returns discount_amount + * Return discount_amount. * * @return float|null */ @@ -2657,7 +2747,7 @@ public function getDiscountAmount() } /** - * Returns discount_canceled + * Return discount_canceled. * * @return float|null */ @@ -2667,7 +2757,7 @@ public function getDiscountCanceled() } /** - * Returns discount_description + * Return discount_description. * * @return string|null */ @@ -2677,7 +2767,7 @@ public function getDiscountDescription() } /** - * Returns discount_invoiced + * Return discount_invoiced. * * @return float|null */ @@ -2687,7 +2777,7 @@ public function getDiscountInvoiced() } /** - * Returns discount_refunded + * Return discount_refunded. * * @return float|null */ @@ -2697,7 +2787,7 @@ public function getDiscountRefunded() } /** - * Returns edit_increment + * Return edit_increment. * * @return int|null */ @@ -2707,7 +2797,7 @@ public function getEditIncrement() } /** - * Returns email_sent + * Return email_sent. * * @return int|null */ @@ -2717,7 +2807,7 @@ public function getEmailSent() } /** - * Returns ext_customer_id + * Return ext_customer_id. * * @return string|null */ @@ -2727,7 +2817,7 @@ public function getExtCustomerId() } /** - * Returns ext_order_id + * Return ext_order_id. * * @return string|null */ @@ -2737,7 +2827,7 @@ public function getExtOrderId() } /** - * Returns forced_shipment_with_invoice + * Return forced_shipment_with_invoice. * * @return int|null */ @@ -2747,7 +2837,7 @@ public function getForcedShipmentWithInvoice() } /** - * Returns global_currency_code + * Return global_currency_code. * * @return string|null */ @@ -2757,7 +2847,7 @@ public function getGlobalCurrencyCode() } /** - * Returns grand_total + * Return grand_total. * * @return float */ @@ -2767,7 +2857,7 @@ public function getGrandTotal() } /** - * Returns discount_tax_compensation_amount + * Return discount_tax_compensation_amount. * * @return float|null */ @@ -2777,7 +2867,7 @@ public function getDiscountTaxCompensationAmount() } /** - * Returns discount_tax_compensation_invoiced + * Return discount_tax_compensation_invoiced. * * @return float|null */ @@ -2787,7 +2877,7 @@ public function getDiscountTaxCompensationInvoiced() } /** - * Returns discount_tax_compensation_refunded + * Return discount_tax_compensation_refunded. * * @return float|null */ @@ -2797,7 +2887,7 @@ public function getDiscountTaxCompensationRefunded() } /** - * Returns hold_before_state + * Return hold_before_state. * * @return string|null */ @@ -2807,7 +2897,7 @@ public function getHoldBeforeState() } /** - * Returns hold_before_status + * Return hold_before_status. * * @return string|null */ @@ -2817,7 +2907,7 @@ public function getHoldBeforeStatus() } /** - * Returns is_virtual + * Return is_virtual. * * @return int|null */ @@ -2827,7 +2917,7 @@ public function getIsVirtual() } /** - * Returns order_currency_code + * Return order_currency_code. * * @return string|null */ @@ -2837,7 +2927,7 @@ public function getOrderCurrencyCode() } /** - * Returns original_increment_id + * Return original_increment_id. * * @return string|null */ @@ -2847,7 +2937,7 @@ public function getOriginalIncrementId() } /** - * Returns payment_authorization_amount + * Return payment_authorization_amount. * * @return float|null */ @@ -2857,7 +2947,7 @@ public function getPaymentAuthorizationAmount() } /** - * Returns payment_auth_expiration + * Return payment_auth_expiration. * * @return int|null */ @@ -2867,7 +2957,7 @@ public function getPaymentAuthExpiration() } /** - * Returns protect_code + * Return protect_code. * * @return string|null */ @@ -2877,7 +2967,7 @@ public function getProtectCode() } /** - * Returns quote_address_id + * Return quote_address_id. * * @return int|null */ @@ -2887,7 +2977,7 @@ public function getQuoteAddressId() } /** - * Returns quote_id + * Return quote_id. * * @return int|null */ @@ -2897,7 +2987,7 @@ public function getQuoteId() } /** - * Returns relation_child_id + * Return relation_child_id. * * @return string|null */ @@ -2907,7 +2997,7 @@ public function getRelationChildId() } /** - * Returns relation_child_real_id + * Return relation_child_real_id. * * @return string|null */ @@ -2917,7 +3007,7 @@ public function getRelationChildRealId() } /** - * Returns relation_parent_id + * Return relation_parent_id. * * @return string|null */ @@ -2927,7 +3017,7 @@ public function getRelationParentId() } /** - * Returns relation_parent_real_id + * Return relation_parent_real_id. * * @return string|null */ @@ -2937,7 +3027,7 @@ public function getRelationParentRealId() } /** - * Returns remote_ip + * Return remote_ip. * * @return string|null */ @@ -2947,7 +3037,7 @@ public function getRemoteIp() } /** - * Returns shipping_amount + * Return shipping_amount. * * @return float|null */ @@ -2957,7 +3047,7 @@ public function getShippingAmount() } /** - * Returns shipping_canceled + * Return shipping_canceled. * * @return float|null */ @@ -2967,7 +3057,7 @@ public function getShippingCanceled() } /** - * Returns shipping_description + * Return shipping_description. * * @return string|null */ @@ -2977,7 +3067,7 @@ public function getShippingDescription() } /** - * Returns shipping_discount_amount + * Return shipping_discount_amount. * * @return float|null */ @@ -2987,7 +3077,7 @@ public function getShippingDiscountAmount() } /** - * Returns shipping_discount_tax_compensation_amount + * Return shipping_discount_tax_compensation_amount. * * @return float|null */ @@ -2997,7 +3087,7 @@ public function getShippingDiscountTaxCompensationAmount() } /** - * Returns shipping_incl_tax + * Return shipping_incl_tax. * * @return float|null */ @@ -3007,7 +3097,7 @@ public function getShippingInclTax() } /** - * Returns shipping_invoiced + * Return shipping_invoiced. * * @return float|null */ @@ -3017,7 +3107,7 @@ public function getShippingInvoiced() } /** - * Returns shipping_refunded + * Return shipping_refunded. * * @return float|null */ @@ -3027,7 +3117,7 @@ public function getShippingRefunded() } /** - * Returns shipping_tax_amount + * Return shipping_tax_amount. * * @return float|null */ @@ -3037,7 +3127,7 @@ public function getShippingTaxAmount() } /** - * Returns shipping_tax_refunded + * Return shipping_tax_refunded. * * @return float|null */ @@ -3047,7 +3137,7 @@ public function getShippingTaxRefunded() } /** - * Returns state + * Return state. * * @return string|null */ @@ -3057,7 +3147,7 @@ public function getState() } /** - * Returns status + * Return status. * * @return string|null */ @@ -3067,7 +3157,7 @@ public function getStatus() } /** - * Returns store_currency_code + * Return store_currency_code. * * @return string|null */ @@ -3077,7 +3167,7 @@ public function getStoreCurrencyCode() } /** - * Returns store_id + * Return store_id. * * @return int|null */ @@ -3087,7 +3177,7 @@ public function getStoreId() } /** - * Returns store_name + * Return store_name. * * @return string|null */ @@ -3097,7 +3187,7 @@ public function getStoreName() } /** - * Returns store_to_base_rate + * Return store_to_base_rate. * * @return float|null */ @@ -3107,7 +3197,7 @@ public function getStoreToBaseRate() } /** - * Returns store_to_order_rate + * Return store_to_order_rate. * * @return float|null */ @@ -3117,7 +3207,7 @@ public function getStoreToOrderRate() } /** - * Returns subtotal + * Return subtotal. * * @return float|null */ @@ -3127,7 +3217,7 @@ public function getSubtotal() } /** - * Returns subtotal_canceled + * Return subtotal_canceled. * * @return float|null */ @@ -3137,7 +3227,7 @@ public function getSubtotalCanceled() } /** - * Returns subtotal_incl_tax + * Return subtotal_incl_tax. * * @return float|null */ @@ -3147,7 +3237,7 @@ public function getSubtotalInclTax() } /** - * Returns subtotal_invoiced + * Return subtotal_invoiced. * * @return float|null */ @@ -3157,7 +3247,7 @@ public function getSubtotalInvoiced() } /** - * Returns subtotal_refunded + * Return subtotal_refunded. * * @return float|null */ @@ -3167,7 +3257,7 @@ public function getSubtotalRefunded() } /** - * Returns tax_amount + * Return tax_amount. * * @return float|null */ @@ -3177,7 +3267,7 @@ public function getTaxAmount() } /** - * Returns tax_canceled + * Return tax_canceled. * * @return float|null */ @@ -3187,7 +3277,7 @@ public function getTaxCanceled() } /** - * Returns tax_invoiced + * Return tax_invoiced. * * @return float|null */ @@ -3197,7 +3287,7 @@ public function getTaxInvoiced() } /** - * Returns tax_refunded + * Return tax_refunded. * * @return float|null */ @@ -3207,7 +3297,7 @@ public function getTaxRefunded() } /** - * Returns total_canceled + * Return total_canceled. * * @return float|null */ @@ -3217,7 +3307,7 @@ public function getTotalCanceled() } /** - * Returns total_invoiced + * Return total_invoiced. * * @return float|null */ @@ -3227,7 +3317,7 @@ public function getTotalInvoiced() } /** - * Returns total_item_count + * Return total_item_count. * * @return int|null */ @@ -3237,7 +3327,7 @@ public function getTotalItemCount() } /** - * Returns total_offline_refunded + * Return total_offline_refunded. * * @return float|null */ @@ -3247,7 +3337,7 @@ public function getTotalOfflineRefunded() } /** - * Returns total_online_refunded + * Return total_online_refunded. * * @return float|null */ @@ -3257,7 +3347,7 @@ public function getTotalOnlineRefunded() } /** - * Returns total_paid + * Return total_paid. * * @return float|null */ @@ -3267,7 +3357,7 @@ public function getTotalPaid() } /** - * Returns total_qty_ordered + * Return total_qty_ordered. * * @return float|null */ @@ -3277,7 +3367,7 @@ public function getTotalQtyOrdered() } /** - * Returns total_refunded + * Return total_refunded. * * @return float|null */ @@ -3287,7 +3377,7 @@ public function getTotalRefunded() } /** - * Returns updated_at + * Return updated_at. * * @return string|null */ @@ -3297,7 +3387,7 @@ public function getUpdatedAt() } /** - * Returns weight + * Return weight. * * @return float|null */ @@ -3307,7 +3397,7 @@ public function getWeight() } /** - * Returns x_forwarded_for + * Return x_forwarded_for. * * @return string|null */ @@ -3317,7 +3407,7 @@ public function getXForwardedFor() } /** - * {@inheritdoc} + * @inheritdoc */ public function setStatusHistories(array $statusHistories = null) { @@ -3325,7 +3415,7 @@ public function setStatusHistories(array $statusHistories = null) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStatus($status) { @@ -3333,7 +3423,7 @@ public function setStatus($status) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCouponCode($code) { @@ -3341,7 +3431,7 @@ public function setCouponCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setProtectCode($code) { @@ -3349,7 +3439,7 @@ public function setProtectCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingDescription($description) { @@ -3357,7 +3447,7 @@ public function setShippingDescription($description) } /** - * {@inheritdoc} + * @inheritdoc */ public function setIsVirtual($isVirtual) { @@ -3365,7 +3455,7 @@ public function setIsVirtual($isVirtual) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreId($id) { @@ -3373,7 +3463,7 @@ public function setStoreId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerId($id) { @@ -3381,7 +3471,7 @@ public function setCustomerId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountAmount($amount) { @@ -3389,7 +3479,7 @@ public function setBaseDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountCanceled($baseDiscountCanceled) { @@ -3397,7 +3487,7 @@ public function setBaseDiscountCanceled($baseDiscountCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountInvoiced($baseDiscountInvoiced) { @@ -3405,7 +3495,7 @@ public function setBaseDiscountInvoiced($baseDiscountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountRefunded($baseDiscountRefunded) { @@ -3413,7 +3503,7 @@ public function setBaseDiscountRefunded($baseDiscountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseGrandTotal($amount) { @@ -3421,7 +3511,7 @@ public function setBaseGrandTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingAmount($amount) { @@ -3429,7 +3519,7 @@ public function setBaseShippingAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingCanceled($baseShippingCanceled) { @@ -3437,7 +3527,7 @@ public function setBaseShippingCanceled($baseShippingCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingInvoiced($baseShippingInvoiced) { @@ -3445,7 +3535,7 @@ public function setBaseShippingInvoiced($baseShippingInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingRefunded($baseShippingRefunded) { @@ -3453,7 +3543,7 @@ public function setBaseShippingRefunded($baseShippingRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingTaxAmount($amount) { @@ -3461,7 +3551,7 @@ public function setBaseShippingTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) { @@ -3469,7 +3559,7 @@ public function setBaseShippingTaxRefunded($baseShippingTaxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotal($amount) { @@ -3477,7 +3567,7 @@ public function setBaseSubtotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotalCanceled($baseSubtotalCanceled) { @@ -3485,7 +3575,7 @@ public function setBaseSubtotalCanceled($baseSubtotalCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) { @@ -3493,7 +3583,7 @@ public function setBaseSubtotalInvoiced($baseSubtotalInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotalRefunded($baseSubtotalRefunded) { @@ -3501,7 +3591,7 @@ public function setBaseSubtotalRefunded($baseSubtotalRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxAmount($amount) { @@ -3509,7 +3599,7 @@ public function setBaseTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxCanceled($baseTaxCanceled) { @@ -3517,7 +3607,7 @@ public function setBaseTaxCanceled($baseTaxCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxInvoiced($baseTaxInvoiced) { @@ -3525,7 +3615,7 @@ public function setBaseTaxInvoiced($baseTaxInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxRefunded($baseTaxRefunded) { @@ -3533,7 +3623,7 @@ public function setBaseTaxRefunded($baseTaxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseToGlobalRate($rate) { @@ -3541,7 +3631,7 @@ public function setBaseToGlobalRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseToOrderRate($rate) { @@ -3549,7 +3639,7 @@ public function setBaseToOrderRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalCanceled($baseTotalCanceled) { @@ -3557,7 +3647,7 @@ public function setBaseTotalCanceled($baseTotalCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalInvoiced($baseTotalInvoiced) { @@ -3565,7 +3655,7 @@ public function setBaseTotalInvoiced($baseTotalInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) { @@ -3573,7 +3663,7 @@ public function setBaseTotalInvoicedCost($baseTotalInvoicedCost) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) { @@ -3581,7 +3671,7 @@ public function setBaseTotalOfflineRefunded($baseTotalOfflineRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) { @@ -3589,7 +3679,7 @@ public function setBaseTotalOnlineRefunded($baseTotalOnlineRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalPaid($baseTotalPaid) { @@ -3597,7 +3687,7 @@ public function setBaseTotalPaid($baseTotalPaid) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) { @@ -3605,7 +3695,7 @@ public function setBaseTotalQtyOrdered($baseTotalQtyOrdered) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalRefunded($baseTotalRefunded) { @@ -3613,7 +3703,7 @@ public function setBaseTotalRefunded($baseTotalRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountAmount($amount) { @@ -3621,7 +3711,7 @@ public function setDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountCanceled($discountCanceled) { @@ -3629,7 +3719,7 @@ public function setDiscountCanceled($discountCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountInvoiced($discountInvoiced) { @@ -3637,7 +3727,7 @@ public function setDiscountInvoiced($discountInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountRefunded($discountRefunded) { @@ -3645,7 +3735,7 @@ public function setDiscountRefunded($discountRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGrandTotal($amount) { @@ -3653,7 +3743,7 @@ public function setGrandTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingAmount($amount) { @@ -3661,7 +3751,7 @@ public function setShippingAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingCanceled($shippingCanceled) { @@ -3669,7 +3759,7 @@ public function setShippingCanceled($shippingCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingInvoiced($shippingInvoiced) { @@ -3677,7 +3767,7 @@ public function setShippingInvoiced($shippingInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingRefunded($shippingRefunded) { @@ -3685,7 +3775,7 @@ public function setShippingRefunded($shippingRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingTaxAmount($amount) { @@ -3693,7 +3783,7 @@ public function setShippingTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingTaxRefunded($shippingTaxRefunded) { @@ -3701,7 +3791,7 @@ public function setShippingTaxRefunded($shippingTaxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreToBaseRate($rate) { @@ -3709,7 +3799,7 @@ public function setStoreToBaseRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreToOrderRate($rate) { @@ -3717,7 +3807,7 @@ public function setStoreToOrderRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotal($amount) { @@ -3725,7 +3815,7 @@ public function setSubtotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotalCanceled($subtotalCanceled) { @@ -3733,7 +3823,7 @@ public function setSubtotalCanceled($subtotalCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotalInvoiced($subtotalInvoiced) { @@ -3741,7 +3831,7 @@ public function setSubtotalInvoiced($subtotalInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotalRefunded($subtotalRefunded) { @@ -3749,7 +3839,7 @@ public function setSubtotalRefunded($subtotalRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxAmount($amount) { @@ -3757,7 +3847,7 @@ public function setTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxCanceled($taxCanceled) { @@ -3765,7 +3855,7 @@ public function setTaxCanceled($taxCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxInvoiced($taxInvoiced) { @@ -3773,7 +3863,7 @@ public function setTaxInvoiced($taxInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxRefunded($taxRefunded) { @@ -3781,7 +3871,7 @@ public function setTaxRefunded($taxRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalCanceled($totalCanceled) { @@ -3789,7 +3879,7 @@ public function setTotalCanceled($totalCanceled) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalInvoiced($totalInvoiced) { @@ -3797,7 +3887,7 @@ public function setTotalInvoiced($totalInvoiced) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalOfflineRefunded($totalOfflineRefunded) { @@ -3805,7 +3895,7 @@ public function setTotalOfflineRefunded($totalOfflineRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalOnlineRefunded($totalOnlineRefunded) { @@ -3813,7 +3903,7 @@ public function setTotalOnlineRefunded($totalOnlineRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalPaid($totalPaid) { @@ -3821,7 +3911,7 @@ public function setTotalPaid($totalPaid) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalQtyOrdered($totalQtyOrdered) { @@ -3829,7 +3919,7 @@ public function setTotalQtyOrdered($totalQtyOrdered) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalRefunded($totalRefunded) { @@ -3837,7 +3927,7 @@ public function setTotalRefunded($totalRefunded) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCanShipPartially($flag) { @@ -3845,7 +3935,7 @@ public function setCanShipPartially($flag) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCanShipPartiallyItem($flag) { @@ -3853,7 +3943,7 @@ public function setCanShipPartiallyItem($flag) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerIsGuest($customerIsGuest) { @@ -3861,7 +3951,7 @@ public function setCustomerIsGuest($customerIsGuest) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerNoteNotify($customerNoteNotify) { @@ -3869,7 +3959,7 @@ public function setCustomerNoteNotify($customerNoteNotify) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBillingAddressId($id) { @@ -3877,7 +3967,7 @@ public function setBillingAddressId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerGroupId($id) { @@ -3885,7 +3975,7 @@ public function setCustomerGroupId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setEditIncrement($editIncrement) { @@ -3893,7 +3983,7 @@ public function setEditIncrement($editIncrement) } /** - * {@inheritdoc} + * @inheritdoc */ public function setEmailSent($emailSent) { @@ -3901,7 +3991,7 @@ public function setEmailSent($emailSent) } /** - * {@inheritdoc} + * @inheritdoc */ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) { @@ -3909,7 +3999,7 @@ public function setForcedShipmentWithInvoice($forcedShipmentWithInvoice) } /** - * {@inheritdoc} + * @inheritdoc */ public function setPaymentAuthExpiration($paymentAuthExpiration) { @@ -3917,7 +4007,7 @@ public function setPaymentAuthExpiration($paymentAuthExpiration) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQuoteAddressId($id) { @@ -3925,7 +4015,7 @@ public function setQuoteAddressId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setQuoteId($id) { @@ -3933,7 +4023,7 @@ public function setQuoteId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAdjustmentNegative($adjustmentNegative) { @@ -3941,7 +4031,7 @@ public function setAdjustmentNegative($adjustmentNegative) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAdjustmentPositive($adjustmentPositive) { @@ -3949,7 +4039,7 @@ public function setAdjustmentPositive($adjustmentPositive) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseAdjustmentNegative($baseAdjustmentNegative) { @@ -3957,7 +4047,7 @@ public function setBaseAdjustmentNegative($baseAdjustmentNegative) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseAdjustmentPositive($baseAdjustmentPositive) { @@ -3965,7 +4055,7 @@ public function setBaseAdjustmentPositive($baseAdjustmentPositive) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingDiscountAmount($amount) { @@ -3973,7 +4063,7 @@ public function setBaseShippingDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotalInclTax($amount) { @@ -3981,7 +4071,7 @@ public function setBaseSubtotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTotalDue($baseTotalDue) { @@ -3989,7 +4079,7 @@ public function setBaseTotalDue($baseTotalDue) } /** - * {@inheritdoc} + * @inheritdoc */ public function setPaymentAuthorizationAmount($amount) { @@ -3997,7 +4087,7 @@ public function setPaymentAuthorizationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingDiscountAmount($amount) { @@ -4005,7 +4095,7 @@ public function setShippingDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotalInclTax($amount) { @@ -4013,7 +4103,7 @@ public function setSubtotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalDue($totalDue) { @@ -4021,7 +4111,7 @@ public function setTotalDue($totalDue) } /** - * {@inheritdoc} + * @inheritdoc */ public function setWeight($weight) { @@ -4029,7 +4119,7 @@ public function setWeight($weight) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerDob($customerDob) { @@ -4037,7 +4127,7 @@ public function setCustomerDob($customerDob) } /** - * {@inheritdoc} + * @inheritdoc */ public function setIncrementId($id) { @@ -4045,7 +4135,7 @@ public function setIncrementId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAppliedRuleIds($appliedRuleIds) { @@ -4053,7 +4143,7 @@ public function setAppliedRuleIds($appliedRuleIds) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseCurrencyCode($code) { @@ -4061,7 +4151,7 @@ public function setBaseCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerEmail($customerEmail) { @@ -4069,7 +4159,7 @@ public function setCustomerEmail($customerEmail) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerFirstname($customerFirstname) { @@ -4077,7 +4167,7 @@ public function setCustomerFirstname($customerFirstname) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerLastname($customerLastname) { @@ -4085,7 +4175,7 @@ public function setCustomerLastname($customerLastname) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerMiddlename($customerMiddlename) { @@ -4093,7 +4183,7 @@ public function setCustomerMiddlename($customerMiddlename) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerPrefix($customerPrefix) { @@ -4101,7 +4191,7 @@ public function setCustomerPrefix($customerPrefix) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerSuffix($customerSuffix) { @@ -4109,7 +4199,7 @@ public function setCustomerSuffix($customerSuffix) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerTaxvat($customerTaxvat) { @@ -4117,7 +4207,7 @@ public function setCustomerTaxvat($customerTaxvat) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountDescription($description) { @@ -4125,7 +4215,7 @@ public function setDiscountDescription($description) } /** - * {@inheritdoc} + * @inheritdoc */ public function setExtCustomerId($id) { @@ -4133,7 +4223,7 @@ public function setExtCustomerId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setExtOrderId($id) { @@ -4141,7 +4231,7 @@ public function setExtOrderId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGlobalCurrencyCode($code) { @@ -4149,7 +4239,7 @@ public function setGlobalCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setHoldBeforeState($holdBeforeState) { @@ -4157,7 +4247,7 @@ public function setHoldBeforeState($holdBeforeState) } /** - * {@inheritdoc} + * @inheritdoc */ public function setHoldBeforeStatus($holdBeforeStatus) { @@ -4165,7 +4255,7 @@ public function setHoldBeforeStatus($holdBeforeStatus) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOrderCurrencyCode($code) { @@ -4173,7 +4263,7 @@ public function setOrderCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOriginalIncrementId($id) { @@ -4181,7 +4271,7 @@ public function setOriginalIncrementId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRelationChildId($id) { @@ -4189,7 +4279,7 @@ public function setRelationChildId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRelationChildRealId($realId) { @@ -4197,7 +4287,7 @@ public function setRelationChildRealId($realId) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRelationParentId($id) { @@ -4205,7 +4295,7 @@ public function setRelationParentId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRelationParentRealId($realId) { @@ -4213,7 +4303,7 @@ public function setRelationParentRealId($realId) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRemoteIp($remoteIp) { @@ -4221,7 +4311,7 @@ public function setRemoteIp($remoteIp) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreCurrencyCode($code) { @@ -4229,7 +4319,7 @@ public function setStoreCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreName($storeName) { @@ -4237,7 +4327,7 @@ public function setStoreName($storeName) } /** - * {@inheritdoc} + * @inheritdoc */ public function setXForwardedFor($xForwardedFor) { @@ -4245,7 +4335,7 @@ public function setXForwardedFor($xForwardedFor) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerNote($customerNote) { @@ -4253,7 +4343,7 @@ public function setCustomerNote($customerNote) } /** - * {@inheritdoc} + * @inheritdoc */ public function setUpdatedAt($timestamp) { @@ -4261,7 +4351,7 @@ public function setUpdatedAt($timestamp) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTotalItemCount($totalItemCount) { @@ -4269,7 +4359,7 @@ public function setTotalItemCount($totalItemCount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerGender($customerGender) { @@ -4277,7 +4367,7 @@ public function setCustomerGender($customerGender) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationAmount($amount) { @@ -4285,7 +4375,7 @@ public function setDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationAmount($amount) { @@ -4293,7 +4383,7 @@ public function setBaseDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingDiscountTaxCompensationAmount($amount) { @@ -4301,7 +4391,7 @@ public function setShippingDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) { @@ -4309,7 +4399,7 @@ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoiced) { @@ -4317,7 +4407,7 @@ public function setDiscountTaxCompensationInvoiced($discountTaxCompensationInvoi } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensationInvoiced) { @@ -4328,7 +4418,7 @@ public function setBaseDiscountTaxCompensationInvoiced($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefunded) { @@ -4339,7 +4429,7 @@ public function setDiscountTaxCompensationRefunded($discountTaxCompensationRefun } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensationRefunded) { @@ -4350,7 +4440,7 @@ public function setBaseDiscountTaxCompensationRefunded($baseDiscountTaxCompensat } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingInclTax($amount) { @@ -4358,7 +4448,7 @@ public function setShippingInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingInclTax($amount) { diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php index a9a293e0fc073..49b9f78d06828 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php @@ -15,6 +15,7 @@ use Magento\Sales\Model\AbstractModel; use Magento\Sales\Model\EntityInterface; use Magento\Sales\Model\Order\InvoiceFactory; +use Magento\Framework\App\Config\ScopeConfigInterface; /** * Order creditmemo model @@ -28,6 +29,7 @@ * @SuppressWarnings(PHPMD.ExcessivePublicCount) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) * @since 100.0.2 */ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInterface @@ -42,6 +44,11 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt const REPORT_DATE_TYPE_REFUND_CREATED = 'refund_created'; + /** + * Allow Zero Grandtotal for Creditmemo path + */ + const XML_PATH_ALLOW_ZERO_GRANDTOTAL = 'sales/zerograndtotal_creditmemo/allow_zero_grandtotal'; + /** * Identifier for order history item * @@ -121,6 +128,11 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt */ private $invoiceFactory; + /** + * @var ScopeConfigInterface; + */ + private $scopeConfig; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -138,6 +150,7 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data * @param InvoiceFactory $invoiceFactory + * @param ScopeConfigInterface $scopeConfig * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -156,7 +169,8 @@ public function __construct( \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [], - InvoiceFactory $invoiceFactory = null + InvoiceFactory $invoiceFactory = null, + ScopeConfigInterface $scopeConfig = null ) { $this->_creditmemoConfig = $creditmemoConfig; $this->_orderFactory = $orderFactory; @@ -167,6 +181,7 @@ public function __construct( $this->_commentCollectionFactory = $commentCollectionFactory; $this->priceCurrency = $priceCurrency; $this->invoiceFactory = $invoiceFactory ?: ObjectManager::getInstance()->get(InvoiceFactory::class); + $this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class); parent::__construct( $context, $registry, @@ -265,6 +280,8 @@ public function getShippingAddress() } /** + * Retrieve collection if items. + * * @return mixed */ public function getItemsCollection() @@ -280,6 +297,8 @@ public function getItemsCollection() } /** + * Retrieve all items. + * * @return \Magento\Sales\Model\Order\Creditmemo\Item[] */ public function getAllItems() @@ -294,6 +313,8 @@ public function getAllItems() } /** + * Retrieve item by id. + * * @param mixed $itemId * @return mixed */ @@ -324,6 +345,8 @@ public function getItemByOrderId($orderId) } /** + * Add an item to credit memo. + * * @param \Magento\Sales\Model\Order\Creditmemo\Item $item * @return $this */ @@ -369,6 +392,8 @@ public function roundPrice($price, $type = 'regular', $negative = false) } /** + * Check if credit memo can be refunded. + * * @return bool */ public function canRefund() @@ -466,6 +491,8 @@ public function getStateName($stateId = null) } /** + * Set shipping amount. + * * @param float $amount * @return $this */ @@ -475,6 +502,8 @@ public function setShippingAmount($amount) } /** + * Set adjustment positive amount. + * * @param string $amount * @return $this */ @@ -495,6 +524,8 @@ public function setAdjustmentPositive($amount) } /** + * Set adjustment negative amount. + * * @param string $amount * @return $this */ @@ -543,6 +574,8 @@ public function isLast() } /** + * Add comment to credit memo. + * * Adds comment to credit memo with additional possibility to send it to customer via email * and show it in customer account * @@ -569,6 +602,8 @@ public function addComment($comment, $notify = false, $visibleOnFront = false) } /** + * Retrieve collection of comments. + * * @param bool $reload * @return \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Comment\Collection * @SuppressWarnings(PHPMD.UnusedFormalParameter) @@ -608,11 +643,28 @@ public function getIncrementId() } /** + * Check if grand total is valid. + * * @return bool */ public function isValidGrandTotal() { - return !($this->getGrandTotal() <= 0 && !$this->getAllowZeroGrandTotal()); + return !($this->getGrandTotal() <= 0 && !$this->isAllowZeroGrandTotal()); + } + + /** + * Return Zero GrandTotal availability. + * + * @return bool + */ + private function isAllowZeroGrandTotal(): bool + { + $isAllowed = $this->scopeConfig->getValue( + self::XML_PATH_ALLOW_ZERO_GRANDTOTAL, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + + return $isAllowed; } /** @@ -660,7 +712,7 @@ public function getDiscountDescription() } /** - * {@inheritdoc} + * @inheritdoc */ public function setItems($items) { @@ -900,7 +952,7 @@ public function getCreatedAt() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCreatedAt($createdAt) { @@ -1159,7 +1211,7 @@ public function getUpdatedAt() } /** - * {@inheritdoc} + * @inheritdoc */ public function setComments($comments) { @@ -1167,7 +1219,7 @@ public function setComments($comments) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreId($id) { @@ -1175,7 +1227,7 @@ public function setStoreId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingTaxAmount($amount) { @@ -1183,7 +1235,7 @@ public function setBaseShippingTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreToOrderRate($rate) { @@ -1191,7 +1243,7 @@ public function setStoreToOrderRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountAmount($amount) { @@ -1199,7 +1251,7 @@ public function setBaseDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseToOrderRate($rate) { @@ -1207,7 +1259,7 @@ public function setBaseToOrderRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGrandTotal($amount) { @@ -1215,7 +1267,7 @@ public function setGrandTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotalInclTax($amount) { @@ -1223,7 +1275,7 @@ public function setBaseSubtotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotalInclTax($amount) { @@ -1231,7 +1283,7 @@ public function setSubtotalInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingAmount($amount) { @@ -1239,7 +1291,7 @@ public function setBaseShippingAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreToBaseRate($rate) { @@ -1247,7 +1299,7 @@ public function setStoreToBaseRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseToGlobalRate($rate) { @@ -1255,7 +1307,7 @@ public function setBaseToGlobalRate($rate) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseAdjustment($baseAdjustment) { @@ -1263,7 +1315,7 @@ public function setBaseAdjustment($baseAdjustment) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseSubtotal($amount) { @@ -1271,7 +1323,7 @@ public function setBaseSubtotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountAmount($amount) { @@ -1279,7 +1331,7 @@ public function setDiscountAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setSubtotal($amount) { @@ -1287,7 +1339,7 @@ public function setSubtotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setAdjustment($adjustment) { @@ -1295,7 +1347,7 @@ public function setAdjustment($adjustment) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseGrandTotal($amount) { @@ -1303,7 +1355,7 @@ public function setBaseGrandTotal($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseTaxAmount($amount) { @@ -1311,7 +1363,7 @@ public function setBaseTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingTaxAmount($amount) { @@ -1319,7 +1371,7 @@ public function setShippingTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setTaxAmount($amount) { @@ -1327,7 +1379,7 @@ public function setTaxAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOrderId($id) { @@ -1335,7 +1387,7 @@ public function setOrderId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setEmailSent($emailSent) { @@ -1343,7 +1395,7 @@ public function setEmailSent($emailSent) } /** - * {@inheritdoc} + * @inheritdoc */ public function setCreditmemoStatus($creditmemoStatus) { @@ -1351,7 +1403,7 @@ public function setCreditmemoStatus($creditmemoStatus) } /** - * {@inheritdoc} + * @inheritdoc */ public function setState($state) { @@ -1359,7 +1411,7 @@ public function setState($state) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingAddressId($id) { @@ -1367,7 +1419,7 @@ public function setShippingAddressId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBillingAddressId($id) { @@ -1375,7 +1427,7 @@ public function setBillingAddressId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setInvoiceId($id) { @@ -1383,7 +1435,7 @@ public function setInvoiceId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setStoreCurrencyCode($code) { @@ -1391,7 +1443,7 @@ public function setStoreCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setOrderCurrencyCode($code) { @@ -1399,7 +1451,7 @@ public function setOrderCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseCurrencyCode($code) { @@ -1407,7 +1459,7 @@ public function setBaseCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setGlobalCurrencyCode($code) { @@ -1415,7 +1467,7 @@ public function setGlobalCurrencyCode($code) } /** - * {@inheritdoc} + * @inheritdoc */ public function setIncrementId($id) { @@ -1423,7 +1475,7 @@ public function setIncrementId($id) } /** - * {@inheritdoc} + * @inheritdoc */ public function setUpdatedAt($timestamp) { @@ -1431,7 +1483,7 @@ public function setUpdatedAt($timestamp) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountTaxCompensationAmount($amount) { @@ -1439,7 +1491,7 @@ public function setDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseDiscountTaxCompensationAmount($amount) { @@ -1447,7 +1499,7 @@ public function setBaseDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingDiscountTaxCompensationAmount($amount) { @@ -1455,7 +1507,7 @@ public function setShippingDiscountTaxCompensationAmount($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) { @@ -1463,7 +1515,7 @@ public function setBaseShippingDiscountTaxCompensationAmnt($amnt) } /** - * {@inheritdoc} + * @inheritdoc */ public function setShippingInclTax($amount) { @@ -1471,7 +1523,7 @@ public function setShippingInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setBaseShippingInclTax($amount) { @@ -1479,7 +1531,7 @@ public function setBaseShippingInclTax($amount) } /** - * {@inheritdoc} + * @inheritdoc */ public function setDiscountDescription($description) { @@ -1487,9 +1539,7 @@ public function setDiscountDescription($description) } /** - * {@inheritdoc} - * - * @return \Magento\Sales\Api\Data\CreditmemoExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -1497,10 +1547,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} - * - * @param \Magento\Sales\Api\Data\CreditmemoExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Sales\Api\Data\CreditmemoExtensionInterface $extensionAttributes) { diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index a4ff621c05e1d..d95adc6c0f38b 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -7,7 +7,7 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <!--Cancel order that is in pending status--> <actionGroup name="cancelPendingOrder"> <click selector="{{AdminOrderDetailsMainActionsSection.cancel}}" stepKey="clickCancelOrder"/> @@ -165,6 +165,15 @@ <assertNotEmpty actual="$getOrderId" stepKey="assertOrderIdIsNotEmpty"/> </actionGroup> + <!--Select free shipping method--> + <actionGroup name="orderSelectFreeShipping"> + <click selector="{{AdminOrderFormPaymentSection.header}}" stepKey="unfocus"/> + <waitForPageLoad stepKey="waitForJavascriptToFinish"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods"/> + <waitForElementVisible selector="{{AdminOrderFormPaymentSection.freeShippingOption}}" stepKey="waitForShippingOptions"/> + <selectOption selector="{{AdminOrderFormPaymentSection.freeShippingOption}}" userInput="freeshipping_freeshipping" stepKey="checkFreeShipping"/> + </actionGroup> + <!--Check that customer information is correct in order--> <actionGroup name="verifyBasicOrderInformation"> <arguments> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml index 79a897ec52a4c..c4cf5bd05bb6f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormItemsSection"> <element name="addProducts" type="button" selector="//section[@id='order-items']/div/div/button/span[text() = 'Add Products']" timeout="30"/> <element name="search" type="button" selector="#sales_order_create_search_grid [data-action='grid-filter-apply']" timeout="30"/> @@ -25,5 +25,6 @@ <element name="productPrice" type="text" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td[@class='col-price col-row-subtotal']/span" parameterized="true"/> <element name="removeItems" type="select" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td/select[@class='admin__control-select']" parameterized="true"/> <element name="applyCoupon" type="input" selector="#coupons:code"/> + <element name="customPriceField" type="input" selector="//*[@class='custom-price-block']/following-sibling::input"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index ab74320f26a30..60d4c53418dc8 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -7,7 +7,7 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormPaymentSection"> <element name="header" type="text" selector="#order-methods span.title"/> <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml new file mode 100644 index 0000000000000..379cb67d3e52f --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml @@ -0,0 +1,90 @@ +<?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="AdminAvailabilityCreditMemoWithNoPaymentTest"> + <annotations> + <features value="Sales"/> + <stories value="MAGETWO-86292: Unable to create Credit memo for order with no payment required"/> + <title value="Checking availability of 'Credit memo' button for order with no payment required"/> + <description value="*Credit Memo* button should be displayed"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-96102"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- Enable *Free Shipping* --> + <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShippingMethod"/> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!-- Disable *Free Shipping* --> + <actionGroup ref="RemoveCustomerFromAdminActionGroup" stepKey="deleteCustomer"> + <argument name="customer" value="Simple_US_Customer"/> + </actionGroup> + <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShippingMethod"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <!-- Flush Magento Cache --> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + <actionGroup ref="logout" stepKey="logOut"/> + </after> + + <!--Proceed to Admin panel > SALES > Orders. Create order--> + <actionGroup ref="navigateToNewOrderPageNewCustomerSingleStore" stepKey="navigateToNewOrderPage"/> + + <!--Add simple product to order--> + <actionGroup ref="addSimpleProductToOrder" stepKey="addFirstProductToOrder"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + + <!--Click *Custom Price* link, enter 0 and click *Update Items and Quantities* button--> + <click selector="{{AdminOrderFormItemsSection.customPrice($$createProduct.name$$)}}" stepKey="clickCustomPriceCheckbox"/> + <waitForElementVisible selector="{{AdminOrderFormItemsSection.customPriceField}}" stepKey="waitForPriceFieldAppears"/> + <fillField selector="{{AdminOrderFormItemsSection.customPriceField}}" userInput="0" stepKey="fillCustomPriceField"/> + <click selector="{{AdminOrderFormItemsSection.update}}" stepKey="clickUpdateItemsAndQuantitiesButton"/> + + <!--Fill customer group and customer email--> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="clickUpdateItemsAndQuantitiesButton"/> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" after="selectCustomerGroup" stepKey="fillCustomerEmail"/> + + <!--Fill customer address information--> + <actionGroup ref="fillOrderCustomerInformation" after="fillCustomerEmail" stepKey="fillCustomerAddress"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + + <!-- Select Free shipping --> + <actionGroup ref="orderSelectFreeShipping" after="fillCustomerAddress" stepKey="selectFreeShippingOption"/> + + <!--Click *Submit Order* button--> + <click selector="{{AdminOrderFormActionSection.submitOrder}}" after="selectFreeShippingOption" stepKey="clickSubmitOrder"/> + + <!--Click *Invoice* button--> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceButton"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" after="clickInvoiceButton" stepKey="seeNewInvoiceInPageTitle"/> + <waitForPageLoad stepKey="waitForInvoicePageOpened"/> + + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <waitForPageLoad stepKey="waitForInvoiceSaved"/> + <see userInput="The invoice has been created." stepKey="seeCorrectMessage"/> + + <!--Verify that *Credit Memo* button is displayed--> + <seeElement selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="seeCreditMemo"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreditMemoItem"/> + <waitForPageLoad stepKey="waitForCreditMemoPageLoaded"/> + <see userInput="New Memo" stepKey="seeNewMemoPage"/> + <seeInCurrentUrl url="{{AdminCreditMemoNewPage.url}}" stepKey="seeUrlOnPage"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php index 71a474c390de3..cc2bf929f8250 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/SaveTest.php @@ -197,9 +197,11 @@ public function testSaveActionWithNegativeCreditmemo() ); $this->_requestMock->expects($this->any())->method('getParam')->will($this->returnValue(null)); - $creditmemoMock = $this->createPartialMock(\Magento\Sales\Model\Order\Creditmemo::class, ['load', 'getGrandTotal', 'getAllowZeroGrandTotal', '__wakeup']); - $creditmemoMock->expects($this->once())->method('getGrandTotal')->will($this->returnValue('0')); - $creditmemoMock->expects($this->once())->method('getAllowZeroGrandTotal')->will($this->returnValue(false)); + $creditmemoMock = $this->createPartialMock( + \Magento\Sales\Model\Order\Creditmemo::class, + ['load', 'isValidGrandTotal', '__wakeup'] + ); + $creditmemoMock->expects($this->once())->method('isValidGrandTotal')->willReturn(false); $this->memoLoaderMock->expects( $this->once() )->method( diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoTest.php index 0b65c2d972d32..5981e8ea77e12 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/CreditmemoTest.php @@ -12,6 +12,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; use Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\CollectionFactory; use Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\Collection as ItemCollection; +use Magento\Framework\App\Config\ScopeConfigInterface; /** * Class CreditmemoTest @@ -30,6 +31,11 @@ class CreditmemoTest extends \PHPUnit\Framework\TestCase */ protected $creditmemo; + /** + * @var ScopeConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $scopeConfigMock; + /** * @var CollectionFactory|\PHPUnit_Framework_MockObject_MockObject */ @@ -38,6 +44,7 @@ class CreditmemoTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->orderFactory = $this->createPartialMock(\Magento\Sales\Model\OrderFactory::class, ['create']); + $this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class); $objectManagerHelper = new ObjectManagerHelper($this); $this->cmItemCollectionFactoryMock = $this->getMockBuilder( @@ -50,16 +57,21 @@ protected function setUp() 'context' => $this->createMock(\Magento\Framework\Model\Context::class), 'registry' => $this->createMock(\Magento\Framework\Registry::class), 'localeDate' => $this->createMock( - \Magento\Framework\Stdlib\DateTime\TimezoneInterface::class), + \Magento\Framework\Stdlib\DateTime\TimezoneInterface::class + ), 'dateTime' => $this->createMock(\Magento\Framework\Stdlib\DateTime::class), 'creditmemoConfig' => $this->createMock( - \Magento\Sales\Model\Order\Creditmemo\Config::class), + \Magento\Sales\Model\Order\Creditmemo\Config::class + ), 'orderFactory' => $this->orderFactory, 'cmItemCollectionFactory' => $this->cmItemCollectionFactoryMock, 'calculatorFactory' => $this->createMock(\Magento\Framework\Math\CalculatorFactory::class), 'storeManager' => $this->createMock(\Magento\Store\Model\StoreManagerInterface::class), 'commentFactory' => $this->createMock(\Magento\Sales\Model\Order\Creditmemo\CommentFactory::class), - 'commentCollectionFactory' => $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Creditmemo\Comment\CollectionFactory::class), + 'commentCollectionFactory' => $this->createMock( + \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Comment\CollectionFactory::class + ), + 'scopeConfig' => $this->scopeConfigMock ]; $this->creditmemo = $objectManagerHelper->getObject( \Magento\Sales\Model\Order\Creditmemo::class, @@ -72,7 +84,10 @@ public function testGetOrder() $orderId = 100000041; $this->creditmemo->setOrderId($orderId); $entityName = 'creditmemo'; - $order = $this->createPartialMock(\Magento\Sales\Model\Order::class, ['load', 'setHistoryEntityName', '__wakeUp']); + $order = $this->createPartialMock( + \Magento\Sales\Model\Order::class, + ['load', 'setHistoryEntityName', '__wakeUp'] + ); $this->creditmemo->setOrderId($orderId); $order->expects($this->atLeastOnce()) ->method('setHistoryEntityName') @@ -95,17 +110,50 @@ public function testGetEntityType() $this->assertEquals('creditmemo', $this->creditmemo->getEntityType()); } - public function testIsValidGrandTotalGrandTotalEmpty() + /** + * @dataProvider validGrandTotalDataProvider + * @param int $grandTotal + * @param int $allowZero + * @param bool $expectedResult + * + * @return void + */ + public function testIsValidGrandTotalGrandTotal(int $grandTotal, int $allowZero, bool $expectedResult) { - $this->creditmemo->setGrandTotal(0); - $this->assertFalse($this->creditmemo->isValidGrandTotal()); + $this->creditmemo->setGrandTotal($grandTotal); + $this->scopeConfigMock->expects($this->any()) + ->method('getValue') + ->with('sales/zerograndtotal_creditmemo/allow_zero_grandtotal', + \Magento\Store\Model\ScopeInterface::SCOPE_STORE) + ->willReturn($allowZero); + + $this->assertEquals($expectedResult, $this->creditmemo->isValidGrandTotal()); } - public function testIsValidGrandTotalGrandTotal() + /** + * Data provider for the testIsValidGrantTotalGrantTotal() + * + * @return array + */ + public function validGrandTotalDataProvider(): array { - $this->creditmemo->setGrandTotal(0); - $this->creditmemo->getAllowZeroGrandTotal(true); - $this->assertFalse($this->creditmemo->isValidGrandTotal()); + return [ + [ + 'grandTotal' => 0, + 'allowZero' => 0, + 'expectedResult' => false, + ], + [ + 'grandTotal' => 0, + 'allowZero' => 1, + 'expectedResult' => true, + ], + [ + 'grandTotal' => 1, + 'allowZero' => 0, + 'expectedResult' => true, + ], + ]; } public function testIsValidGrandTotal() @@ -136,7 +184,8 @@ public function testGetItemsCollectionWithId() /** @var ItemCollection|\PHPUnit_Framework_MockObject_MockObject $itemCollectionMock */ $itemCollectionMock = $this->getMockBuilder( - \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\Collection::class) + \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\Collection::class + ) ->disableOriginalConstructor() ->getMock(); $itemCollectionMock->expects($this->once()) @@ -164,7 +213,8 @@ public function testGetItemsCollectionWithoutId() /** @var ItemCollection|\PHPUnit_Framework_MockObject_MockObject $itemCollectionMock */ $itemCollectionMock = $this->getMockBuilder( - \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\Collection::class) + \Magento\Sales\Model\ResourceModel\Order\Creditmemo\Item\Collection::class + ) ->disableOriginalConstructor() ->getMock(); $itemCollectionMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php index 7f6363346872c..f759280a0e446 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/OrderTest.php @@ -51,6 +51,7 @@ class OrderTest extends \PHPUnit\Framework\TestCase protected $item; /** + * @var HistoryCollectionFactory|\PHPUnit_Framework_MockObject_MockObject * @var HistoryCollectionFactory|\PHPUnit_Framework_MockObject_MockObject */ protected $historyCollectionFactoryMock; @@ -332,6 +333,20 @@ public function testCanCreditMemo() $this->assertTrue($this->order->canCreditmemo()); } + /** + * Test canCreditMemo method when grand total and paid total are zero. + * + * @return void + */ + public function testCanCreditMemoForZeroTotal() + { + $grandTotal = 0; + $totalPaid = 0; + $this->order->setGrandTotal($grandTotal); + $this->order->setTotalPaid($totalPaid); + $this->assertFalse($this->order->canCreditmemo()); + } + public function testCanNotCreditMemoWithTotalNull() { $totalPaid = 0; diff --git a/app/code/Magento/Sales/etc/adminhtml/system.xml b/app/code/Magento/Sales/etc/adminhtml/system.xml index 157420b3d0c73..1b2f8b88d7dc3 100644 --- a/app/code/Magento/Sales/etc/adminhtml/system.xml +++ b/app/code/Magento/Sales/etc/adminhtml/system.xml @@ -48,6 +48,13 @@ <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> </group> + <group id="zerograndtotal_creditmemo" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1"> + <label>Allow Zero GrandTotal</label> + <field id="allow_zero_grandtotal" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <label>Allow Zero GrandTotal for Creditmemo</label> + <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> + </field> + </group> <group id="identity" translate="label" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Invoice and Packing Slip Design</label> <field id="logo" translate="label comment" type="image" sortOrder="100" showInDefault="1" showInWebsite="1" showInStore="1"> diff --git a/app/code/Magento/Sales/etc/config.xml b/app/code/Magento/Sales/etc/config.xml index d4d10bfa6dcce..5be06fa3836a7 100644 --- a/app/code/Magento/Sales/etc/config.xml +++ b/app/code/Magento/Sales/etc/config.xml @@ -18,6 +18,9 @@ <reorder> <allow>1</allow> </reorder> + <zerograndtotal_creditmemo> + <allow_zero_grandtotal>1</allow_zero_grandtotal> + </zerograndtotal_creditmemo> <minimum_order> <tax_including>1</tax_including> </minimum_order> diff --git a/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php index 71105cd844c29..48430fbddad2e 100644 --- a/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php +++ b/dev/tests/integration/testsuite/Magento/Authorizenet/Model/DirectpostTest.php @@ -19,6 +19,8 @@ /** * Class contains tests for Direct Post integration + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DirectpostTest extends \PHPUnit\Framework\TestCase { @@ -136,12 +138,12 @@ public function fdsFilterActionDataProvider() [ 'filter_action' => 'authAndHold', 'order_id' => '100000003', - 'expected_order_state' => Order::STATE_PAYMENT_REVIEW + 'expected_order_state' => Order::STATE_PAYMENT_REVIEW, ], [ 'filter_action' => 'report', 'order_id' => '100000004', - 'expected_order_state' => Order::STATE_PROCESSING + 'expected_order_state' => Order::STATE_COMPLETE, ], ]; } diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Order/PaymentReviewTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Order/PaymentReviewTest.php index 04bac807637db..bb7b04f53dd6d 100644 --- a/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Order/PaymentReviewTest.php +++ b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Adminhtml/Order/PaymentReviewTest.php @@ -70,8 +70,8 @@ public function testExecuteAccept() ); $order = $this->orderRepository->get($orderId); - static::assertEquals(Order::STATE_PROCESSING, $order->getState()); - static::assertEquals(Order::STATE_PROCESSING, $order->getStatus()); + static::assertEquals(Order::STATE_COMPLETE, $order->getState()); + static::assertEquals(Order::STATE_COMPLETE, $order->getStatus()); } /** diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Payflow/SilentPostTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Payflow/SilentPostTest.php index 2bebb5bd95bb2..81a9587d36f4a 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Payflow/SilentPostTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Payflow/SilentPostTest.php @@ -93,7 +93,7 @@ public function testSuccessfulNotification($resultCode, $orderState, $orderStatu public function responseCodeDataProvider() { return [ - [Payflowlink::RESPONSE_CODE_APPROVED, Order::STATE_PROCESSING, Order::STATE_PROCESSING], + [Payflowlink::RESPONSE_CODE_APPROVED, Order::STATE_COMPLETE, Order::STATE_COMPLETE], [Payflowlink::RESPONSE_CODE_FRAUDSERVICE_FILTER, Order::STATE_PAYMENT_REVIEW, Order::STATUS_FRAUD], ]; } From a61bc0b4466a214a68ab678c9045b104fb2ca749 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Tue, 6 Nov 2018 17:10:57 +0200 Subject: [PATCH 23/49] MAGETWO-73061: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 --- app/code/Magento/Bundle/etc/di.xml | 7 + app/code/Magento/Catalog/etc/di.xml | 7 + .../Magento/ConfigurableProduct/etc/di.xml | 7 + app/code/Magento/Downloadable/etc/di.xml | 7 + app/code/Magento/Sales/Model/Order.php | 12 +- .../Sales/Model/Order/ItemRepository.php | 117 +----- .../Sales/Model/Order/ProductOption.php | 103 +++++ .../Unit/Model/Order/ItemRepositoryTest.php | 365 ------------------ .../Magento/Sales/Service/V1/OrderGetTest.php | 134 +++++-- .../Sales/_files/order_with_bundle.php | 87 +++++ .../_files/order_with_bundle_rollback.php | 8 + .../Magento/Sales/_files/order_with_tax.php | 57 +++ .../Sales/_files/order_with_tax_rollback.php | 8 + .../Interception/PluginList/PluginList.php | 2 +- 14 files changed, 428 insertions(+), 493 deletions(-) create mode 100644 app/code/Magento/Sales/Model/Order/ProductOption.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml index 733b089dccd4b..d0e956efee694 100644 --- a/app/code/Magento/Bundle/etc/di.xml +++ b/app/code/Magento/Bundle/etc/di.xml @@ -140,6 +140,13 @@ </argument> </arguments> </type> + <type name="Magento\Sales\Model\Order\ProductOption"> + <arguments> + <argument name="processorPool" xsi:type="array"> + <item name="bundle" xsi:type="object">Magento\Bundle\Model\ProductOptionProcessor</item> + </argument> + </arguments> + </type> <type name="Magento\Bundle\Ui\DataProvider\Product\Listing\Collector\BundlePrice"> <arguments> <argument name="excludeAdjustments" xsi:type="array"> diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 22c6495c2bc93..5b87c7d6ac030 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -600,6 +600,13 @@ </argument> </arguments> </type> + <type name="Magento\Sales\Model\Order\ProductOption"> + <arguments> + <argument name="processorPool" xsi:type="array"> + <item name="custom_options" xsi:type="object">Magento\Catalog\Model\ProductOptionProcessor</item> + </argument> + </arguments> + </type> <type name="Magento\Framework\Model\Entity\RepositoryFactory"> <arguments> <argument name="entities" xsi:type="array"> diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 1dbb0969687d5..102ed1314f864 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -125,6 +125,13 @@ </argument> </arguments> </type> + <type name="Magento\Sales\Model\Order\ProductOption"> + <arguments> + <argument name="processorPool" xsi:type="array"> + <item name="configurable" xsi:type="object">Magento\ConfigurableProduct\Model\ProductOptionProcessor</item> + </argument> + </arguments> + </type> <virtualType name="ConfigurableFinalPriceResolver" type="Magento\ConfigurableProduct\Pricing\Price\ConfigurablePriceResolver"> <arguments> <argument name="priceResolver" xsi:type="object">Magento\ConfigurableProduct\Pricing\Price\FinalPriceResolver</argument> diff --git a/app/code/Magento/Downloadable/etc/di.xml b/app/code/Magento/Downloadable/etc/di.xml index 932e48e880880..4e9b0b55afb0b 100644 --- a/app/code/Magento/Downloadable/etc/di.xml +++ b/app/code/Magento/Downloadable/etc/di.xml @@ -77,6 +77,13 @@ </argument> </arguments> </type> + <type name="Magento\Sales\Model\Order\ProductOption"> + <arguments> + <argument name="processorPool" xsi:type="array"> + <item name="downloadable" xsi:type="object">Magento\Downloadable\Model\ProductOptionProcessor</item> + </argument> + </arguments> + </type> <preference for="Magento\Downloadable\Api\LinkRepositoryInterface" type="Magento\Downloadable\Model\LinkRepository" /> <preference for="Magento\Downloadable\Api\SampleRepositoryInterface" type="Magento\Downloadable\Model\SampleRepository" /> <preference for="Magento\Downloadable\Api\Data\LinkInterface" type="Magento\Downloadable\Model\Link" /> diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php index a1bbd4856df16..40e271c0ee35f 100644 --- a/app/code/Magento/Sales/Model/Order.php +++ b/app/code/Magento/Sales/Model/Order.php @@ -13,6 +13,7 @@ use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderStatusHistoryInterface; use Magento\Sales\Model\Order\Payment; +use Magento\Sales\Model\Order\ProductOption; use Magento\Sales\Model\ResourceModel\Order\Address\Collection; use Magento\Sales\Model\ResourceModel\Order\Creditmemo\Collection as CreditmemoCollection; use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection as InvoiceCollection; @@ -274,6 +275,11 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface */ private $localeResolver; + /** + * @var ProductOption + */ + private $productOption; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -303,6 +309,7 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data * @param ResolverInterface $localeResolver + * @param ProductOption|null $productOption * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -334,7 +341,8 @@ public function __construct( \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [], - ResolverInterface $localeResolver = null + ResolverInterface $localeResolver = null, + ProductOption $productOption = null ) { $this->_storeManager = $storeManager; $this->_orderConfig = $orderConfig; @@ -356,6 +364,7 @@ public function __construct( $this->salesOrderCollectionFactory = $salesOrderCollectionFactory; $this->priceCurrency = $priceCurrency; $this->localeResolver = $localeResolver ?: ObjectManager::getInstance()->get(ResolverInterface::class); + $this->productOption = $productOption ?: ObjectManager::getInstance()->get(ProductOption::class); parent::__construct( $context, @@ -1288,6 +1297,7 @@ public function getItemsCollection($filterByTypes = [], $nonChildrenOnly = false if ($this->getId()) { foreach ($collection as $item) { $item->setOrder($this); + $this->productOption->add($item); } } return $collection; diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index 544c809e2c082..fd6836d3f286e 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -5,9 +5,7 @@ */ namespace Magento\Sales\Model\Order; -use Magento\Catalog\Api\Data\ProductOptionExtensionFactory; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; -use Magento\Catalog\Model\ProductOptionFactory; use Magento\Catalog\Model\ProductOptionProcessorInterface; use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\DataObject; @@ -17,6 +15,7 @@ use Magento\Sales\Api\Data\OrderItemInterface; use Magento\Sales\Api\Data\OrderItemSearchResultInterfaceFactory; use Magento\Sales\Api\OrderItemRepositoryInterface; +use Magento\Sales\Model\Order\ProductOption; use Magento\Sales\Model\ResourceModel\Metadata; /** @@ -40,16 +39,6 @@ class ItemRepository implements OrderItemRepositoryInterface */ protected $searchResultFactory; - /** - * @var ProductOptionFactory - */ - protected $productOptionFactory; - - /** - * @var ProductOptionExtensionFactory - */ - protected $extensionFactory; - /** * @var ProductOptionProcessorInterface[] */ @@ -61,40 +50,41 @@ class ItemRepository implements OrderItemRepositoryInterface protected $registry = []; /** - * @var \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface + * @var CollectionProcessorInterface */ private $collectionProcessor; /** - * ItemRepository constructor. + * @var ProductOption + */ + private $productOption; + + /** * @param DataObjectFactory $objectFactory * @param Metadata $metadata * @param OrderItemSearchResultInterfaceFactory $searchResultFactory - * @param ProductOptionFactory $productOptionFactory - * @param ProductOptionExtensionFactory $extensionFactory + * @param CollectionProcessorInterface $collectionProcessor + * @param ProductOption $productOption * @param array $processorPool - * @param CollectionProcessorInterface|null $collectionProcessor */ public function __construct( DataObjectFactory $objectFactory, Metadata $metadata, OrderItemSearchResultInterfaceFactory $searchResultFactory, - ProductOptionFactory $productOptionFactory, - ProductOptionExtensionFactory $extensionFactory, - array $processorPool = [], - CollectionProcessorInterface $collectionProcessor = null + CollectionProcessorInterface $collectionProcessor, + ProductOption $productOption, + array $processorPool = [] ) { $this->objectFactory = $objectFactory; $this->metadata = $metadata; $this->searchResultFactory = $searchResultFactory; - $this->productOptionFactory = $productOptionFactory; - $this->extensionFactory = $extensionFactory; + $this->collectionProcessor = $collectionProcessor; + $this->productOption = $productOption; $this->processorPool = $processorPool; - $this->collectionProcessor = $collectionProcessor ?: $this->getCollectionProcessor(); } /** - * load entity + * Loads entity. * * @param int $id * @return OrderItemInterface @@ -113,7 +103,7 @@ public function get($id) throw new NoSuchEntityException(__('Requested entity doesn\'t exist')); } - $this->addProductOption($orderItem); + $this->productOption->add($orderItem); $this->addParentItem($orderItem); $this->registry[$id] = $orderItem; } @@ -134,7 +124,7 @@ public function getList(SearchCriteriaInterface $searchCriteria) $this->collectionProcessor->process($searchCriteria, $searchResult); /** @var OrderItemInterface $orderItem */ foreach ($searchResult->getItems() as $orderItem) { - $this->addProductOption($orderItem); + $this->productOption->add($orderItem); } return $searchResult; @@ -183,37 +173,6 @@ public function save(OrderItemInterface $entity) return $this->registry[$entity->getEntityId()]; } - /** - * Add product option data - * - * @param OrderItemInterface $orderItem - * @return $this - */ - protected function addProductOption(OrderItemInterface $orderItem) - { - /** @var DataObject $request */ - $request = $orderItem->getBuyRequest(); - - $productType = $orderItem->getProductType(); - if (isset($this->processorPool[$productType]) - && !$orderItem->getParentItemId()) { - $data = $this->processorPool[$productType]->convertToProductOption($request); - if ($data) { - $this->setProductOption($orderItem, $data); - } - } - - if (isset($this->processorPool['custom_options']) - && !$orderItem->getParentItemId()) { - $data = $this->processorPool['custom_options']->convertToProductOption($request); - if ($data) { - $this->setProductOption($orderItem, $data); - } - } - - return $this; - } - /** * Set parent item. * @@ -228,32 +187,6 @@ private function addParentItem(OrderItemInterface $orderItem) } } - /** - * Set product options data - * - * @param OrderItemInterface $orderItem - * @param array $data - * @return $this - */ - protected function setProductOption(OrderItemInterface $orderItem, array $data) - { - $productOption = $orderItem->getProductOption(); - if (!$productOption) { - $productOption = $this->productOptionFactory->create(); - $orderItem->setProductOption($productOption); - } - - $extensionAttributes = $productOption->getExtensionAttributes(); - if (!$extensionAttributes) { - $extensionAttributes = $this->extensionFactory->create(); - $productOption->setExtensionAttributes($extensionAttributes); - } - - $extensionAttributes->setData(key($data), current($data)); - - return $this; - } - /** * Retrieve order item's buy request * @@ -285,20 +218,4 @@ protected function getBuyRequest(OrderItemInterface $entity) return $request; } - - /** - * Retrieve collection processor - * - * @deprecated 100.2.0 - * @return CollectionProcessorInterface - */ - private function getCollectionProcessor() - { - if (!$this->collectionProcessor) { - $this->collectionProcessor = \Magento\Framework\App\ObjectManager::getInstance()->get( - \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface::class - ); - } - return $this->collectionProcessor; - } } diff --git a/app/code/Magento/Sales/Model/Order/ProductOption.php b/app/code/Magento/Sales/Model/Order/ProductOption.php new file mode 100644 index 0000000000000..dc9ec42e27e60 --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/ProductOption.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Sales\Model\Order; + +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Framework\DataObject; +use Magento\Catalog\Model\ProductOptionFactory; +use Magento\Catalog\Model\ProductOptionProcessorInterface; +use Magento\Catalog\Api\Data\ProductOptionExtensionFactory; + +/** + * Adds product option to the order item according to product options processors pool. + * + * @api + */ +class ProductOption +{ + /** + * @var ProductOptionFactory + */ + private $productOptionFactory; + + /** + * @var ProductOptionExtensionFactory + */ + private $extensionFactory; + + /** + * @var ProductOptionProcessorInterface[] + */ + private $processorPool; + + /** + * @param ProductOptionFactory $productOptionFactory + * @param ProductOptionExtensionFactory $extensionFactory + * @param array $processorPool + */ + public function __construct( + ProductOptionFactory $productOptionFactory, + ProductOptionExtensionFactory $extensionFactory, + array $processorPool = [] + ) { + $this->productOptionFactory = $productOptionFactory; + $this->extensionFactory = $extensionFactory; + $this->processorPool = $processorPool; + } + + /** + * Adds product option to the order item. + * + * @param OrderItemInterface $orderItem + */ + public function add(OrderItemInterface $orderItem): void + { + /** @var DataObject $request */ + $request = $orderItem->getBuyRequest(); + + $productType = $orderItem->getProductType(); + if (isset($this->processorPool[$productType]) + && !$orderItem->getParentItemId()) { + $data = $this->processorPool[$productType]->convertToProductOption($request); + if ($data) { + $this->setProductOption($orderItem, $data); + } + } + + if (isset($this->processorPool['custom_options']) + && !$orderItem->getParentItemId()) { + $data = $this->processorPool['custom_options']->convertToProductOption($request); + if ($data) { + $this->setProductOption($orderItem, $data); + } + } + } + + /** + * Sets product options data. + * + * @param OrderItemInterface $orderItem + * @param array $data + */ + private function setProductOption(OrderItemInterface $orderItem, array $data): void + { + $productOption = $orderItem->getProductOption(); + if (!$productOption) { + $productOption = $this->productOptionFactory->create(); + $orderItem->setProductOption($productOption); + } + + $extensionAttributes = $productOption->getExtensionAttributes(); + if (!$extensionAttributes) { + $extensionAttributes = $this->extensionFactory->create(); + $productOption->setExtensionAttributes($extensionAttributes); + } + + $extensionAttributes->setData(key($data), current($data)); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php deleted file mode 100644 index 0c34e5bdffd4a..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ItemRepositoryTest.php +++ /dev/null @@ -1,365 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Sales\Test\Unit\Model\Order; - -use Magento\Sales\Model\Order\ItemRepository; - -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class ItemRepositoryTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Framework\DataObject\Factory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $objectFactory; - - /** - * @var \Magento\Sales\Model\ResourceModel\Metadata|\PHPUnit_Framework_MockObject_MockObject - */ - protected $metadata; - - /** - * @var \Magento\Sales\Api\Data\OrderItemSearchResultInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $searchResultFactory; - - /** - * @var \Magento\Catalog\Model\ProductOptionProcessorInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $productOptionProcessorMock; - - /** - * @var \Magento\Catalog\Model\ProductOptionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $productOptionFactory; - - /** - * @var \Magento\Catalog\Api\Data\ProductOptionExtensionFactory|\PHPUnit_Framework_MockObject_MockObject - */ - protected $extensionFactory; - - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $collectionProcessor; - - /** - * @var array - */ - protected $productOptionData = []; - - protected function setUp() - { - $this->objectFactory = $this->getMockBuilder(\Magento\Framework\DataObject\Factory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->metadata = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Metadata::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->searchResultFactory = $this->getMockBuilder( - \Magento\Sales\Api\Data\OrderItemSearchResultInterfaceFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->productOptionFactory = $this->getMockBuilder(\Magento\Catalog\Model\ProductOptionFactory::class) - ->setMethods([ - 'create', - ]) - ->disableOriginalConstructor() - ->getMock(); - - $this->collectionProcessor = $this->createMock( - \Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface::class - ); - - $this->extensionFactory = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductOptionExtensionFactory::class) - ->setMethods([ - 'create', - ]) - ->disableOriginalConstructor() - ->getMock(); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage ID required - */ - public function testGetWithNoId() - { - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [], - $this->collectionProcessor - ); - - $model->get(null); - } - - /** - * @expectedException \Magento\Framework\Exception\NoSuchEntityException - * @expectedExceptionMessage Requested entity doesn't exist - */ - public function testGetEmptyEntity() - { - $orderItemId = 1; - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn(null); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [], - $this->collectionProcessor - ); - - $model->get($orderItemId); - } - - public function testGet() - { - $orderItemId = 1; - $productType = 'configurable'; - - $this->productOptionData = ['option1' => 'value1']; - - $this->getProductOptionExtensionMock(); - $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); - - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn($orderItemId); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertSame($orderItemMock, $model->get($orderItemId)); - - // Assert already registered - $this->assertSame($orderItemMock, $model->get($orderItemId)); - } - - public function testGetList() - { - $productType = 'configurable'; - $this->productOptionData = ['option1' => 'value1']; - $searchCriteriaMock = $this->getMockBuilder(\Magento\Framework\Api\SearchCriteria::class) - ->disableOriginalConstructor() - ->getMock(); - $this->getProductOptionExtensionMock(); - $productOption = $this->getProductOptionMock(); - $orderItemMock = $this->getOrderMock($productType, $productOption); - - $searchResultMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Item\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $searchResultMock->expects($this->once()) - ->method('getItems') - ->willReturn([$orderItemMock]); - - $this->searchResultFactory->expects($this->once()) - ->method('create') - ->willReturn($searchResultMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertSame($searchResultMock, $model->getList($searchCriteriaMock)); - } - - public function testDeleteById() - { - $orderItemId = 1; - $productType = 'configurable'; - - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('load') - ->with($orderItemId) - ->willReturn($orderItemMock); - $orderItemMock->expects($this->once()) - ->method('getItemId') - ->willReturn($orderItemId); - $orderItemMock->expects($this->once()) - ->method('getProductType') - ->willReturn($productType); - $orderItemMock->expects($this->once()) - ->method('getBuyRequest') - ->willReturn($requestMock); - - $orderItemResourceMock = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemResourceMock->expects($this->once()) - ->method('delete') - ->with($orderItemMock) - ->willReturnSelf(); - - $this->metadata->expects($this->once()) - ->method('getNewInstance') - ->willReturn($orderItemMock); - $this->metadata->expects($this->exactly(1)) - ->method('getMapper') - ->willReturn($orderItemResourceMock); - - $model = $this->getModel($orderItemMock, $productType); - $this->assertTrue($model->deleteById($orderItemId)); - } - - /** - * @param \PHPUnit_Framework_MockObject_MockObject $orderItemMock - * @param string $productType - * @param array $data - * @return ItemRepository - */ - protected function getModel( - \PHPUnit_Framework_MockObject_MockObject $orderItemMock, - $productType, - array $data = [] - ) { - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $requestUpdateMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - $requestUpdateMock->expects($this->any()) - ->method('getData') - ->willReturn($data); - - $this->productOptionProcessorMock = $this->getMockBuilder( - \Magento\Catalog\Model\ProductOptionProcessorInterface::class - ) - ->getMockForAbstractClass(); - $this->productOptionProcessorMock->expects($this->any()) - ->method('convertToProductOption') - ->with($requestMock) - ->willReturn($this->productOptionData); - $this->productOptionProcessorMock->expects($this->any()) - ->method('convertToBuyRequest') - ->with($orderItemMock) - ->willReturn($requestUpdateMock); - - $model = new ItemRepository( - $this->objectFactory, - $this->metadata, - $this->searchResultFactory, - $this->productOptionFactory, - $this->extensionFactory, - [ - $productType => $this->productOptionProcessorMock, - 'custom_options' => $this->productOptionProcessorMock - ], - $this->collectionProcessor - ); - return $model; - } - - /** - * @param string $productType - * @param \PHPUnit_Framework_MockObject_MockObject $productOption - * @return \PHPUnit_Framework_MockObject_MockObject - */ - protected function getOrderMock($productType, $productOption) - { - $requestMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->disableOriginalConstructor() - ->getMock(); - - $orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) - ->disableOriginalConstructor() - ->getMock(); - $orderItemMock->expects($this->once()) - ->method('getProductType') - ->willReturn($productType); - $orderItemMock->expects($this->once()) - ->method('getBuyRequest') - ->willReturn($requestMock); - $orderItemMock->expects($this->any()) - ->method('getProductOption') - ->willReturn(null); - $orderItemMock->expects($this->any()) - ->method('setProductOption') - ->with($productOption) - ->willReturnSelf(); - - return $orderItemMock; - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - protected function getProductOptionMock() - { - $productOption = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductOptionInterface::class) - ->getMockForAbstractClass(); - $productOption->expects($this->any()) - ->method('getExtensionAttributes') - ->willReturn(null); - - $this->productOptionFactory->expects($this->any()) - ->method('create') - ->willReturn($productOption); - - return $productOption; - } - - protected function getProductOptionExtensionMock() - { - $productOptionExtension = $this->getMockBuilder( - \Magento\Catalog\Api\Data\ProductOptionExtensionInterface::class - ) - ->setMethods([ - 'setData', - ]) - ->getMockForAbstractClass(); - $productOptionExtension->expects($this->any()) - ->method('setData') - ->with(key($this->productOptionData), current($this->productOptionData)) - ->willReturnSelf(); - - $this->extensionFactory->expects($this->any()) - ->method('create') - ->willReturn($productOptionExtension); - } -} diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php index 7adde3c11ac61..6715c73510290 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderGetTest.php @@ -3,10 +3,20 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Service\V1; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\WebapiAbstract; +/** + * Test for Order Get + */ class OrderGetTest extends WebapiAbstract { const RESOURCE_PATH = '/V1/orders'; @@ -18,16 +28,21 @@ class OrderGetTest extends WebapiAbstract const ORDER_INCREMENT_ID = '100000001'; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManagerInterface */ - protected $objectManager; + private $objectManager; + /** + * @inheritdoc + */ protected function setUp() { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = Bootstrap::getObjectManager(); } /** + * Checks order attributes. + * * @magentoApiDataFixture Magento/Sales/_files/order.php */ public function testOrderGet() @@ -67,36 +82,21 @@ public function testOrderGet() 'region' => 'CA' ]; - /** @var \Magento\Sales\Model\Order $order */ - $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); - $order->loadByIncrementId(self::ORDER_INCREMENT_ID); - - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => self::RESOURCE_PATH . '/' . $order->getId(), - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, - ], - 'soap' => [ - 'service' => self::SERVICE_READ_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_READ_NAME . 'get', - ], - ]; - $result = $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + $result = $this->makeServiceCall(self::ORDER_INCREMENT_ID); foreach ($expectedOrderData as $field => $value) { - $this->assertArrayHasKey($field, $result); - $this->assertEquals($value, $result[$field]); + self::assertArrayHasKey($field, $result); + self::assertEquals($value, $result[$field]); } - $this->assertArrayHasKey('payment', $result); + self::assertArrayHasKey('payment', $result); foreach ($expectedPayments as $field => $value) { - $this->assertEquals($value, $result['payment'][$field]); + self::assertEquals($value, $result['payment'][$field]); } - $this->assertArrayHasKey('billing_address', $result); + self::assertArrayHasKey('billing_address', $result); foreach ($expectedBillingAddressNotEmpty as $field) { - $this->assertArrayHasKey($field, $result['billing_address']); + self::assertArrayHasKey($field, $result['billing_address']); } self::assertArrayHasKey('extension_attributes', $result); @@ -112,7 +112,89 @@ public function testOrderGet() //check that nullable fields were marked as optional and were not sent foreach ($result as $value) { - $this->assertNotNull($value); + self::assertNotNull($value); } } + + /** + * Checks if the order contains product option attributes. + * + * @magentoApiDataFixture Magento/Sales/_files/order_with_bundle.php + */ + public function testGetOrderWithProductOption() + { + $expected = [ + 'extension_attributes' => [ + 'bundle_options' => [ + [ + 'option_id' => 1, + 'option_selections' => [1], + 'option_qty' => 1 + ] + ] + ] + ]; + $result = $this->makeServiceCall(self::ORDER_INCREMENT_ID); + + $bundleProduct = $this->getBundleProduct($result['items']); + self::assertNotEmpty($bundleProduct, '"Bundle Product" should not be empty.'); + self::assertNotEmpty($bundleProduct['product_option'], '"Product Option" should not be empty.'); + self::assertEquals($expected, $bundleProduct['product_option']); + } + + /** + * Gets order by increment ID. + * + * @param string $incrementId + * @return OrderInterface + */ + private function getOrder(string $incrementId): OrderInterface + { + /** @var Order $order */ + $order = $this->objectManager->create(Order::class); + $order->loadByIncrementId($incrementId); + + return $order; + } + + /** + * Makes service call. + * + * @param string $incrementId + * @return array + */ + private function makeServiceCall(string $incrementId): array + { + $order = $this->getOrder($incrementId); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . '/' . $order->getId(), + 'httpMethod' => Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'get', + ], + ]; + + return $this->_webApiCall($serviceInfo, ['id' => $order->getId()]); + } + + /** + * Gets a bundle product from the result. + * + * @param array $items + * @return array + */ + private function getBundleProduct(array $items): array + { + foreach ($items as $item) { + if ($item['product_type'] == 'bundle') { + return $item; + } + } + + return []; + } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php new file mode 100644 index 0000000000000..4473fb8dfe72c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Item; +use Magento\TestFramework\ObjectManager; + +$objectManager = ObjectManager::getInstance(); + +require 'order.php'; +/** @var Order $order */ + +$orderItems = [ + [ + OrderItemInterface::PRODUCT_ID => 2, + OrderItemInterface::BASE_PRICE => 100, + OrderItemInterface::ORDER_ID => $order->getId(), + OrderItemInterface::QTY_ORDERED => 2, + OrderItemInterface::QTY_INVOICED => 2, + OrderItemInterface::PRICE => 100, + OrderItemInterface::ROW_TOTAL => 102, + OrderItemInterface::PRODUCT_TYPE => 'bundle', + 'product_options' => [ + 'product_calculations' => 0, + 'info_buyRequest' => [ + 'bundle_option' => [1 => 1], + 'bundle_option_qty' => 1, + ] + ], + 'children' => [ + [ + OrderItemInterface::PRODUCT_ID => 13, + OrderItemInterface::ORDER_ID => $order->getId(), + OrderItemInterface::QTY_ORDERED => 10, + OrderItemInterface::QTY_INVOICED => 10, + OrderItemInterface::BASE_PRICE => 90, + OrderItemInterface::PRICE => 90, + OrderItemInterface::ROW_TOTAL => 92, + OrderItemInterface::PRODUCT_TYPE => 'simple', + 'product_options' => [ + 'bundle_selection_attributes' => [ + 'qty' => 2, + ], + ], + ], + ], + ], +]; + +if (!function_exists('saveOrderItems')) { + /** + * Save Order Items. + * + * @param array $orderItems + * @param Item|null $parentOrderItem [optional] + * @return void + */ + function saveOrderItems(array $orderItems, Order $order, $parentOrderItem = null) + { + $objectManager = ObjectManager::getInstance(); + + foreach ($orderItems as $orderItemData) { + /** @var Item $orderItem */ + $orderItem = $objectManager->create(Item::class); + if (null !== $parentOrderItem) { + $orderItemData['parent_item'] = $parentOrderItem; + } + $orderItem->setData($orderItemData); + $order->addItem($orderItem); + + if (isset($orderItemData['children'])) { + saveOrderItems($orderItemData['children'], $order, $orderItem); + } + } + } +} + +saveOrderItems($orderItems, $order); +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$order = $orderRepository->save($order); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php new file mode 100644 index 0000000000000..dd52deab825cb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_bundle_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require 'order_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php new file mode 100644 index 0000000000000..3612f4957a964 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Sales\Model\Order\Tax\ItemFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\Tax\Model\Sales\Order\TaxFactory; +use Magento\Sales\Model\ResourceModel\Order\Item as OrderItemResource; +use Magento\Sales\Model\ResourceModel\Order\Tax\Item as OrderTaxItemResource; + +require 'default_rollback.php'; +require 'order.php'; + +$amount = 45; +$taxFactory = $objectManager->create(TaxFactory::class); + +/** @var \Magento\Tax\Model\Sales\Order\Tax $tax */ +$tax = $taxFactory->create(); +$tax->setOrderId($order->getId()) + ->setCode('US-NY-*-Rate 1') + ->setTitle('US-NY-*-Rate 1') + ->setPercent(8.37) + ->setAmount($amount) + ->setBaseAmount($amount) + ->setBaseRealAmount($amount); +$tax->save(); + +/** @var ItemFactory $salesOrderFactory */ +$salesOrderFactory = $objectManager->create(ItemFactory::class); + +/** @var \Magento\Sales\Model\Order\Tax\Item $salesOrderItem */ +$salesOrderItem = $salesOrderFactory->create(); +$salesOrderItem->setOrderId($order->getId()) + ->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore()->getId()) + ->setProductOptions([]); +/** @var OrderItemResource $orderItemResource */ +$orderItemResource = $objectManager->create(OrderItemResource::class); +$orderItemResource->save($salesOrderItem); + +/** @var \Magento\Sales\Model\Order\Tax\Item $salesOrderTaxItem */ +$salesOrderTaxItem = $salesOrderFactory->create(); +$salesOrderTaxItem->setTaxId($tax->getId()) + ->setTaxPercent(8.37) + ->setTaxAmount($amount) + ->setBaseAmount($amount) + ->setRealAmount($amount) + ->setRealBaseAmount($amount) + ->setAppliedTaxes([$tax]) + ->setTaxableItemType('shipping') + ->setItemId($salesOrderItem->getId()); + +/** @var OrderTaxItemResource $orderTaxItemResource */ +$orderTaxItemResource = $objectManager->create(OrderTaxItemResource::class); +$orderTaxItemResource->save($salesOrderTaxItem); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php new file mode 100644 index 0000000000000..dd52deab825cb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +require 'order_rollback.php'; diff --git a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php index 718b08190d8be..8e6c42080a4ce 100644 --- a/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php +++ b/lib/internal/Magento/Framework/Interception/PluginList/PluginList.php @@ -30,7 +30,7 @@ class PluginList extends Scoped implements InterceptionPluginList * * @var array */ - protected $_inherited; + protected $_inherited = []; /** * Inherited plugin data, preprocessed for read From c28d5dfa78fab6725e1dd077762fc445c0e75c38 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Tue, 6 Nov 2018 19:03:07 +0200 Subject: [PATCH 24/49] MAGETWO-85162: Results of filters with color and other filters are not showing product results --- .../AdminProductAttributeActionGroup.xml | 11 + .../AdminProductAttributeSetActionGroup.xml | 21 +- .../Test/Mftf/Data/FrontendLabelData.xml | 5 + .../Data/ProductConfigurableAttributeData.xml | 8 + .../Catalog/Test/Mftf/Data/ProductData.xml | 1 + .../AdminProductAttributeSetGridSection.xml | 1 + .../Section/AdminProductFormActionSection.xml | 1 + .../Mftf/Section/AdminProductFormSection.xml | 5 + .../Section/AttributePropertiesSection.xml | 2 + .../StorefrontCategorySidebarSection.xml | 1 + .../FilterMapper/CustomAttributeFilter.php | 6 +- ...inCreateConfigurableProductActionGroup.xml | 67 +++++ ...ProductWithExcludingOptionsActionGroup.xml | 25 ++ .../Section/AdminNewAttributePanelSection.xml | 2 + ...StorefrontCheckingResultsOfFiltersTest.xml | 235 ++++++++++++++++++ .../CustomAttributeFilterTest.php | 3 - 16 files changed, 386 insertions(+), 8 deletions(-) create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductWithExcludingOptionsActionGroup.xml create mode 100644 app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index 341360ce87173..dcc97fedbb8bf 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -25,4 +25,15 @@ <click selector="{{AttributePropertiesSection.save}}" stepKey="saveAttribute"/> <see selector="{{AdminMessagesSection.successMessage}}" userInput="You saved the product attribute." stepKey="successMessage"/> </actionGroup> + <actionGroup name="navigateToProductAttributeByCode"> + <arguments> + <argument name="attributeCode" type="string"/> + </arguments> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="goToProductAttributesPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <fillField selector="{{AdminProductAttributeGridSection.filterByAttributeCode}}" userInput="{{attributeCode}}" stepKey="fillFilter"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearch"/> + <click selector="{{AdminProductAttributeGridSection.attributeCode(attributeCode)}}" stepKey="clickRowToEdit"/> + <waitForPageLoad stepKey="waitForColorAttributePageLoad"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml index a7e76253728a3..17f27056c555e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml @@ -11,7 +11,7 @@ <actionGroup name="AssignAttributeToGroup"> <arguments> <argument name="group" type="string"/> - <argument name="attribute" type="string"/> + <argument name="attribute"/> </arguments> <conditionalClick selector="{{AdminProductAttributeSetEditSection.attributeGroupExtender(group)}}" dependentSelector="{{AdminProductAttributeSetEditSection.attributeGroupCollapsed(group)}}" visible="true" stepKey="extendGroup"/> <waitForPageLoad stepKey="waitForPageLoad1"/> @@ -34,4 +34,23 @@ <click selector="{{AdminProductAttributeSetActionSection.save}}" stepKey="clickSave"/> <see userInput="You saved the attribute set" selector="{{AdminMessagesSection.success}}" stepKey="successMessage"/> </actionGroup> + <actionGroup name="CreateAttributeSet"> + <arguments> + <argument name="attributeSetName" type="string"/> + </arguments> + <amOnPage url="{{AdminProductAttributeSetGridPage.url}}" stepKey="goToAttributeSets"/> + <click selector="{{AdminProductAttributeSetGridSection.addAttributeSetBtn}}" stepKey="clickAddAttributeSet"/> + <fillField selector="{{AdminProductAttributeSetSection.name}}" userInput="{{attributeSetName}}" stepKey="fillName"/> + <selectOption selector="{{AdminProductAttributeSetSection.basedOn}}" userInput="Default" stepKey="changeOption"/> + <click selector="{{AdminProductAttributeSetSection.save}}" stepKey="clickSaveAttributeSet"/> + <see userInput="You saved the attribute set" selector="{{AdminMessagesSection.success}}" stepKey="successMessage"/> + </actionGroup> + <actionGroup name="AssignProductToAttributeSet"> + <arguments> + <argument name="attributeSetName" type="string"/> + </arguments> + <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSetName}}" stepKey="searchForAttrSet"/> + <waitForAjaxLoad stepKey="waitForLoad"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml index 77cb6e13a95e3..7b01b6b4e5189 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/FrontendLabelData.xml @@ -11,9 +11,14 @@ <entity name="ProductAttributeFrontendLabel" type="FrontendLabel"> <data key="store_id">0</data> <data key="label" unique="suffix">attribute</data> + <data key="default_label" unique="suffix">attribute</data> </entity> <entity name="ProductAttributeFrontendLabelThree" type="FrontendLabel"> <data key="store_id">0</data> <data key="label" unique="suffix">attributeThree</data> </entity> + <entity name="ColorAttributeFrontandLabel" type="FrontendLabel"> + <data key="store_id">0</data> + <data key="label">color</data> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductConfigurableAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductConfigurableAttributeData.xml index 0c9a2f7041902..4deebbe09af34 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductConfigurableAttributeData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductConfigurableAttributeData.xml @@ -24,4 +24,12 @@ <data key="name" unique="suffix">Blue</data> <data key="price">3.00</data> </entity> + <entity name="ColorProductAttribute4" type="product_attribute"> + <data key="name" unique="suffix">Green</data> + <data key="price">4.00</data> + </entity> + <entity name="ColorProductAttribute5" type="product_attribute"> + <data key="name" unique="suffix">Black</data> + <data key="price">5.00</data> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 007529a06d9f4..912a78928ab30 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -85,6 +85,7 @@ <data key="attribute_set_id">4</data> <data key="name" unique="suffix">SimpleProduct2</data> <data key="price">300.00</data> + <data key="quantity">200</data> <data key="visibility">4</data> <data key="status">1</data> <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeSetGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeSetGridSection.xml index bc179ff95841e..661ed4998ffc7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeSetGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeSetGridSection.xml @@ -14,5 +14,6 @@ <element name="applyFilterButton" type="button" selector="#setGrid [data-action='grid-filter-apply']" timeout="30"/> <element name="attributeSetRowByIndex" type="block" selector="#setGrid_table tbody tr:nth-of-type({{var1}})" parameterized="true"/> <element name="addAttributeSetBtn" type="button" selector="button.add-set" timeout="30"/> + <element name="deleteOptionByName" type="button" selector="//*[contains(@value, '{{arg}}')]/../following-sibling::td[contains(@class, 'delete')]/button" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml index 797e603bace30..3eab31e32cc24 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormActionSection.xml @@ -14,5 +14,6 @@ <element name="saveAndClose" type="button" selector="span[id='save_and_close']" timeout="30"/> <element name="changeStoreButton" type="button" selector="#store-change-button"/> <element name="selectStoreView" type="button" selector="//ul[@data-role='stores-list']/li/a[normalize-space(.)='{{var1}}']" timeout="10" parameterized="true"/> + <element name="saveAndNew" type="button" selector="#save_and_new" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml index 0cbb0cb519751..f17ab4d65ef81 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection.xml @@ -35,6 +35,8 @@ <element name="attributeSetSearchCount" type="text" selector="div[data-index='attribute_set_id'] .admin__action-multiselect-search-count"/> <element name="attributeLabelByText" type="text" selector="//*[@class='admin__field']//label[text()='{{attributeLabel}}']" parameterized="true"/> <element name="addAttributeBtn" type="button" selector="#addAttribute"/> + <element name="attributeSetFilterResultByName" type="text" selector="//label/span[text() = '{{var}}']" timeout="30" parameterized="true"/> + <element name="attributeSetDropDown" type="select" selector="div[data-index='attribute_set_id'] .action-select.admin__action-multiselect"/> </section> <section name="ProductInWebsitesSection"> <element name="sectionHeader" type="button" selector="div[data-index='websites']" timeout="30"/> @@ -172,6 +174,9 @@ <element name="applySingleQuantityToEachSkus" type="radio" selector=".admin__field-label[for='apply-single-inventory-radio']" timeout="30"/> <element name="quantity" type="input" selector="#apply-single-inventory-input"/> + <element name="applySinglePriceToAllSkus" type="radio" selector=".admin__field-label[for='apply-single-price-radio']"/> + <element name="singlePrice" type="input" selector="#apply-single-price-input"/> + <element name="attributeByName" type="input" selector="//label[text()='{{var}}']/preceding-sibling::input" parameterized="true"/> </section> <section name="AdminNewAttributePanel"> <element name="saveAttribute" type="button" selector="#save" timeout="30"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AttributePropertiesSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AttributePropertiesSection.xml index fbf07429b8408..9df1b6a383972 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AttributePropertiesSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AttributePropertiesSection.xml @@ -17,5 +17,7 @@ <element name="save" type="button" selector="#save" timeout="30"/> <element name="saveAndEdit" type="button" selector="#save_and_edit_button"/> <element name="checkIfTabOpen" selector="//div[@id='advanced_fieldset-wrapper' and not(contains(@class,'opened'))]" type="button"/> + <element name="scope" type="select" selector="#is_global"/> + <element name="useInLayeredNavigation" type="select" selector="#is_filterable"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategorySidebarSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategorySidebarSection.xml index ef4c475730174..daa93dc3e6c38 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategorySidebarSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategorySidebarSection.xml @@ -13,5 +13,6 @@ <element name="filterOptions" type="text" selector=".filter-options-content .items"/> <element name="filterOption" type="text" selector=".filter-options-content .item"/> <element name="optionQty" type="text" selector=".filter-options-content .item .count"/> + <element name="filterByName" type="text" selector="//*[contains(text(), '{{arg}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php index fc93b86f5da5e..98dff9e6fbd56 100644 --- a/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php +++ b/app/code/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilter.php @@ -16,7 +16,6 @@ use Magento\Catalog\Model\Product; /** - * Class CustomAttributeFilter * Applies filters by custom attributes to base select */ class CustomAttributeFilter @@ -71,13 +70,13 @@ public function __construct( * Applies filters by custom attributes to base select * * @param Select $select - * @param FilterInterface[] ...$filters + * @param FilterInterface[] $filters * @return Select * @throws \Magento\Framework\Exception\LocalizedException * @throws \InvalidArgumentException * @throws \DomainException */ - public function apply(Select $select, FilterInterface ... $filters) + public function apply(Select $select, FilterInterface ...$filters) { $select = clone $select; $mainTableAlias = $this->extractTableAliasFromSelect($select); @@ -141,7 +140,6 @@ private function getJoinConditions($attrId, $mainTable, $joinTable) { return [ sprintf('`%s`.`entity_id` = `%s`.`entity_id`', $mainTable, $joinTable), - sprintf('`%s`.`source_id` = `%s`.`source_id`', $mainTable, $joinTable), $this->conditionManager->generateCondition( sprintf('%s.attribute_id', $joinTable), '=', diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml new file mode 100644 index 0000000000000..46e8edfd08b07 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml @@ -0,0 +1,67 @@ +<?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="AdminCreateConfigurableProductActionGroup"> + <arguments> + <argument name="product"/> + <argument name="category"/> + <argument name="attributeSet"/> + <argument name="configurableAttributeCode" defaultValue="color" type="string"/> + <argument name="configurationsPrice" defaultValue="0" type="string"/> + <argument name="configurationsQty" defaultValue="0" type="string"/> + </arguments> + + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickOnAddProductToggle"/> + <click selector="{{AdminProductGridActionSection.addConfigurableProduct}}" stepKey="clickOnAddConfigurableProduct"/> + <fillField userInput="{{product.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> + <fillField userInput="{{product.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> + <fillField userInput="{{product.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> + <fillField userInput="{{product.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[{{category}}]" stepKey="fillCategory"/> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + + <!--Apply Attribute Set for product--> + <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet}}" stepKey="searchForAttrSet"/> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(attributeSet)}}" stepKey="selectAttrSetProd"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveEditedProductForProduct"/> + + <!--Click "Create Configurations" button in configurations field--> + <conditionalClick selector="{{AdminProductFormConfigurationsSection.sectionHeader}}" dependentSelector="{{AdminProductFormConfigurationsSection.createConfigurations}}" visible="false" stepKey="openConfigurationSection"/> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="openConfigurationPanel"/> + + <!--Select attribute "Color"--> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="clickFiltersExpand"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('attribute_code')}}" userInput="{{configurableAttributeCode}}" stepKey="fillFilter"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickSearch"/> + <click selector="{{AdminCreateProductConfigurationsPanel.firstCheckbox}}" stepKey="clickAttributeColorCheckbox"/> + + <!--Click the "Next" button--> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickNextButton"/> + + <!--Select All--> + <click selector="{{AdminCreateProductConfigurationsPanel.selectAll}}" stepKey="clickOnSelectAllSecond"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextButtonSecond"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applySinglePriceToAllSkus}}" stepKey="clickOnApplySinglePriceToEachSkuSecond"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.singlePrice}}" userInput="{{configurationsPrice}}" stepKey="enterAttributePriceSecond"/> + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSkuSecond"/> + <fillField selector="{{AdminCreateProductConfigurationsPanel.quantity}}" userInput="{{configurationsQty}}" stepKey="enterAttributeQuantitySecond"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickOnNextStepSecond"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="generateSecondProducts"/> + + <!-- Save the product --> + <click selector="{{AdminProductFormActionSection.saveArrow}}" stepKey="openSaveDropDown"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickOnSave"/> + <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="You saved the product." stepKey="assertSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductWithExcludingOptionsActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductWithExcludingOptionsActionGroup.xml new file mode 100644 index 0000000000000..c4485ab5f5c9b --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductWithExcludingOptionsActionGroup.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="AdminCreateConfigurableProductExcludeOptionActionGroup" extends="AdminCreateConfigurableProductActionGroup"> + <arguments> + <!-- custom multiselect attribute option name to start --> + <argument name="customAttributeOptionNameFrom" type="string"/> + <!-- custom multiselect attribute option name to end --> + <argument name="customAttributeOptionNameTill" type="string"/> + <argument name="excludedOption"/> + </arguments> + + <selectOption userInput="{{customAttributeOptionNameFrom}}" selector="{{AdminNewAttributePanelSection.attributeSelect(ProductAttributeFrontendLabel.label)}}" after="saveEditedProductForProduct" stepKey="selectAttribute"/> + <dragAndDrop selector1="{{AdminNewAttributePanelSection.attributeName(customAttributeOptionNameFrom)}}" selector2="{{AdminNewAttributePanelSection.attributeName(customAttributeOptionNameTill)}}" after="selectAttribute" stepKey="selectOptions"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.attributeByName(excludedOption.name)}}" after="clickOnSelectAllSecond" stepKey="deselectOption"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminNewAttributePanelSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminNewAttributePanelSection.xml index 86e22554d95f0..429d535952f76 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminNewAttributePanelSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/AdminNewAttributePanelSection.xml @@ -19,5 +19,7 @@ <element name="optionAdminValue" type="input" selector="[data-role='options-container'] input[name='option[value][option_{{row}}][0]']" parameterized="true"/> <element name="optionDefaultStoreValue" type="input" selector="[data-role='options-container'] input[name='option[value][option_{{row}}][1]']" parameterized="true"/> <element name="deleteOption" type="button" selector="#delete_button_option_{{row}}" parameterized="true"/> + <element name="attributeSelect" type="select" selector="product[{{var}}]" parameterized="true"/> + <element name="attributeName" type="select" selector="//option[text()='{{var}}']" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml new file mode 100644 index 0000000000000..b29701bd11b97 --- /dev/null +++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml @@ -0,0 +1,235 @@ +<?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="StorefrontCheckingResultsOfFiltersTest"> + <annotations> + <features value="LayerNavigation"/> + <group value="layernavigation"/> + <stories value="MAGETWO-85162: Results of filters with color and other filters are not showing product results"/> + <title value="Checking results of filters: color and other filters"/> + <description value="Checking results of filters: color and other filters"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-96032"/> + </annotations> + <before> + <actionGroup ref="LoginActionGroup" stepKey="login"/> + <createData entity="ApiCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <!--Delete attribute color options--> + <actionGroup ref="navigateToProductAttributeByCode" stepKey="navigateToProductAttributeByNameColor"> + <argument name="attributeCode" value="color"/> + </actionGroup> + + <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('Red')}}" stepKey="deleteOption1"/> + <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('Green')}}" stepKey="deleteOption2"/> + <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('Blue')}}" stepKey="deleteOption3"/> + <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('White')}}" stepKey="deleteOption4"/> + <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('Black')}}" stepKey="deleteOption5"/> + + <!--Save attribute--> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveColorAttribute"/> + + <!--Delete Category--> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + + <!-- Delete all created products (including virtual) --> + <actionGroup ref="DeleteAllProductsOnProductsGridPageFilteredByName" stepKey="deleteAllCreatedProducts"> + <argument name="product" value="_defaultProduct"/> + </actionGroup> + + <!-- Delete created product attribute --> + <actionGroup ref="DeleteProductAttribute" stepKey="deleteCreatedProductAttribute"> + <argument name="productAttribute" value="ProductAttributeFrontendLabel"/> + </actionGroup> + + <!-- Delete the new attribute set --> + <actionGroup ref="DeleteAttributeSetActionGroup" stepKey="deleteAttributeSet"> + <argument name="name" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Go to the edit page for the "color" attribute--> + <actionGroup ref="navigateToProductAttributeByCode" stepKey="navigateToProductAttributeByName"> + <argument name="attributeCode" value="color"/> + </actionGroup> + + <!--Add option 1 to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption1"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('1')}}" time="30" stepKey="waitForOptionRow1"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('0')}}" userInput="{{colorProductAttribute1.name}}" stepKey="fillAdminLabel1"/> + <!--Add option 2 to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption2"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('2')}}" time="30" stepKey="waitForOptionRow2"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('1')}}" userInput="{{colorProductAttribute2.name}}" stepKey="fillAdminLabel2"/> + <!--Add option 3 to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption3"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('3')}}" time="30" stepKey="waitForOptionRow3"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('2')}}" userInput="{{colorProductAttribute3.name}}" stepKey="fillAdminLabel3"/> + <!--Add option 4 to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption4"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('4')}}" time="30" stepKey="waitForOptionRow4"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('3')}}" userInput="{{ColorProductAttribute4.name}}" stepKey="fillAdminLabel4"/> + <!--Add option 5 to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption5"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('5')}}" time="30" stepKey="waitForOptionRow5"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('4')}}" userInput="{{ColorProductAttribute5.name}}" stepKey="fillAdminLabel5"/> + <!--Save attribute--> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveAttribute"/> + + <!--Create 'material' attribute:--> + <amOnPage url="{{ProductAttributePage.url}}" stepKey="goToNewProductAttributePage"/> + <fillField selector="{{AttributePropertiesSection.defaultLabel}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="fillDefaultLabel"/> + <selectOption selector="{{AttributePropertiesSection.inputType}}" userInput="multiselect" stepKey="selectInputType"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="waitForElementVisible"/> + + <!--Add 'cotton' option to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption6"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('1')}}" time="30" stepKey="waitForOptionRow6"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('0')}}" userInput="cotton" stepKey="fillAdminLabel6"/> + <!--Add 'fabric' option to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption7"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('2')}}" time="30" stepKey="waitForOptionRow7"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('1')}}" userInput="fabric" stepKey="fillAdminLabel7"/> + <!--Add 'jeans' option to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption8"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('3')}}" time="30" stepKey="waitForOptionRow8"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('2')}}" userInput="jeans" stepKey="fillAdminLabel8"/> + <!--Add 'synthetic' option to attribute--> + <click selector="{{AdminNewAttributePanelSection.addOption}}" stepKey="clickAddOption9"/> + <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('4')}}" time="30" stepKey="waitForOptionRow9"/> + <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('3')}}" userInput="synthetic" stepKey="fillAdminLabel9"/> + + <!-- Set scope --> + <click selector="{{AttributePropertiesSection.AdvancedProperties}}" stepKey="expandAdvancedProperties"/> + <selectOption selector="{{AttributePropertiesSection.scope}}" userInput="1" stepKey="selectGlobalScope"/> + + <!-- Set Use In Layered Navigation --> + <scrollToTopOfPage stepKey="scrollToTop1"/> + <click selector="{{StorefrontPropertiesSection.storefrontPropertiesTab}}" stepKey="goToStorefrontProperties"/> + <selectOption selector="{{AttributePropertiesSection.useInLayeredNavigation}}" userInput="1" stepKey="selectUseInLayeredNavigation"/> + + <!--Save attribute--> + <click selector="{{AdminNewAttributePanel.saveAttribute}}" stepKey="clickSaveNewAttribute"/> + <waitForPageLoad stepKey="waitForSavingNewAttribute"/> + <see userInput="You saved the product attribute." stepKey="seeSuccessMessage"/> + <click selector="{{AdminUserGridSection.resetButton}}" stepKey="clickResetButton"/> + + <!--Create attribute set--> + <actionGroup ref="CreateAttributeSet" stepKey="attribute"> + <argument name="attributeSetName" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + + <!-- Assign attribute to a group --> + <actionGroup ref="AssignAttributeToGroup" stepKey="assignAttributeToGroupColor"> + <argument name="group" value="Product Details"/> + <argument name="attribute" value="ColorAttributeFrontandLabel.label"/> + </actionGroup> + + <actionGroup ref="AssignAttributeToGroup" stepKey="assignAttributeToGroup"> + <argument name="group" value="Product Details"/> + <argument name="attribute" value="ProductAttributeFrontendLabel.label"/> + </actionGroup> + + <!-- Save attribute set --> + <actionGroup ref="SaveAttributeSet" stepKey="SaveAttributeSet"/> + + <!--Create First Configurable product--> + <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct1"> + <argument name="product" value="_defaultProduct"/> + <argument name="category" value="$$createCategory.name$$"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="customAttributeOptionNameFrom" value="cotton"/> + <argument name="customAttributeOptionNameTill" value="synthetic"/> + <argument name="excludedOption" value="ColorProductAttribute5"/> + <argument name="configurableAttributeCode" value="color"/> + <argument name="configurationsPrice" value="34"/> + <argument name="configurationsQty" value="100"/> + </actionGroup> + + <!--Create Second Configurable product--> + <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct2"> + <argument name="product" value="SimpleProduct2"/> + <argument name="category" value="$$createCategory.name$$"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="customAttributeOptionNameFrom" value="cotton"/> + <argument name="customAttributeOptionNameTill" value="jeans"/> + <argument name="excludedOption" value="ColorProductAttribute5"/> + <argument name="configurableAttributeCode" value="color"/> + <argument name="configurationsPrice" value="43"/> + <argument name="configurationsQty" value="1111"/> + </actionGroup> + + <!--Edit Third Configurable product--> + <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct3"> + <argument name="product" value="SimpleProduct3"/> + <argument name="category" value="$$createCategory.name$$"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="customAttributeOptionNameFrom" value="fabric"/> + <argument name="customAttributeOptionNameTill" value="synthetic"/> + <argument name="excludedOption" value="ColorProductAttribute5"/> + <argument name="configurableAttributeCode" value="color"/> + <argument name="configurationsPrice" value="55"/> + <argument name="configurationsQty" value="222"/> + </actionGroup> + + <!--Open Simple Product--> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + + <!--Apply Attribute Set for product--> + <actionGroup ref="AssignProductToAttributeSet" stepKey="assignProductToAttributeSet4"> + <argument name="attributeSetName" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(ProductAttributeFrontendLabel.label)}}" stepKey="selectAttrSetProdSimple"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveEditedProductForProductSimple"/> + <waitForPageLoad stepKey="waitForFirstProductSavedSimple"/> + <selectOption userInput="cotton" selector="{{AdminNewAttributePanelSection.attributeSelect(ProductAttributeFrontendLabel.label)}}" stepKey="selectMaterialSimple"/> + <dragAndDrop selector1="{{AdminNewAttributePanelSection.attributeName('cotton')}}" selector2="{{AdminNewAttributePanelSection.attributeName('fabric')}}" stepKey="selectMaterialsSimple"/> + + <!-- Save the product --> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveSimpleProduct"/> + <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="You saved the product." stepKey="assertSuccessSimpleProduct"/> + + <!--Clear caches--> + <magentoCLI command="cache:flush" stepKey="flushCache"/> + + <!--Open a category on storefront--> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage"/> + + <!--Choose COLOR filter - green. Make sure that Products with green color are shown.--> + <click selector="{{StorefrontCategorySidebarSection.filterOptionsTitle('Color')}}" stepKey="expandAttribute"/> + <click selector="{{StorefrontCategorySidebarSection.filterByName(ColorProductAttribute4.name)}}" stepKey="clickGreenToFilter"/> + <waitForLoadingMaskToDisappear stepKey="waitForFiltering"/> + <see userInput="{{_defaultProduct.name}}" stepKey="seeFirstProduct"/> + <see userInput="{{SimpleProduct2.name}}" stepKey="seeSecondProduct"/> + <see userInput="{{SimpleProduct3.name}}" stepKey="seeThirdProduct"/> + <dontSee userInput="$$createSimpleProduct.name$$" stepKey="dontSeeSimpleProduct"/> + + <!--Add cotton filter. Make sure Products are shown and filtered correctly. Only product2 and product3 are shown--> + <click selector="{{StorefrontCategorySidebarSection.filterOptionsTitle(ProductAttributeFrontendLabel.label)}}" stepKey="expandCreatedAttribute"/> + <waitForElementVisible selector="{{StorefrontCategorySidebarSection.filterByName('cotton')}}" stepKey="waitForAttributeElementVisible"/> + <click selector="{{StorefrontCategorySidebarSection.filterByName('cotton')}}" stepKey="filterByCotton"/> + <waitForLoadingMaskToDisappear stepKey="waitForFilteringByCotton"/> + <see userInput="{{_defaultProduct.name}}" stepKey="seeFirstProductCotton"/> + <see userInput="{{SimpleProduct2.name}}" stepKey="seeSecondProductCotton"/> + <dontSee userInput="{{SimpleProduct3.name}}" stepKey="dontSeeThirdProductCotton"/> + <dontSee userInput="$$createSimpleProduct.name$$" stepKey="dontSeeSimpleProductCotton"/> + </test> +</tests> diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php index 7d0f9148cd708..d92539396de58 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Search/FilterMapper/CustomAttributeFilterTest.php @@ -155,7 +155,6 @@ private function getSqlForOneAttributeSearch() $joinConditions = [ '`some_index`.`entity_id` = `field1_filter`.`entity_id`', - '`some_index`.`source_id` = `field1_filter`.`source_id`', sprintf('`field1_filter`.`attribute_id` = %s', $firstAttribute->getId()), sprintf('`field1_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) ]; @@ -182,14 +181,12 @@ private function getSqlForTwoAttributeSearch() $joinConditions1 = [ '`some_index`.`entity_id` = `field1_filter`.`entity_id`', - '`some_index`.`source_id` = `field1_filter`.`source_id`', sprintf('`field1_filter`.`attribute_id` = %s', $firstAttribute->getId()), sprintf('`field1_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) ]; $joinConditions2 = [ '`some_index`.`entity_id` = `field2_filter`.`entity_id`', - '`some_index`.`source_id` = `field2_filter`.`source_id`', sprintf('`field2_filter`.`attribute_id` = %s', $secondAttribute->getId()), sprintf('`field2_filter`.`store_id` = %s', (int) $this->storeManager->getStore()->getId()) ]; From b1f6590d77a26adba45dcdb04961d25150f745e6 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Wed, 7 Nov 2018 11:05:46 +0200 Subject: [PATCH 25/49] MAGETWO-73061: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 --- app/code/Magento/Sales/Model/Order/ProductOption.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/ProductOption.php b/app/code/Magento/Sales/Model/Order/ProductOption.php index dc9ec42e27e60..b5b365e498e65 100644 --- a/app/code/Magento/Sales/Model/Order/ProductOption.php +++ b/app/code/Magento/Sales/Model/Order/ProductOption.php @@ -54,8 +54,9 @@ public function __construct( * Adds product option to the order item. * * @param OrderItemInterface $orderItem + * @return void */ - public function add(OrderItemInterface $orderItem): void + public function add(OrderItemInterface $orderItem) { /** @var DataObject $request */ $request = $orderItem->getBuyRequest(); @@ -83,8 +84,9 @@ public function add(OrderItemInterface $orderItem): void * * @param OrderItemInterface $orderItem * @param array $data + * @return void */ - private function setProductOption(OrderItemInterface $orderItem, array $data): void + private function setProductOption(OrderItemInterface $orderItem, array $data) { $productOption = $orderItem->getProductOption(); if (!$productOption) { From d1d035cc98fb42ce594b8a7116590106ee1618fd Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Wed, 7 Nov 2018 13:31:23 +0200 Subject: [PATCH 26/49] MAGETWO-85162: Results of filters with color and other filters are not showing product results --- .../AdminCreateConfigurableProductActionGroup.xml | 6 +++--- .../Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml index 46e8edfd08b07..a01a9e14b97b6 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateConfigurableProductActionGroup.xml @@ -11,7 +11,7 @@ <actionGroup name="AdminCreateConfigurableProductActionGroup"> <arguments> <argument name="product"/> - <argument name="category"/> + <argument name="category" type="string"/> <argument name="attributeSet"/> <argument name="configurableAttributeCode" defaultValue="color" type="string"/> <argument name="configurationsPrice" defaultValue="0" type="string"/> @@ -30,9 +30,9 @@ <!--Apply Attribute Set for product--> <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet}}" stepKey="searchForAttrSet"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet.label}}" stepKey="searchForAttrSet"/> <waitForAjaxLoad stepKey="waitForLoad"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(attributeSet)}}" stepKey="selectAttrSetProd"/> + <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(attributeSet.label)}}" stepKey="selectAttrSetProd"/> <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveEditedProductForProduct"/> <!--Click "Create Configurations" button in configurations field--> diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml index b29701bd11b97..1d4a861ffe7b8 100644 --- a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml +++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml @@ -150,7 +150,7 @@ <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct1"> <argument name="product" value="_defaultProduct"/> <argument name="category" value="$$createCategory.name$$"/> - <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel"/> <argument name="customAttributeOptionNameFrom" value="cotton"/> <argument name="customAttributeOptionNameTill" value="synthetic"/> <argument name="excludedOption" value="ColorProductAttribute5"/> @@ -163,7 +163,7 @@ <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct2"> <argument name="product" value="SimpleProduct2"/> <argument name="category" value="$$createCategory.name$$"/> - <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel"/> <argument name="customAttributeOptionNameFrom" value="cotton"/> <argument name="customAttributeOptionNameTill" value="jeans"/> <argument name="excludedOption" value="ColorProductAttribute5"/> @@ -176,7 +176,7 @@ <actionGroup ref="AdminCreateConfigurableProductExcludeOptionActionGroup" stepKey="createConfigurableProduct3"> <argument name="product" value="SimpleProduct3"/> <argument name="category" value="$$createCategory.name$$"/> - <argument name="attributeSet" value="ProductAttributeFrontendLabel.label"/> + <argument name="attributeSet" value="ProductAttributeFrontendLabel"/> <argument name="customAttributeOptionNameFrom" value="fabric"/> <argument name="customAttributeOptionNameTill" value="synthetic"/> <argument name="excludedOption" value="ColorProductAttribute5"/> From 77304d4f5c00868995679f15e90776872ce07d13 Mon Sep 17 00:00:00 2001 From: BlackEagle <ike.devolder@gmail.com> Date: Wed, 7 Nov 2018 15:21:44 +0100 Subject: [PATCH 27/49] fix cipherMethod detection for openssl 1.1.1 if openssl is updated to 1.1.1, openssl_get_cipher_methods returns all ciphers lowercase. Before you would get mixed uppercase and lowercase ciphers. You can still use uppercase or lowercase to use openssl. To avoid "Not valid cipher method." we must search if the cipherMethod exist in uppercase or lowercase before failing. output of openssl_get_cipher_methods with openssl 1.1.0f: ``` php -r 'print_r(openssl_get_cipher_methods());' Array ( [0] => AES-128-CBC [1] => AES-128-CBC-HMAC-SHA1 [2] => AES-128-CBC-HMAC-SHA256 [3] => AES-128-CFB [4] => AES-128-CFB1 [5] => AES-128-CFB8 [6] => AES-128-CTR [7] => AES-128-ECB [8] => AES-128-OCB [9] => AES-128-OFB [10] => AES-128-XTS [11] => AES-192-CBC [12] => AES-192-CFB [13] => AES-192-CFB1 [14] => AES-192-CFB8 [15] => AES-192-CTR [16] => AES-192-ECB [17] => AES-192-OCB [18] => AES-192-OFB [19] => AES-256-CBC [20] => AES-256-CBC-HMAC-SHA1 [21] => AES-256-CBC-HMAC-SHA256 [22] => AES-256-CFB [23] => AES-256-CFB1 [24] => AES-256-CFB8 [25] => AES-256-CTR [26] => AES-256-ECB [27] => AES-256-OCB [28] => AES-256-OFB [29] => AES-256-XTS [30] => BF-CBC [31] => BF-CFB [32] => BF-ECB [33] => BF-OFB [34] => CAMELLIA-128-CBC [35] => CAMELLIA-128-CFB [36] => CAMELLIA-128-CFB1 [37] => CAMELLIA-128-CFB8 [38] => CAMELLIA-128-CTR [39] => CAMELLIA-128-ECB [40] => CAMELLIA-128-OFB [41] => CAMELLIA-192-CBC [42] => CAMELLIA-192-CFB [43] => CAMELLIA-192-CFB1 [44] => CAMELLIA-192-CFB8 [45] => CAMELLIA-192-CTR [46] => CAMELLIA-192-ECB [47] => CAMELLIA-192-OFB [48] => CAMELLIA-256-CBC [49] => CAMELLIA-256-CFB [50] => CAMELLIA-256-CFB1 [51] => CAMELLIA-256-CFB8 [52] => CAMELLIA-256-CTR [53] => CAMELLIA-256-ECB [54] => CAMELLIA-256-OFB [55] => CAST5-CBC [56] => CAST5-CFB [57] => CAST5-ECB [58] => CAST5-OFB [59] => ChaCha20 [60] => ChaCha20-Poly1305 [61] => DES-CBC [62] => DES-CFB [63] => DES-CFB1 [64] => DES-CFB8 [65] => DES-ECB [66] => DES-EDE [67] => DES-EDE-CBC [68] => DES-EDE-CFB [69] => DES-EDE-OFB [70] => DES-EDE3 [71] => DES-EDE3-CBC [72] => DES-EDE3-CFB [73] => DES-EDE3-CFB1 [74] => DES-EDE3-CFB8 [75] => DES-EDE3-OFB [76] => DES-OFB [77] => DESX-CBC [78] => RC2-40-CBC [79] => RC2-64-CBC [80] => RC2-CBC [81] => RC2-CFB [82] => RC2-ECB [83] => RC2-OFB [84] => RC4 [85] => RC4-40 [86] => RC4-HMAC-MD5 [87] => SEED-CBC [88] => SEED-CFB [89] => SEED-ECB [90] => SEED-OFB [91] => aes-128-cbc [92] => aes-128-cbc-hmac-sha1 [93] => aes-128-cbc-hmac-sha256 [94] => aes-128-ccm [95] => aes-128-cfb [96] => aes-128-cfb1 [97] => aes-128-cfb8 [98] => aes-128-ctr [99] => aes-128-ecb [100] => aes-128-gcm [101] => aes-128-ocb [102] => aes-128-ofb [103] => aes-128-xts [104] => aes-192-cbc [105] => aes-192-ccm [106] => aes-192-cfb [107] => aes-192-cfb1 [108] => aes-192-cfb8 [109] => aes-192-ctr [110] => aes-192-ecb [111] => aes-192-gcm [112] => aes-192-ocb [113] => aes-192-ofb [114] => aes-256-cbc [115] => aes-256-cbc-hmac-sha1 [116] => aes-256-cbc-hmac-sha256 [117] => aes-256-ccm [118] => aes-256-cfb [119] => aes-256-cfb1 [120] => aes-256-cfb8 [121] => aes-256-ctr [122] => aes-256-ecb [123] => aes-256-gcm [124] => aes-256-ocb [125] => aes-256-ofb [126] => aes-256-xts [127] => bf-cbc [128] => bf-cfb [129] => bf-ecb [130] => bf-ofb [131] => camellia-128-cbc [132] => camellia-128-cfb [133] => camellia-128-cfb1 [134] => camellia-128-cfb8 [135] => camellia-128-ctr [136] => camellia-128-ecb [137] => camellia-128-ofb [138] => camellia-192-cbc [139] => camellia-192-cfb [140] => camellia-192-cfb1 [141] => camellia-192-cfb8 [142] => camellia-192-ctr [143] => camellia-192-ecb [144] => camellia-192-ofb [145] => camellia-256-cbc [146] => camellia-256-cfb [147] => camellia-256-cfb1 [148] => camellia-256-cfb8 [149] => camellia-256-ctr [150] => camellia-256-ecb [151] => camellia-256-ofb [152] => cast5-cbc [153] => cast5-cfb [154] => cast5-ecb [155] => cast5-ofb [156] => chacha20 [157] => chacha20-poly1305 [158] => des-cbc [159] => des-cfb [160] => des-cfb1 [161] => des-cfb8 [162] => des-ecb [163] => des-ede [164] => des-ede-cbc [165] => des-ede-cfb [166] => des-ede-ofb [167] => des-ede3 [168] => des-ede3-cbc [169] => des-ede3-cfb [170] => des-ede3-cfb1 [171] => des-ede3-cfb8 [172] => des-ede3-ofb [173] => des-ofb [174] => desx-cbc [175] => id-aes128-CCM [176] => id-aes128-GCM [177] => id-aes128-wrap [178] => id-aes128-wrap-pad [179] => id-aes192-CCM [180] => id-aes192-GCM [181] => id-aes192-wrap [182] => id-aes192-wrap-pad [183] => id-aes256-CCM [184] => id-aes256-GCM [185] => id-aes256-wrap [186] => id-aes256-wrap-pad [187] => id-smime-alg-CMS3DESwrap [188] => rc2-40-cbc [189] => rc2-64-cbc [190] => rc2-cbc [191] => rc2-cfb [192] => rc2-ecb [193] => rc2-ofb [194] => rc4 [195] => rc4-40 [196] => rc4-hmac-md5 [197] => seed-cbc [198] => seed-cfb [199] => seed-ecb [200] => seed-ofb ) ``` that output is missing the uppercase versions using openssl 1.1.1: ``` php -r 'print_r(openssl_get_cipher_methods());' Array ( [0] => aes-128-cbc [1] => aes-128-cbc-hmac-sha1 [2] => aes-128-cbc-hmac-sha256 [3] => aes-128-ccm [4] => aes-128-cfb [5] => aes-128-cfb1 [6] => aes-128-cfb8 [7] => aes-128-ctr [8] => aes-128-ecb [9] => aes-128-gcm [10] => aes-128-ocb [11] => aes-128-ofb [12] => aes-128-xts [13] => aes-192-cbc [14] => aes-192-ccm [15] => aes-192-cfb [16] => aes-192-cfb1 [17] => aes-192-cfb8 [18] => aes-192-ctr [19] => aes-192-ecb [20] => aes-192-gcm [21] => aes-192-ocb [22] => aes-192-ofb [23] => aes-256-cbc [24] => aes-256-cbc-hmac-sha1 [25] => aes-256-cbc-hmac-sha256 [26] => aes-256-ccm [27] => aes-256-cfb [28] => aes-256-cfb1 [29] => aes-256-cfb8 [30] => aes-256-ctr [31] => aes-256-ecb [32] => aes-256-gcm [33] => aes-256-ocb [34] => aes-256-ofb [35] => aes-256-xts [36] => aria-128-cbc [37] => aria-128-ccm [38] => aria-128-cfb [39] => aria-128-cfb1 [40] => aria-128-cfb8 [41] => aria-128-ctr [42] => aria-128-ecb [43] => aria-128-gcm [44] => aria-128-ofb [45] => aria-192-cbc [46] => aria-192-ccm [47] => aria-192-cfb [48] => aria-192-cfb1 [49] => aria-192-cfb8 [50] => aria-192-ctr [51] => aria-192-ecb [52] => aria-192-gcm [53] => aria-192-ofb [54] => aria-256-cbc [55] => aria-256-ccm [56] => aria-256-cfb [57] => aria-256-cfb1 [58] => aria-256-cfb8 [59] => aria-256-ctr [60] => aria-256-ecb [61] => aria-256-gcm [62] => aria-256-ofb [63] => bf-cbc [64] => bf-cfb [65] => bf-ecb [66] => bf-ofb [67] => camellia-128-cbc [68] => camellia-128-cfb [69] => camellia-128-cfb1 [70] => camellia-128-cfb8 [71] => camellia-128-ctr [72] => camellia-128-ecb [73] => camellia-128-ofb [74] => camellia-192-cbc [75] => camellia-192-cfb [76] => camellia-192-cfb1 [77] => camellia-192-cfb8 [78] => camellia-192-ctr [79] => camellia-192-ecb [80] => camellia-192-ofb [81] => camellia-256-cbc [82] => camellia-256-cfb [83] => camellia-256-cfb1 [84] => camellia-256-cfb8 [85] => camellia-256-ctr [86] => camellia-256-ecb [87] => camellia-256-ofb [88] => cast5-cbc [89] => cast5-cfb [90] => cast5-ecb [91] => cast5-ofb [92] => chacha20 [93] => chacha20-poly1305 [94] => des-cbc [95] => des-cfb [96] => des-cfb1 [97] => des-cfb8 [98] => des-ecb [99] => des-ede [100] => des-ede-cbc [101] => des-ede-cfb [102] => des-ede-ofb [103] => des-ede3 [104] => des-ede3-cbc [105] => des-ede3-cfb [106] => des-ede3-cfb1 [107] => des-ede3-cfb8 [108] => des-ede3-ofb [109] => des-ofb [110] => desx-cbc [111] => id-aes128-CCM [112] => id-aes128-GCM [113] => id-aes128-wrap [114] => id-aes128-wrap-pad [115] => id-aes192-CCM [116] => id-aes192-GCM [117] => id-aes192-wrap [118] => id-aes192-wrap-pad [119] => id-aes256-CCM [120] => id-aes256-GCM [121] => id-aes256-wrap [122] => id-aes256-wrap-pad [123] => id-smime-alg-CMS3DESwrap [124] => rc2-40-cbc [125] => rc2-64-cbc [126] => rc2-cbc [127] => rc2-cfb [128] => rc2-ecb [129] => rc2-ofb [130] => rc4 [131] => rc4-40 [132] => rc4-hmac-md5 [133] => seed-cbc [134] => seed-cfb [135] => seed-ecb [136] => seed-ofb [137] => sm4-cbc [138] => sm4-cfb [139] => sm4-ctr [140] => sm4-ecb [141] => sm4-ofb ) ``` So checking if uppercase or lowercase exists in the array fixes the issue with openssl 1.1.1 where the uppercase 'AES-256-CBC' is not found. You could also fix this by changing the $cipherMethod to 'aes-256-cbc', but you never know if openssl will change the output case again. The issue appears when just running the unittests on php with openssl 1.1.1, with the previous version of openssl (1.1.0f) the issue is not yet present. Test: ``` $ openssl version OpenSSL 1.1.1 11 Sep 2018 $ php -d memory_limit=2048M vendor/bin/phpunit --configuration dev/tests/unit/phpunit.xml.dist PHPUnit 6.5.13 by Sebastian Bergmann and contributors. ..................................................................................... 85 / 21418 ( 0%) ..................................................................................... 170 / 21418 ( 0%) ..............EE...F................................................................. 255 / 21418 ( 1%) ..................................................................................... 340 / 21418 ( 1%) ... There were 2 errors: 1) Magento\Analytics\Test\Unit\Model\CryptographerTest::testEncode Magento\Framework\Exception\LocalizedException: The data is invalid. Use a valid cipher method and try again. /phpapp/app/code/Magento/Analytics/Model/Cryptographer.php:70 /phpapp/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php:134 2) Magento\Analytics\Test\Unit\Model\CryptographerTest::testEncodeUniqueInitializationVector Magento\Framework\Exception\LocalizedException: The data is invalid. Use a valid cipher method and try again. /phpapp/app/code/Magento/Analytics/Model/Cryptographer.php:70 /phpapp/app/code/Magento/Analytics/Test/Unit/Model/CryptographerTest.php:167 ... ``` Signed-off-by: BlackEagle <ike.devolder@gmail.com> --- app/code/Magento/Analytics/Model/Cryptographer.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Analytics/Model/Cryptographer.php b/app/code/Magento/Analytics/Model/Cryptographer.php index 6905eee372ae2..7659d44801091 100644 --- a/app/code/Magento/Analytics/Model/Cryptographer.php +++ b/app/code/Magento/Analytics/Model/Cryptographer.php @@ -124,7 +124,12 @@ private function getInitializationVector() */ private function validateCipherMethod($cipherMethod) { - $methods = openssl_get_cipher_methods(); + $methods = array_map( + 'strtolower', + openssl_get_cipher_methods() + ); + $cipherMethod = strtolower($cipherMethod); + return (false !== array_search($cipherMethod, $methods)); } } From 7aa7ce06bf3e9471dc6c0dced8ad1adfaffc7d7c Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Thu, 8 Nov 2018 12:05:16 +0200 Subject: [PATCH 28/49] MAGETWO-73061: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 --- app/code/Magento/Sales/Model/Order/ItemRepository.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/ItemRepository.php b/app/code/Magento/Sales/Model/Order/ItemRepository.php index fd6836d3f286e..6d03f31c76380 100644 --- a/app/code/Magento/Sales/Model/Order/ItemRepository.php +++ b/app/code/Magento/Sales/Model/Order/ItemRepository.php @@ -165,7 +165,9 @@ public function save(OrderItemInterface $entity) { if ($entity->getProductOption()) { $request = $this->getBuyRequest($entity); - $entity->setProductOptions(['info_buyRequest' => $request->toArray()]); + $productOptions = $entity->getProductOptions(); + $productOptions['info_buyRequest'] = $request->toArray(); + $entity->setProductOptions($productOptions); } $this->metadata->getMapper()->save($entity); From 0c36fc7a2d81d6a5ef65e547e5acf3520945aca2 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 8 Nov 2018 13:38:52 +0200 Subject: [PATCH 29/49] MAGETWO-96074: Incorrect product displaying on storefront in IE11 --- .../Magento/blank/Magento_Theme/web/css/source/_module.less | 5 ----- .../Magento/luma/Magento_Theme/web/css/source/_module.less | 5 ----- 2 files changed, 10 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less index 3ef4d3224f7d5..b314bcf5b3473 100644 --- a/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/blank/Magento_Theme/web/css/source/_module.less @@ -296,11 +296,6 @@ box-sizing: border-box; width: 100%; } - - .ie10 &, - .ie11 & { - height: 100%; - } } .navigation ul { diff --git a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less index dee6f8e09fc76..68938ed206038 100644 --- a/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less +++ b/app/design/frontend/Magento/luma/Magento_Theme/web/css/source/_module.less @@ -639,11 +639,6 @@ box-sizing: border-box; width: 100%; } - - .ie10 &, - .ie11 & { - height: 100%; - } } .page-footer { From 00932fc16985b02100e165e60aa868eafee12999 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Fri, 9 Nov 2018 08:29:37 +0200 Subject: [PATCH 30/49] MAGETWO-96236: [SO-3036] Bug with stock status in price indexer --- .../Model/Indexer/ProductPriceIndexFilter.php | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php index 8757dba0873f0..b7fade5205287 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -9,11 +9,11 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\CatalogInventory\Model\ResourceModel\Stock\Item; -use Magento\CatalogInventory\Model\Stock; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\PriceModifierInterface; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure; use Magento\Framework\App\ResourceConnection; use Magento\Framework\App\ObjectManager; +use Magento\Framework\DB\Query\Generator; /** * Class for filter product price index. @@ -40,22 +40,38 @@ class ProductPriceIndexFilter implements PriceModifierInterface */ private $connectionName; + /** + * @var Generator + */ + private $batchQueryGenerator; + + /** + * @var int + */ + private $batchSize; + /** * @param StockConfigurationInterface $stockConfiguration * @param Item $stockItem * @param ResourceConnection $resourceConnection * @param string $connectionName + * @param Generator $batchQueryGenerator + * @param int $batchSize */ public function __construct( StockConfigurationInterface $stockConfiguration, Item $stockItem, ResourceConnection $resourceConnection = null, - $connectionName = 'indexer' + $connectionName = 'indexer', + Generator $batchQueryGenerator = null, + $batchSize = 100 ) { $this->stockConfiguration = $stockConfiguration; $this->stockItem = $stockItem; $this->resourceConnection = $resourceConnection ?: ObjectManager::getInstance()->get(ResourceConnection::class); $this->connectionName = $connectionName; + $this->batchQueryGenerator = $batchQueryGenerator ?: ObjectManager::getInstance()->get(Generator::class); + $this->batchSize = $batchSize; } /** @@ -66,6 +82,7 @@ public function __construct( * @return void * * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Zend_Db_Statement_Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) @@ -76,32 +93,39 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = $connection = $this->resourceConnection->getConnection($this->connectionName); $select = $connection->select(); + $select->from( - ['price_index' => $priceTable->getTableName()], - [] - ); - $select->joinInner( ['stock_item' => $this->stockItem->getMainTable()], - 'stock_item.product_id = price_index.' . $priceTable->getEntityField() - . ' AND stock_item.stock_id = ' . Stock::DEFAULT_STOCK_ID, - [] + ['*', 'MAX(stock_item.is_in_stock) as max_is_in_stock'] ); + if ($this->stockConfiguration->getManageStock()) { - $stockStatus = $connection->getCheckSql( - 'use_config_manage_stock = 0 AND manage_stock = 0', - Stock::STOCK_IN_STOCK, - 'is_in_stock' - ); + $select->where('stock_item.use_config_manage_stock = 1 OR stock_item.manage_stock = 1 '); } else { - $stockStatus = $connection->getCheckSql( - 'use_config_manage_stock = 0 AND manage_stock = 1', - 'is_in_stock', - Stock::STOCK_IN_STOCK - ); + $select->where('use_config_manage_stock = 0 AND manage_stock = 1 '); + } - $select->where($stockStatus . ' = ?', Stock::STOCK_OUT_OF_STOCK); - $query = $select->deleteFromSelect('price_index'); - $connection->query($query); + $select->group('stock_item.product_id'); + $select->having('max_is_in_stock = 0'); + + $batchSelectIterator = $this->batchQueryGenerator->generate( + 'product_id', + $select, + $this->batchSize, + \Magento\Framework\DB\Query\BatchIteratorInterface::UNIQUE_FIELD_ITERATOR + ); + + foreach ($batchSelectIterator as $select) { + $productIds = null; + foreach ($connection->query($select)->fetchAll() as $row) { + $productIds[] = $row['product_id']; + } + if ($productIds !== null) { + $where = [$priceTable->getEntityField() .' IN (?)' => $productIds]; + $connection->delete($priceTable->getTableName(), $where); + $productIds = null; + } + } } } From 910a976be34a1cd424815cd8ea5cfb2306688c17 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Fri, 9 Nov 2018 08:41:22 +0200 Subject: [PATCH 31/49] MAGETWO-96236: [SO-3036] Bug with stock status in price indexer --- .../CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php index b7fade5205287..022c7505187b3 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -103,7 +103,6 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = $select->where('stock_item.use_config_manage_stock = 1 OR stock_item.manage_stock = 1 '); } else { $select->where('use_config_manage_stock = 0 AND manage_stock = 1 '); - } $select->group('stock_item.product_id'); From 1af3db5d2d45b3f484149aa990a4604627e1b4c2 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Fri, 9 Nov 2018 09:01:35 +0200 Subject: [PATCH 32/49] MAGETWO-96236: [SO-3036] Bug with stock status in price indexer --- .../Model/Indexer/ProductPriceIndexFilter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php index 022c7505187b3..5bcc26388bc37 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -96,13 +96,13 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = $select->from( ['stock_item' => $this->stockItem->getMainTable()], - ['*', 'MAX(stock_item.is_in_stock) as max_is_in_stock'] + ['stock_item.product_id', 'MAX(stock_item.is_in_stock) as max_is_in_stock'] ); if ($this->stockConfiguration->getManageStock()) { - $select->where('stock_item.use_config_manage_stock = 1 OR stock_item.manage_stock = 1 '); + $select->where('stock_item.use_config_manage_stock = 1 OR stock_item.manage_stock = 1'); } else { - $select->where('use_config_manage_stock = 0 AND manage_stock = 1 '); + $select->where('stock_item.use_config_manage_stock = 0 AND stock_item.manage_stock = 1'); } $select->group('stock_item.product_id'); From 3ec427f8d9bbbd2fbc4ee5b7526acd6cdfd84ee4 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Fri, 9 Nov 2018 11:45:46 +0200 Subject: [PATCH 33/49] MAGETWO-73061: [GitHub] REST API Missing Product_Option values for Order Items in salesOrderManagementV1 and salesOrderItemRepositoryV1 #9326 --- .../Sales/Model/Order/ProductOption.php | 2 - .../Magento/Sales/_files/order_with_tax.php | 57 ------------------- .../Sales/_files/order_with_tax_rollback.php | 8 --- 3 files changed, 67 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php delete mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php diff --git a/app/code/Magento/Sales/Model/Order/ProductOption.php b/app/code/Magento/Sales/Model/Order/ProductOption.php index b5b365e498e65..da0bccd3d806b 100644 --- a/app/code/Magento/Sales/Model/Order/ProductOption.php +++ b/app/code/Magento/Sales/Model/Order/ProductOption.php @@ -15,8 +15,6 @@ /** * Adds product option to the order item according to product options processors pool. - * - * @api */ class ProductOption { diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php deleted file mode 100644 index 3612f4957a964..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -use Magento\Sales\Model\Order\Tax\ItemFactory; -use Magento\Store\Model\StoreManagerInterface; -use Magento\Tax\Model\Sales\Order\TaxFactory; -use Magento\Sales\Model\ResourceModel\Order\Item as OrderItemResource; -use Magento\Sales\Model\ResourceModel\Order\Tax\Item as OrderTaxItemResource; - -require 'default_rollback.php'; -require 'order.php'; - -$amount = 45; -$taxFactory = $objectManager->create(TaxFactory::class); - -/** @var \Magento\Tax\Model\Sales\Order\Tax $tax */ -$tax = $taxFactory->create(); -$tax->setOrderId($order->getId()) - ->setCode('US-NY-*-Rate 1') - ->setTitle('US-NY-*-Rate 1') - ->setPercent(8.37) - ->setAmount($amount) - ->setBaseAmount($amount) - ->setBaseRealAmount($amount); -$tax->save(); - -/** @var ItemFactory $salesOrderFactory */ -$salesOrderFactory = $objectManager->create(ItemFactory::class); - -/** @var \Magento\Sales\Model\Order\Tax\Item $salesOrderItem */ -$salesOrderItem = $salesOrderFactory->create(); -$salesOrderItem->setOrderId($order->getId()) - ->setStoreId($objectManager->get(StoreManagerInterface::class)->getStore()->getId()) - ->setProductOptions([]); -/** @var OrderItemResource $orderItemResource */ -$orderItemResource = $objectManager->create(OrderItemResource::class); -$orderItemResource->save($salesOrderItem); - -/** @var \Magento\Sales\Model\Order\Tax\Item $salesOrderTaxItem */ -$salesOrderTaxItem = $salesOrderFactory->create(); -$salesOrderTaxItem->setTaxId($tax->getId()) - ->setTaxPercent(8.37) - ->setTaxAmount($amount) - ->setBaseAmount($amount) - ->setRealAmount($amount) - ->setRealBaseAmount($amount) - ->setAppliedTaxes([$tax]) - ->setTaxableItemType('shipping') - ->setItemId($salesOrderItem->getId()); - -/** @var OrderTaxItemResource $orderTaxItemResource */ -$orderTaxItemResource = $objectManager->create(OrderTaxItemResource::class); -$orderTaxItemResource->save($salesOrderTaxItem); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php deleted file mode 100644 index dd52deab825cb..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/order_with_tax_rollback.php +++ /dev/null @@ -1,8 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -require 'order_rollback.php'; From 3750ccd3a814574916d0801482d7904e90b79ba3 Mon Sep 17 00:00:00 2001 From: "Lopukhov, Stanislav" <lopukhov@adobe.com> Date: Fri, 9 Nov 2018 15:55:09 +0200 Subject: [PATCH 34/49] MAGETWO-96236: [SO-3036] Bug with stock status in price indexer --- .../CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php index 5bcc26388bc37..96f943a6e3400 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -82,7 +82,6 @@ public function __construct( * @return void * * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Zend_Db_Statement_Exception * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = []) @@ -123,7 +122,6 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = if ($productIds !== null) { $where = [$priceTable->getEntityField() .' IN (?)' => $productIds]; $connection->delete($priceTable->getTableName(), $where); - $productIds = null; } } } From e08dd1d4766016fa203a28759a531e7b3a82df43 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Fri, 9 Nov 2018 19:25:18 +0200 Subject: [PATCH 35/49] MAGETWO-95759: Category tree display wrong number of product --- .../Model/ResourceModel/Category/Collection.php | 4 +--- ...eringCategoryProductsUsingScopeSelectorTest.xml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php index 6de2cf7788779..d9d0dde3e87c0 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php @@ -265,9 +265,7 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr 'main_table.category_id=e.entity_id', [] )->where( - 'e.entity_id = :entity_id' - )->orWhere( - 'e.path LIKE :c_path' + '(e.entity_id = :entity_id or e.path LIKE :c_path)' ); if ($websiteId) { $select->join( diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml index 2431d626387e3..539136515bd04 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml @@ -113,6 +113,10 @@ <click selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" stepKey="clickCategoryName"/> <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection"/> + <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" + stepKey="grabTextFromCategory"/> + <assertRegExp expected="/\(4\)/" expectedType="string" actual="$grabTextFromCategory" actualType="variable" + message="wrongCountProductOnAllStoreViews" stepKey="checkCountProducts"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct0.name$$)}}" userInput="$$createProduct0.name$$" stepKey="seeProductName"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct1.name$$)}}" @@ -133,6 +137,10 @@ stepKey="waitForPopup1"/> <click selector="{{AdminCategoryMainActionsSection.categoryStoreViewModalAccept}}" stepKey="clickActionAccept"/> <waitForPageLoad stepKey="waitForCategoryPageLoad2"/> + <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" + stepKey="grabTextFromCategory1"/> + <assertRegExp expected="/\(2\)/" expectedType="string" actual="$grabTextFromCategory1" actualType="variable" + message="wrongCountProductOnWebsite1" stepKey="checkCountProducts1"/> <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection1"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct1.name$$)}}" userInput="$$createProduct1.name$$" stepKey="seeProductName4"/> @@ -143,7 +151,7 @@ <dontSee selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct2.name$$)}}" userInput="$$createProduct2.name$$" stepKey="dontSeeProductName1"/> - <!-- Step 4: Set scope selector to Website2 ( StopreView for Website 2) --> + <!-- Step 4: Set scope selector to Website2 ( StoreView for Website 2) --> <scrollToTopOfPage stepKey="scrollToTopOfPage1"/> <click selector="{{AdminCategoryMainActionsSection.categoryStoreViewDropdownToggle}}" stepKey="clickStoresList1"/> @@ -156,6 +164,10 @@ stepKey="clickActionAccept1"/> <waitForPageLoad stepKey="waitForCategoryPageLoad4"/> <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection2"/> + <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" + stepKey="grabTextFromCategory2"/> + <assertRegExp expected="/\(2\)/" expectedType="string" actual="$grabTextFromCategory2" actualType="variable" + message="wrongCountProductOnWebsite2" stepKey="checkCountProducts2"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct2.name$$)}}" userInput="$$createProduct2.name$$" stepKey="seeProductName6"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct12.name$$)}}" From 9b47faaf5355ecd10121ed4d9c270497367512ad Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Fri, 9 Nov 2018 20:19:24 +0200 Subject: [PATCH 36/49] MAGETWO-95759: Category tree display wrong number of product --- ...AdminFilteringCategoryProductsUsingScopeSelectorTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml index 539136515bd04..ba0eb20ce7733 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminFilteringCategoryProductsUsingScopeSelectorTest.xml @@ -115,7 +115,7 @@ <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection"/> <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" stepKey="grabTextFromCategory"/> - <assertRegExp expected="/\(4\)/" expectedType="string" actual="$grabTextFromCategory" actualType="variable" + <assertRegExp expected="/\(4\)$/" expectedType="string" actual="$grabTextFromCategory" actualType="variable" message="wrongCountProductOnAllStoreViews" stepKey="checkCountProducts"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct0.name$$)}}" userInput="$$createProduct0.name$$" stepKey="seeProductName"/> @@ -139,7 +139,7 @@ <waitForPageLoad stepKey="waitForCategoryPageLoad2"/> <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" stepKey="grabTextFromCategory1"/> - <assertRegExp expected="/\(2\)/" expectedType="string" actual="$grabTextFromCategory1" actualType="variable" + <assertRegExp expected="/\(2\)$/" expectedType="string" actual="$grabTextFromCategory1" actualType="variable" message="wrongCountProductOnWebsite1" stepKey="checkCountProducts1"/> <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection1"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct1.name$$)}}" @@ -166,7 +166,7 @@ <click selector="{{AdminCategoryProductsSection.sectionHeader}}" stepKey="openProductSection2"/> <grabTextFrom selector="{{AdminCategorySidebarTreeSection.categoryInTree($$createCategory.name$$)}}" stepKey="grabTextFromCategory2"/> - <assertRegExp expected="/\(2\)/" expectedType="string" actual="$grabTextFromCategory2" actualType="variable" + <assertRegExp expected="/\(2\)$/" expectedType="string" actual="$grabTextFromCategory2" actualType="variable" message="wrongCountProductOnWebsite2" stepKey="checkCountProducts2"/> <see selector="{{AdminCategoryProductsGridSection.productGridNameProduct($$createProduct2.name$$)}}" userInput="$$createProduct2.name$$" stepKey="seeProductName6"/> From 4b022dc48d2ec6b2b2349a9903d5b305639da9ac Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Mon, 12 Nov 2018 14:21:24 +0200 Subject: [PATCH 37/49] MAGETWO-95759: Category tree display wrong number of product --- .../Magento/Catalog/Model/ResourceModel/Category/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php index d9d0dde3e87c0..e7361c6426b1d 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php @@ -265,7 +265,7 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr 'main_table.category_id=e.entity_id', [] )->where( - '(e.entity_id = :entity_id or e.path LIKE :c_path)' + '(e.entity_id = :entity_id OR e.path LIKE :c_path)' ); if ($websiteId) { $select->join( From 955caf726a87b1e47fc7878516a054e5dd1c99db Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Mon, 12 Nov 2018 16:31:02 +0200 Subject: [PATCH 38/49] MAGETWO-95781: The value Quantity of Advenced Pricing isn't saved correctly --- .../Product/Attribute/Backend/TierPrice/SaveHandler.php | 5 ++--- .../Product/Attribute/Backend/TierPrice/UpdateHandler.php | 4 ++-- .../Model/Product/Attribute/Backend/TierpriceTest.php | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php index 81811f1a90ba0..92046bf15d2e4 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php @@ -52,13 +52,12 @@ public function __construct( MetadataPool $metadataPool, Tierprice $tierPriceResource ) { + parent::__construct($groupManagement); + $this->storeManager = $storeManager; $this->attributeRepository = $attributeRepository; - $this->groupManagement = $groupManagement; $this->metadataPoll = $metadataPool; $this->tierPriceResource = $tierPriceResource; - - parent::__construct($groupManagement); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php index 89f31cd132e83..500e59f26a2c3 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php @@ -52,12 +52,12 @@ public function __construct( MetadataPool $metadataPool, Tierprice $tierPriceResource ) { + parent::__construct($groupManagement); + $this->storeManager = $storeManager; $this->attributeRepository = $attributeRepository; $this->metadataPoll = $metadataPool; $this->tierPriceResource = $tierPriceResource; - - parent::__construct($groupManagement); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php index 5651d1658fed8..4e42ed0ec32f3 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php @@ -75,7 +75,7 @@ public function testValidate() /** * Test that duplicated tier price values issues exception during validation. * - * @dataProvider testValidateDuplicateDataProvider + * @dataProvider validateDuplicateDataProvider * @expectedException \Magento\Framework\Exception\LocalizedException */ public function testValidateDuplicate(array $tierPricesData) @@ -91,7 +91,7 @@ public function testValidateDuplicate(array $tierPricesData) * * @return array */ - public function testValidateDuplicateDataProvider(): array + public function validateDuplicateDataProvider(): array { return [ [ From 6f6694c3b1ca869fc6bd238c68dc8772d2261471 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Mon, 12 Nov 2018 19:36:39 +0200 Subject: [PATCH 39/49] MAGETWO-96288: [Magento Cloud] Cannot update category positions via REST API --- .../Magento/Catalog/Model/Category/Link/SaveHandler.php | 8 +++----- .../Catalog/Model/ResourceModel/Product/CategoryLink.php | 9 ++++----- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php b/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php index 5af421b5bc34c..1464f6557f6a6 100644 --- a/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php @@ -111,18 +111,16 @@ private function mergeCategoryLinks($newCategoryPositions, $oldCategoryPositions return $result; } + $oldCategoryList = array_column($oldCategoryPositions, 'category_id'); foreach ($newCategoryPositions as $newCategoryPosition) { - $key = array_search( - $newCategoryPosition['category_id'], - array_column($oldCategoryPositions, 'category_id') - ); + $key = array_search($newCategoryPosition['category_id'], $oldCategoryList); if ($key === false) { $result[] = $newCategoryPosition; } elseif (isset($oldCategoryPositions[$key]) && $oldCategoryPositions[$key]['position'] != $newCategoryPosition['position'] ) { - $result[] = $newCategoryPositions[$key]; + $result[] = $newCategoryPosition; unset($oldCategoryPositions[$key]); } } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php index b54c19a111508..ada000ca58bdc 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php @@ -114,16 +114,15 @@ private function getCategoryLinkMetadata() private function processCategoryLinks($newCategoryPositions, &$oldCategoryPositions) { $result = ['changed' => [], 'updated' => []]; + + $oldCategoryList = array_column($oldCategoryPositions, 'category_id'); foreach ($newCategoryPositions as $newCategoryPosition) { - $key = array_search( - $newCategoryPosition['category_id'], - array_column($oldCategoryPositions, 'category_id') - ); + $key = array_search($newCategoryPosition['category_id'], $oldCategoryList); if ($key === false) { $result['changed'][] = $newCategoryPosition; } elseif ($oldCategoryPositions[$key]['position'] != $newCategoryPosition['position']) { - $result['updated'][] = $newCategoryPositions[$key]; + $result['updated'][] = $newCategoryPosition; unset($oldCategoryPositions[$key]); } } From 48738eab7ce4946245d36640b903dad594d4c85f Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Tue, 13 Nov 2018 10:23:21 +0200 Subject: [PATCH 40/49] MAGETWO-96174: [2.2] Improve order creation flow --- .../Section/AdminOrderFormPaymentSection.xml | 2 +- .../templates/order/create/data.phtml | 18 ++- .../order/create/shipping/method/form.phtml | 6 +- .../adminhtml/web/order/create/scripts.js | 115 ++++++++++++++---- .../order/create/payment/reload.html | 18 +++ .../order/create/shipping/reload.html | 19 +++ .../web/css/source/module/_order.less | 38 +----- .../module/order/_payment-shipping.less | 3 + .../Magento/backend/web/css/styles-old.less | 7 +- .../Test/Block/Adminhtml/Order/Create.php | 3 +- .../Adminhtml/Order/Create/Billing/Method.php | 14 +++ .../Block/Adminhtml/Order/Create/Items.php | 1 + .../Order/Create/Shipping/Method.php | 12 +- 13 files changed, 167 insertions(+), 89 deletions(-) create mode 100644 app/code/Magento/Sales/view/adminhtml/web/templates/order/create/payment/reload.html create mode 100644 app/code/Magento/Sales/view/adminhtml/web/templates/order/create/shipping/reload.html diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index ab74320f26a30..2ef2c08f7b2b1 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -9,7 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminOrderFormPaymentSection"> - <element name="header" type="text" selector="#order-methods span.title"/> + <element name="header" type="text" selector="#shipping-methods span.title"/> <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> <element name="flatRateOption" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> <element name="shippingError" type="text" selector="#order[has_shipping]-error"/> diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/data.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/data.phtml index fdbaae2347398..170fea937348d 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/data.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/data.phtml @@ -47,17 +47,15 @@ </div> </section> - <section id="order-methods" class="admin__page-section order-methods"> - <div class="admin__page-section-title"> - <span class="title"><?= /* @escapeNotVerified */ __('Payment & Shipping Information') ?></span> + <section id="shipping-methods" class="admin__page-section order-methods"> + <div id="order-shipping_method" class="admin__page-section-item order-shipping-method"> + <?= $block->getChildHtml('shipping_method') ?> </div> - <div class="admin__page-section-content"> - <div id="order-billing_method" class="admin__page-section-item order-billing-method"> - <?= $block->getChildHtml('billing_method') ?> - </div> - <div id="order-shipping_method" class="admin__page-section-item order-shipping-method"> - <?= $block->getChildHtml('shipping_method') ?> - </div> + </section> + + <section id="payment-methods" class="admin__page-section payment-methods"> + <div id="order-billing_method" class="admin__page-section-item order-billing-method"> + <?= $block->getChildHtml('billing_method') ?> </div> </section> diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/shipping/method/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/shipping/method/form.phtml index 9e0394f6430bd..65d3a612e5133 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/shipping/method/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/shipping/method/form.phtml @@ -100,12 +100,8 @@ require(['prototype'], function(){ </div> <script> require(["Magento_Sales/order/create/form"], function(){ - order.overlay('shipping-method-overlay', <?php if ($block->getQuote()->isVirtual()): ?>false<?php else: ?>true<?php endif; ?>); order.overlay('address-shipping-overlay', <?php if ($block->getQuote()->isVirtual()): ?>false<?php else: ?>true<?php endif; ?>); - - <?php if ($block->getQuote()->isVirtual()): ?> - order.isOnlyVirtualProduct = true; - <?php endif; ?> + order.isOnlyVirtualProduct = <?= /* @noEscape */ $block->getQuote()->isVirtual() ? 'true' : 'false'; ?>; }); </script> diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 259ca2165e647..05449c478152f 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -4,14 +4,17 @@ */ define([ - "jquery", + 'jquery', 'Magento_Ui/js/modal/confirm', 'Magento_Ui/js/modal/alert', - "mage/translate", - "prototype", - "Magento_Catalog/catalog/product/composite/configure", + 'mage/template', + 'text!Magento_Sales/templates/order/create/shipping/reload.html', + 'text!Magento_Sales/templates/order/create/payment/reload.html', + 'mage/translate', + 'prototype', + 'Magento_Catalog/catalog/product/composite/configure', 'Magento_Ui/js/lib/view/utils/async' -], function(jQuery, confirm, alert){ +], function(jQuery, confirm, alert, template, shippingTemplate, paymentTemplate){ window.AdminOrder = new Class.create(); @@ -29,7 +32,7 @@ define([ this.gridProducts = $H({}); this.gridProductsGift = $H({}); this.billingAddressContainer = ''; - this.shippingAddressContainer= ''; + this.shippingAddressContainer = ''; this.isShippingMethodReseted = data.shipping_method_reseted ? data.shipping_method_reseted : false; this.overlayData = $H({}); this.giftMessageDataChanged = false; @@ -40,6 +43,19 @@ define([ this.excludedPaymentMethods = []; this.summarizePrice = true; this.timerId = null; + this.shippingTemplate = template(shippingTemplate, { + data: { + title: jQuery.mage.__('Shipping Method'), + linkText: jQuery.mage.__('Get shipping methods and rates') + } + }); + this.paymentTemplate = template(paymentTemplate, { + data: { + title: jQuery.mage.__('Payment Method'), + linkText: jQuery.mage.__('Get available payment methods') + } + }); + jQuery.async('#order-items', (function(){ this.dataArea = new OrderFormArea('data', $(this.getAreaId('data')), this); this.itemsArea = Object.extend(new OrderFormArea('items', $(this.getAreaId('items')), this), { @@ -168,10 +184,11 @@ define([ var data = this.serializeData(container); data[el.name] = id; - if(this.isShippingField(container) && !this.isShippingMethodReseted){ + + this.resetPaymentMethod(); + if (this.isShippingField(container) && !this.isShippingMethodReseted) { this.resetShippingMethod(data); - } - else{ + } else{ this.saveData(data); } }, @@ -239,13 +256,14 @@ define([ } data['order[' + type + '_address][customer_address_id]'] = null; - data['shipping_as_billing'] = jQuery('[name="shipping_same_as_billing"]').is(':checked') ? 1 : 0; + data['shipping_as_billing'] = +this.isShippingAsBilling(); if (name === 'customer_address_id') { data['order[' + type + '_address][customer_address_id]'] = $('order-' + type + '_address_customer_address_id').value; } + this.resetPaymentMethod(); if (data['reset_shipping']) { this.resetShippingMethod(data); } else { @@ -348,30 +366,69 @@ define([ this.loadArea(areasToLoad, true, data); }, - resetShippingMethod : function(data){ - var areasToLoad = ['billing_method', 'shipping_address', 'totals', 'giftmessage', 'items']; - if(!this.isOnlyVirtualProduct) { - areasToLoad.push('shipping_method'); - areasToLoad.push('shipping_address'); + /** + * Checks if shipping address is corresponds to billing address. + * + * @return {Boolean} + */ + isShippingAsBilling: function () { + return jQuery('[name="shipping_same_as_billing"]').is(':checked'); + }, + + resetShippingMethod: function() { + if (!this.isOnlyVirtualProduct) { + $(this.getAreaId('shipping_method')).update(this.shippingTemplate); } + }, - data['reset_shipping'] = 1; - this.isShippingMethodReseted = true; - this.loadArea(areasToLoad, true, data); + resetPaymentMethod: function() { + $(this.getAreaId('billing_method')).update(this.paymentTemplate); }, - loadShippingRates : function(){ + /** + * Loads shipping options according to address data. + * + * @return {Boolean} + */ + loadShippingRates: function () { + var addressContainer = this.isShippingAsBilling() ? + 'billingAddressContainer' : + 'shippingAddressContainer', + data = this.serializeData(this[addressContainer]).toObject(); + + data['collect_shipping_rates'] = 1; this.isShippingMethodReseted = false; - this.loadArea(['shipping_method', 'totals'], true, {collect_shipping_rates: 1}); + this.loadArea(['shipping_method', 'totals'], true, data); + + return false; }, - setShippingMethod : function(method){ + setShippingMethod: function(method) { var data = {}; + data['order[shipping_method]'] = method; - this.loadArea(['shipping_method', 'totals', 'billing_method'], true, data); + this.loadArea([ + 'shipping_method', + 'totals', + 'billing_method' + ], true, data); }, - switchPaymentMethod : function(method){ + /** + * Updates available payment + * methods list according to order data. + * + * @return boolean + */ + loadPaymentMethods: function() { + var data = this.serializeData(this.billingAddressContainer).toObject(); + + this.loadArea(['billing_method','totals'], true, data); + + return false; + }, + + switchPaymentMethod: function(method){ jQuery('#edit_form') .off('submitOrder') .on('submitOrder', function(){ @@ -1149,9 +1206,15 @@ define([ || this.excludedPaymentMethods.indexOf(this.paymentMethod) == -1); }, - serializeData : function(container){ - var fields = $(container).select('input', 'select', 'textarea'); - var data = Form.serializeElements(fields, true); + /** + * Serializes container form elements data. + * + * @param {String} container + * @return {Object} + */ + serializeData: function (container) { + var fields = $(container).select('input', 'select', 'textarea'), + data = Form.serializeElements(fields, true); return $H(data); }, diff --git a/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/payment/reload.html b/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/payment/reload.html new file mode 100644 index 0000000000000..c503f3c678ab6 --- /dev/null +++ b/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/payment/reload.html @@ -0,0 +1,18 @@ +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<div class="admin__page-section-title"> + <span class="title"><%- data.title %></span> +</div> +<div id="order-billing_method_summary" + class="order-billing-method-summary"> + <a href="#" + onclick="return order.loadPaymentMethods();" + class="action-default"> + <span><%- data.linkText %></span> + </a> +</div> diff --git a/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/shipping/reload.html b/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/shipping/reload.html new file mode 100644 index 0000000000000..6b191ee81a45a --- /dev/null +++ b/app/code/Magento/Sales/view/adminhtml/web/templates/order/create/shipping/reload.html @@ -0,0 +1,19 @@ +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<div class="admin__page-section-title"> + <span class="title"><%- data.title %></span> +</div> +<div id="order-shipping-method-summary" + class="order-shipping-method-summary"> + <a href="#" + onclick="return order.loadShippingRates();" + class="action-default"> + <span><%- data.linkText %></span> + </a> + <input type="hidden" name="order[has_shipping]" value="" class="required-entry" /> +</div> diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less index 984556816b035..1e76679f594c1 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less @@ -55,7 +55,6 @@ } .order-billing-address, - .order-billing-method, .order-history, .order-information, .order-payment-method, @@ -65,7 +64,6 @@ } .order-shipping-address, - .order-shipping-method, .order-totals, .order-view-account-information .order-account-information { float: right; @@ -300,38 +298,4 @@ } } -// ToDo UI: review the collapsible block -//.order-subtotal { -// .summary-collapse { -// cursor: pointer; -// display: inline-block; -// &:before { -// @iconsize: 16px; -// -// -webkit-font-smoothing: antialiased; -// background: #f2ebde; -// border-radius: 2px; -// border: 1px solid #ada89e; -// color: #816063; -// content: '+'; -// display: inline-block; -// font-size: @iconsize; -// font-style: normal; -// font-weight: normal; -// height: @iconsize; -// line-height: @iconsize; -// margin-right: 7px; -// overflow: hidden; -// speak: none; -// text-indent: 0; -// vertical-align: top; -// width: @iconsize; -// } -// &:hover:before { -// background: #cac3b4; -// } -// } -// &.show-details .summary-collapse:before { -// content: '\e03a'; -// } -//} +// ToDo: MAGETWO-32299 UI: review the collapsible block diff --git a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less index 1e40fe1fa3403..029594625ed1c 100644 --- a/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less +++ b/app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/order/_payment-shipping.less @@ -9,6 +9,7 @@ .admin__payment-method-wrapper { margin: 0; + width: calc(50% - @indent__l); .admin__field { margin-left: 0; &:first-child { @@ -34,6 +35,7 @@ margin: 0; } +.order-billing-method-summary, .order-shipping-method-summary { padding-top: @field-option__padding-top; } @@ -43,6 +45,7 @@ position: relative; } +.order-billing-method-summary, .order-shipping-method-summary, .order-shipping-method-info { .action-default { diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less index 8d314e06899b3..c94dd4e62ada8 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -2544,6 +2544,8 @@ .order-summary:after, .order-methods:before, .order-methods:after, + .payment-methods:before, + .payment-methods:after, .grid-actions:before, .grid-actions:after, .fieldset-wrapper-title:before, @@ -2559,6 +2561,7 @@ .order-addresses:after, .order-summary:after, .order-methods:after, + .payment-methods:after, .grid-actions:after, .fieldset-wrapper-title:after { clear: both; @@ -2898,6 +2901,7 @@ .style28(); } + #order-billing-method-summary a, #order-shipping-method-summary a { .style3(); } @@ -2936,7 +2940,8 @@ margin: 0 0 0 20px; } - #order-data .order-methods ul { + #order-data .order-methods ul, + #order-data .payment-methods ul { list-style: none; margin: 0; padding: 0; diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php index 5b9ae99a2e868..14bc04cfed70c 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create.php @@ -105,7 +105,7 @@ class Create extends Block * * @var string */ - protected $orderMethodsSelector = '#order-methods'; + protected $orderMethodsSelector = '#shipping-methods'; /** * Page header. @@ -323,7 +323,6 @@ public function fillShippingAddress(FixtureInterface $shippingAddress) */ public function selectShippingMethod(array $shippingMethod) { - $this->_rootElement->find($this->orderMethodsSelector)->click(); $this->getShippingMethodBlock()->selectShippingMethod($shippingMethod); $this->getTemplateBlock()->waitLoader(); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php index dee1336c14e4c..e5c414c4807d6 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Billing/Method.php @@ -22,6 +22,13 @@ class Method extends Block */ private $paymentMethod = '#p_method_%s'; + /** + * Get available payment methods link. + * + * @var string + */ + private $billingMethodsLink = '#order-billing_method_summary a'; + /** * Purchase order number selector. * @@ -59,6 +66,13 @@ class Method extends Block */ public function selectPaymentMethod(array $payment, CreditCard $creditCard = null) { + $this->waitForElementNotVisible($this->loader); + $billingMethodsLink = $this->_rootElement->find($this->billingMethodsLink); + if ($billingMethodsLink->isPresent()) { + $billingMethodsLink->click(); + $this->waitForElementNotVisible($this->loader); + } + $paymentMethod = $payment['method']; $paymentInput = $this->_rootElement->find(sprintf($this->paymentMethod, $paymentMethod)); if ($paymentInput->isVisible()) { diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php index daa58a3447c02..61c48d62630f4 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Items.php @@ -73,6 +73,7 @@ function () use ($element, $selector) { return $addProductsButton->isVisible() ? true : null; } ); + $this->getTemplateBlock()->waitLoader(); $this->_rootElement->find($this->addProducts, Locator::SELECTOR_XPATH)->click(); $this->getTemplateBlock()->waitLoader(); } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php index 2ee6269c39d47..b5acaf01f5483 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Adminhtml/Order/Create/Shipping/Method.php @@ -44,13 +44,12 @@ class Method extends Block public function selectShippingMethod(array $shippingMethod) { $this->waitFormLoading(); - $this->_rootElement->waitUntil( - function () { - return $this->_rootElement->find($this->shippingMethodsLink)->isVisible() ? true : null; - } - ); + $shippingMethodsLink = $this->_rootElement->find($this->shippingMethodsLink); + if ($shippingMethodsLink->isPresent()) { + $shippingMethodsLink->click(); + $this->waitFormLoading(); + } - $this->_rootElement->find($this->shippingMethodsLink)->click(); $selector = sprintf( $this->shippingMethod, $shippingMethod['shipping_service'], @@ -67,7 +66,6 @@ function () { */ private function waitFormLoading() { - $this->_rootElement->click(); $this->browser->waitUntil( function () { return $this->browser->find($this->waitElement)->isVisible() ? null : true; From 9c066ca1cc2f2db9e66575da25992ca9bb74f65a Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 13 Nov 2018 11:04:46 +0200 Subject: [PATCH 41/49] MAGETWO-87920: Shipping method Table Rates settings gets from wrong store --- .../Magento/Quote/Model/Quote/Address.php | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index a738f844c8d8d..f0419c7f96095 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -965,6 +965,7 @@ public function collectShippingRates() /** * Request shipping rates for entire address or specified address item + * * Returns true if current selected shipping method code corresponds to one of the found rates * * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item @@ -1003,8 +1004,14 @@ public function requestShippingRates(\Magento\Quote\Model\Quote\Item\AbstractIte * Store and website identifiers specified from StoreManager */ $request->setQuoteStoreId($this->getQuote()->getStoreId()); - $request->setStoreId($this->storeManager->getStore()->getId()); - $request->setWebsiteId($this->storeManager->getWebsite()->getId()); + if ($this->getQuote()->getStoreId()) { + $storeId = $this->getQuote()->getStoreId(); + $request->setStoreId($storeId); + $request->setWebsiteId($this->storeManager->getStore($storeId)->getWebsiteId()); + } else { + $request->setStoreId($this->storeManager->getStore()->getId()); + $request->setWebsiteId($this->storeManager->getWebsite()->getId()); + } $request->setFreeShipping($this->getFreeShipping()); /** * Currencies need to convert in free shipping @@ -1349,7 +1356,7 @@ public function getAllBaseTotalAmounts() /******************************* End Total Collector Interface *******************************************/ /** - * {@inheritdoc} + * @inheritdoc */ protected function _getValidationRulesBeforeSave() { @@ -1357,7 +1364,7 @@ protected function _getValidationRulesBeforeSave() } /** - * {@inheritdoc} + * @inheritdoc */ public function getCountryId() { @@ -1365,7 +1372,7 @@ public function getCountryId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCountryId($countryId) { @@ -1373,7 +1380,7 @@ public function setCountryId($countryId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getStreet() { @@ -1382,7 +1389,7 @@ public function getStreet() } /** - * {@inheritdoc} + * @inheritdoc */ public function setStreet($street) { @@ -1390,7 +1397,7 @@ public function setStreet($street) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCompany() { @@ -1398,7 +1405,7 @@ public function getCompany() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCompany($company) { @@ -1406,7 +1413,7 @@ public function setCompany($company) } /** - * {@inheritdoc} + * @inheritdoc */ public function getTelephone() { @@ -1414,7 +1421,7 @@ public function getTelephone() } /** - * {@inheritdoc} + * @inheritdoc */ public function setTelephone($telephone) { @@ -1422,7 +1429,7 @@ public function setTelephone($telephone) } /** - * {@inheritdoc} + * @inheritdoc */ public function getFax() { @@ -1430,7 +1437,7 @@ public function getFax() } /** - * {@inheritdoc} + * @inheritdoc */ public function setFax($fax) { @@ -1438,7 +1445,7 @@ public function setFax($fax) } /** - * {@inheritdoc} + * @inheritdoc */ public function getPostcode() { @@ -1446,7 +1453,7 @@ public function getPostcode() } /** - * {@inheritdoc} + * @inheritdoc */ public function setPostcode($postcode) { @@ -1454,7 +1461,7 @@ public function setPostcode($postcode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCity() { @@ -1462,7 +1469,7 @@ public function getCity() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCity($city) { @@ -1470,7 +1477,7 @@ public function setCity($city) } /** - * {@inheritdoc} + * @inheritdoc */ public function getFirstname() { @@ -1478,7 +1485,7 @@ public function getFirstname() } /** - * {@inheritdoc} + * @inheritdoc */ public function setFirstname($firstname) { @@ -1486,7 +1493,7 @@ public function setFirstname($firstname) } /** - * {@inheritdoc} + * @inheritdoc */ public function getLastname() { @@ -1494,7 +1501,7 @@ public function getLastname() } /** - * {@inheritdoc} + * @inheritdoc */ public function setLastname($lastname) { @@ -1502,7 +1509,7 @@ public function setLastname($lastname) } /** - * {@inheritdoc} + * @inheritdoc */ public function getMiddlename() { @@ -1510,7 +1517,7 @@ public function getMiddlename() } /** - * {@inheritdoc} + * @inheritdoc */ public function setMiddlename($middlename) { @@ -1518,7 +1525,7 @@ public function setMiddlename($middlename) } /** - * {@inheritdoc} + * @inheritdoc */ public function getPrefix() { @@ -1526,7 +1533,7 @@ public function getPrefix() } /** - * {@inheritdoc} + * @inheritdoc */ public function setPrefix($prefix) { @@ -1534,7 +1541,7 @@ public function setPrefix($prefix) } /** - * {@inheritdoc} + * @inheritdoc */ public function getSuffix() { @@ -1542,7 +1549,7 @@ public function getSuffix() } /** - * {@inheritdoc} + * @inheritdoc */ public function setSuffix($suffix) { @@ -1550,7 +1557,7 @@ public function setSuffix($suffix) } /** - * {@inheritdoc} + * @inheritdoc */ public function getVatId() { @@ -1558,7 +1565,7 @@ public function getVatId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setVatId($vatId) { @@ -1566,7 +1573,7 @@ public function setVatId($vatId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomerId() { @@ -1574,7 +1581,7 @@ public function getCustomerId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerId($customerId) { @@ -1582,7 +1589,7 @@ public function setCustomerId($customerId) } /** - * {@inheritdoc} + * @inheritdoc */ public function getEmail() { @@ -1595,7 +1602,7 @@ public function getEmail() } /** - * {@inheritdoc} + * @inheritdoc */ public function setEmail($email) { @@ -1603,7 +1610,7 @@ public function setEmail($email) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegion($region) { @@ -1611,7 +1618,7 @@ public function setRegion($region) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegionId($regionId) { @@ -1619,7 +1626,7 @@ public function setRegionId($regionId) } /** - * {@inheritdoc} + * @inheritdoc */ public function setRegionCode($regionCode) { @@ -1627,7 +1634,7 @@ public function setRegionCode($regionCode) } /** - * {@inheritdoc} + * @inheritdoc */ public function getSameAsBilling() { @@ -1635,7 +1642,7 @@ public function getSameAsBilling() } /** - * {@inheritdoc} + * @inheritdoc */ public function setSameAsBilling($sameAsBilling) { @@ -1643,7 +1650,7 @@ public function setSameAsBilling($sameAsBilling) } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomerAddressId() { @@ -1651,7 +1658,7 @@ public function getCustomerAddressId() } /** - * {@inheritdoc} + * @inheritdoc */ public function setCustomerAddressId($customerAddressId) { @@ -1682,9 +1689,7 @@ public function setSaveInAddressBook($saveInAddressBook) //@codeCoverageIgnoreEnd /** - * {@inheritdoc} - * - * @return \Magento\Quote\Api\Data\AddressExtensionInterface|null + * @inheritdoc */ public function getExtensionAttributes() { @@ -1692,10 +1697,7 @@ public function getExtensionAttributes() } /** - * {@inheritdoc} - * - * @param \Magento\Quote\Api\Data\AddressExtensionInterface $extensionAttributes - * @return $this + * @inheritdoc */ public function setExtensionAttributes(\Magento\Quote\Api\Data\AddressExtensionInterface $extensionAttributes) { @@ -1713,7 +1715,7 @@ public function getShippingMethod() } /** - * {@inheritdoc} + * @inheritdoc */ protected function getCustomAttributesCodes() { From 3fe6c70882669acf77838da7bf86f678e690d6ed Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Tue, 13 Nov 2018 11:02:59 +0200 Subject: [PATCH 42/49] MAGETWO-96288: [Magento Cloud] Cannot update category positions via REST API --- .../Model/Category/Link/SaveHandler.php | 20 +++++++------------ .../ResourceModel/Product/CategoryLink.php | 1 + 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php b/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php index 1464f6557f6a6..fd80d754a5b57 100644 --- a/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php +++ b/app/code/Magento/Catalog/Model/Category/Link/SaveHandler.php @@ -106,25 +106,19 @@ private function getCategoryLinksPositions($entity) */ private function mergeCategoryLinks($newCategoryPositions, $oldCategoryPositions) { - $result = []; if (empty($newCategoryPositions)) { - return $result; + return []; } - $oldCategoryList = array_column($oldCategoryPositions, 'category_id'); + $categoryPositions = array_combine(array_column($oldCategoryPositions, 'category_id'), $oldCategoryPositions); foreach ($newCategoryPositions as $newCategoryPosition) { - $key = array_search($newCategoryPosition['category_id'], $oldCategoryList); - - if ($key === false) { - $result[] = $newCategoryPosition; - } elseif (isset($oldCategoryPositions[$key]) - && $oldCategoryPositions[$key]['position'] != $newCategoryPosition['position'] - ) { - $result[] = $newCategoryPosition; - unset($oldCategoryPositions[$key]); + $categoryId = $newCategoryPosition['category_id']; + if (!isset($categoryPositions[$categoryId])) { + $categoryPositions[$categoryId] = ['category_id' => $categoryId]; } + $categoryPositions[$categoryId]['position'] = $newCategoryPosition['position']; } - $result = array_merge($result, $oldCategoryPositions); + $result = array_values($categoryPositions); return $result; } diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php index ada000ca58bdc..69da78543d8eb 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/CategoryLink.php @@ -115,6 +115,7 @@ private function processCategoryLinks($newCategoryPositions, &$oldCategoryPositi { $result = ['changed' => [], 'updated' => []]; + $oldCategoryPositions = array_values($oldCategoryPositions); $oldCategoryList = array_column($oldCategoryPositions, 'category_id'); foreach ($newCategoryPositions as $newCategoryPosition) { $key = array_search($newCategoryPosition['category_id'], $oldCategoryList); From 4b3b6699a6e1d3f70ad1c6006583110bf7987330 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 13 Nov 2018 14:52:03 +0200 Subject: [PATCH 43/49] MAGETWO-96156: Track not saved during shipment creation through API --- .../Magento/Sales/Model/Order/Shipment.php | 43 +++--- .../ResourceModel/Order/Shipment/Relation.php | 4 +- .../Order/Shipment/RelationTest.php | 142 ++++++++---------- .../Sales/Model/Order/ShipmentTest.php | 18 ++- 4 files changed, 98 insertions(+), 109 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php index 92bbdb9626b6e..9346283321eac 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Order/Shipment.php @@ -343,7 +343,15 @@ public function addItem(\Magento\Sales\Model\Order\Shipment\Item $item) public function getTracksCollection() { if ($this->tracksCollection === null) { - $this->tracksCollection = $this->_trackCollectionFactory->create()->setShipmentFilter($this->getId()); + $this->tracksCollection = $this->_trackCollectionFactory->create(); + + if ($this->getId()) { + $this->tracksCollection->setShipmentFilter($this->getId()); + + foreach ($this->tracksCollection as $item) { + $item->setShipment($this); + } + } } return $this->tracksCollection; @@ -383,19 +391,20 @@ public function getTrackById($trackId) */ public function addTrack(\Magento\Sales\Model\Order\Shipment\Track $track) { - $track->setShipment( - $this - )->setParentId( - $this->getId() - )->setOrderId( - $this->getOrderId() - )->setStoreId( - $this->getStoreId() - ); + $track->setShipment($this) + ->setParentId($this->getId()) + ->setOrderId($this->getOrderId()) + ->setStoreId($this->getStoreId()); + if (!$track->getId()) { $this->getTracksCollection()->addItem($track); } + $tracks = $this->getTracks(); + // as it new track entity, collection doesn't contain it + $tracks[] = $track; + $this->setTracks($tracks); + /** * Track saving is implemented in _afterSave() * This enforces \Magento\Framework\Model\AbstractModel::save() not to skip _afterSave() @@ -562,18 +571,16 @@ public function setItems($items) /** * Returns tracks * - * @return \Magento\Sales\Api\Data\ShipmentTrackInterface[] + * @return \Magento\Sales\Api\Data\ShipmentTrackInterface[]|null */ public function getTracks() { + if (!$this->getId()) { + return $this->getData(ShipmentInterface::TRACKS); + } + if ($this->getData(ShipmentInterface::TRACKS) === null) { - $collection = $this->_trackCollectionFactory->create()->setShipmentFilter($this->getId()); - if ($this->getId()) { - foreach ($collection as $item) { - $item->setShipment($this); - } - $this->setData(ShipmentInterface::TRACKS, $collection->getItems()); - } + $this->setData(ShipmentInterface::TRACKS, $this->getTracksCollection()->getItems()); } return $this->getData(ShipmentInterface::TRACKS); } diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php index 9c8671d02c578..5851b2d936139 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Shipment/Relation.php @@ -62,8 +62,8 @@ public function processRelation(\Magento\Framework\Model\AbstractModel $object) $this->shipmentItemResource->save($item); } } - if (null !== $object->getTracksCollection()) { - foreach ($object->getTracksCollection() as $track) { + if (null !== $object->getTracks()) { + foreach ($object->getTracks() as $track) { $track->setParentId($object->getId()); $this->shipmentTrackResource->save($track); } diff --git a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php index a7a615fb0f508..9eee4b809ba0e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/ResourceModel/Order/Shipment/RelationTest.php @@ -3,145 +3,125 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Sales\Test\Unit\Model\ResourceModel\Order\Shipment; +use Magento\Sales\Model\Order\Shipment; +use Magento\Sales\Model\Order\Shipment\Comment as CommentEntity; +use Magento\Sales\Model\Order\Shipment\Item as ItemEntity; +use Magento\Sales\Model\Order\Shipment\Track as TrackEntity; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Comment; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Item; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Relation; +use Magento\Sales\Model\ResourceModel\Order\Shipment\Track; +use PHPUnit\Framework\MockObject\MockObject; + /** * Class RelationTest */ class RelationTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Relation + * @var Relation */ - protected $relationProcessor; + private $relationProcessor; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Item|\PHPUnit_Framework_MockObject_MockObject + * @var Item|MockObject */ - protected $itemResourceMock; + private $itemResource; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Track|\PHPUnit_Framework_MockObject_MockObject + * @var Track|MockObject */ - protected $trackResourceMock; + private $trackResource; /** - * @var \Magento\Sales\Model\ResourceModel\Order\Shipment\Comment|\PHPUnit_Framework_MockObject_MockObject + * @var Comment|MockObject */ - protected $commentResourceMock; + private $commentResource; /** - * @var \Magento\Sales\Model\Order\Shipment\Comment|\PHPUnit_Framework_MockObject_MockObject + * @var CommentEntity|MockObject */ - protected $commentMock; + private $comment; /** - * @var \Magento\Sales\Model\Order\Shipment\Track|\PHPUnit_Framework_MockObject_MockObject + * @var TrackEntity|MockObject */ - protected $trackMock; + private $track; /** - * @var \Magento\Sales\Model\Order\Shipment|\PHPUnit_Framework_MockObject_MockObject + * @var Shipment|MockObject */ - protected $shipmentMock; + private $shipment; /** - * @var \Magento\Sales\Model\Order\Shipment\Item|\PHPUnit_Framework_MockObject_MockObject + * @var ItemEntity|MockObject */ - protected $itemMock; + private $item; + /** + * @inheritdoc + */ protected function setUp() { - $this->itemResourceMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Item::class) + $this->itemResource = $this->getMockBuilder(Item::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->commentResourceMock = $this->getMockBuilder( - \Magento\Sales\Model\ResourceModel\Order\Shipment\Comment::class - ) + $this->commentResource = $this->getMockBuilder(Comment::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->trackResourceMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Track::class) + $this->trackResource = $this->getMockBuilder(Track::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'save' - ] - ) ->getMock(); - $this->shipmentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + $this->shipment = $this->getMockBuilder(Shipment::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'getId', - 'getItems', - 'getTracks', - 'getComments', - 'getTracksCollection', - ] - ) ->getMock(); - $this->itemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class) + $this->item = $this->getMockBuilder(ItemEntity::class) ->disableOriginalConstructor() - ->setMethods( - [ - 'setParentId' - ] - ) ->getMock(); - $this->trackMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + $this->track = $this->getMockBuilder(TrackEntity::class) ->disableOriginalConstructor() ->getMock(); - $this->commentMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + $this->comment = $this->getMockBuilder(Shipment::class) ->disableOriginalConstructor() ->getMock(); - $this->relationProcessor = new \Magento\Sales\Model\ResourceModel\Order\Shipment\Relation( - $this->itemResourceMock, - $this->trackResourceMock, - $this->commentResourceMock + $this->relationProcessor = new Relation( + $this->itemResource, + $this->trackResource, + $this->commentResource ); } + /** + * Checks saving shipment relations. + * + * @throws \Exception + */ public function testProcessRelations() { - $this->shipmentMock->expects($this->exactly(3)) - ->method('getId') + $this->shipment->method('getId') ->willReturn('shipment-id-value'); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getItems') - ->willReturn([$this->itemMock]); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getComments') - ->willReturn([$this->commentMock]); - $this->shipmentMock->expects($this->exactly(2)) - ->method('getTracksCollection') - ->willReturn([$this->trackMock]); - $this->itemMock->expects($this->once()) - ->method('setParentId') + $this->shipment->method('getItems') + ->willReturn([$this->item]); + $this->shipment->method('getComments') + ->willReturn([$this->comment]); + $this->shipment->method('getTracks') + ->willReturn([$this->track]); + $this->item->method('setParentId') ->with('shipment-id-value') ->willReturnSelf(); - $this->itemResourceMock->expects($this->once()) - ->method('save') - ->with($this->itemMock) + $this->itemResource->method('save') + ->with($this->item) ->willReturnSelf(); - $this->commentResourceMock->expects($this->once()) - ->method('save') - ->with($this->commentMock) + $this->commentResource->method('save') + ->with($this->comment) ->willReturnSelf(); - $this->trackResourceMock->expects($this->once()) - ->method('save') - ->with($this->trackMock) + $this->trackResource->method('save') + ->with($this->track) ->willReturnSelf(); - $this->relationProcessor->processRelation($this->shipmentMock); + $this->relationProcessor->processRelation($this->shipment); } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php index cee0534761d15..8cbd5a6fb91e7 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/ShipmentTest.php @@ -77,20 +77,22 @@ public function testAddTrack() { $order = $this->getOrder('100000001'); - /** @var ShipmentInterface $shipment */ - $shipment = $this->objectManager->create(ShipmentInterface::class); - /** @var ShipmentTrackInterface $track */ $track = $this->objectManager->create(ShipmentTrackInterface::class); $track->setNumber('Test Number') ->setTitle('Test Title') ->setCarrierCode('Test CODE'); - $shipment->setOrder($order) - ->addItem($this->objectManager->create(ShipmentItemInterface::class)) - ->addTrack($track); - - $saved = $this->shipmentRepository->save($shipment); + $items = []; + foreach ($order->getItems() as $item) { + $items[$item->getId()] = $item->getQtyOrdered(); + } + /** @var \Magento\Sales\Model\Order\Shipment $shipment */ + $shipment = $this->objectManager->get(ShipmentFactory::class) + ->create($order, $items); + $shipment->addTrack($track); + $this->shipmentRepository->save($shipment); + $saved = $this->shipmentRepository->get((int)$shipment->getEntityId()); self::assertNotEmpty($saved->getTracks()); } From ed8fde464439fe69780a305f7d7c726490ca11db Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 13 Nov 2018 16:02:12 +0200 Subject: [PATCH 44/49] MAGETWO-88810: Bundled SKUs are being assembled based on the product ID number --- app/code/Magento/Bundle/Model/Product/Type.php | 7 +++++-- .../Bundle/Test/Unit/Model/Product/TypeTest.php | 11 +++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index afcb09f2f43fe..09efe07916521 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -310,8 +310,11 @@ public function getSku($product) $selectionIds = $this->serializer->unserialize($customOption->getValue()); if (!empty($selectionIds)) { $selections = $this->getSelectionsByIds($selectionIds, $product); - foreach ($selections->getItems() as $selection) { - $skuParts[] = $selection->getSku(); + foreach ($selectionIds as $selectionId) { + $entity = $selections->getItemByColumnValue('selection_id', $selectionId); + if (isset($entity) && $entity->getEntityId()) { + $skuParts[] = $entity->getSku(); + } } } } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php index d5a11e0310d35..a413be0bed5ba 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php @@ -1595,7 +1595,7 @@ public function testGetSkuWithoutType() ->disableOriginalConstructor() ->getMock(); $selectionItemMock = $this->getMockBuilder(\Magento\Framework\DataObject::class) - ->setMethods(['getSku', '__wakeup']) + ->setMethods(['getSku', 'getEntityId', '__wakeup']) ->disableOriginalConstructor() ->getMock(); @@ -1623,9 +1623,12 @@ public function testGetSkuWithoutType() ->will($this->returnValue($serializeIds)); $selectionMock = $this->getSelectionsByIdsMock($selectionIds, $productMock, 5, 6); $selectionMock->expects(($this->any())) - ->method('getItems') - ->will($this->returnValue([$selectionItemMock])); - $selectionItemMock->expects($this->any()) + ->method('getItemByColumnValue') + ->will($this->returnValue($selectionItemMock)); + $selectionItemMock->expects($this->at(0)) + ->method('getEntityId') + ->will($this->returnValue(1)); + $selectionItemMock->expects($this->once()) ->method('getSku') ->will($this->returnValue($itemSku)); From c0bfa9b826ce30ee9ec33cd42fe03cdf57bcd5f7 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Tue, 13 Nov 2018 17:41:52 +0200 Subject: [PATCH 45/49] MAGETWO-96288: [Magento Cloud] Cannot update category positions via REST API --- .../Model/Category/Link/SaveHandlerTest.php | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php new file mode 100644 index 0000000000000..f8644c20335f5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php @@ -0,0 +1,116 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Model\Category\Link; + +use Magento\Catalog\Api\Data\CategoryLinkInterfaceFactory; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * @magentoDataFixture Magento/Catalog/_files/categories_no_products.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + */ +class SaveHandlerTest extends TestCase +{ + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var string + */ + private $productLinkField; + + /** + * @var CategoryLinkInterfaceFactory + */ + private $categoryLinkFactory; + + /** + * @var SaveHandler + */ + private $saveHandler; + + protected function setUp() + { + $this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class); + $metadataPool = Bootstrap::getObjectManager()->create(MetadataPool::class); + $this->productLinkField = $metadataPool->getMetadata(ProductInterface::class)->getLinkField(); + $this->categoryLinkFactory = Bootstrap::getObjectManager()->create(CategoryLinkInterfaceFactory::class); + $this->saveHandler = Bootstrap::getObjectManager()->create(SaveHandler::class); + } + + public function testExecute() + { + $product = $this->productRepository->get('simple2'); + $product->setCategoryIds([3, 4, 6]); + $this->productRepository->save($product); + $categoryPositions = [ + 3 => [ + 'category_id' => 3, + 'position' => 0, + ], + 4 => [ + 'category_id' => 4, + 'position' => 0, + ], + 6 => [ + 'category_id' => 6, + 'position' => 0, + ], + ]; + + $categoryLinks = $product->getExtensionAttributes()->getCategoryLinks(); + $this->assertEmpty($categoryLinks); + + $categoryLinks = []; + $categoryPositions[4]['position'] = 1; + $categoryPositions[6]['position'] = 1; + foreach ($categoryPositions as $categoryPosition) { + $categoryLink = $this->categoryLinkFactory->create() + ->setCategoryId($categoryPosition['category_id']) + ->setPosition($categoryPosition['position']); + $categoryLinks[] = $categoryLink; + } + $categoryLinks = $this->updateCategoryLinks($product, $categoryLinks); + foreach ($categoryLinks as $categoryLink) { + $categoryPosition = $categoryPositions[$categoryLink->getCategoryId()]; + $this->assertEquals($categoryPosition['category_id'], $categoryLink->getCategoryId()); + $this->assertEquals($categoryPosition['position'], $categoryLink->getPosition()); + } + + $categoryPositions[4]['position'] = 2; + $categoryLink = $this->categoryLinkFactory->create() + ->setCategoryId(4) + ->setPosition($categoryPositions[4]['position']); + $categoryLinks = $this->updateCategoryLinks($product, [$categoryLink]); + foreach ($categoryLinks as $categoryLink) { + $categoryPosition = $categoryPositions[$categoryLink->getCategoryId()]; + $this->assertEquals($categoryPosition['category_id'], $categoryLink->getCategoryId()); + $this->assertEquals($categoryPosition['position'], $categoryLink->getPosition()); + } + } + + /** + * @param ProductInterface $product + * @param \Magento\Catalog\Api\Data\CategoryLinkInterface[] $categoryLinks + * @return \Magento\Catalog\Api\Data\CategoryLinkInterface[] + */ + private function updateCategoryLinks(ProductInterface $product, array $categoryLinks): array + { + $product->getExtensionAttributes()->setCategoryLinks($categoryLinks); + $arguments = [$this->productLinkField => $product->getData($this->productLinkField)]; + $this->saveHandler->execute($product, $arguments); + $product = $this->productRepository->get($product->getSku(), false, null, true); + $categoryLinks = $product->getExtensionAttributes()->getCategoryLinks(); + + return $categoryLinks; + } +} From af6f54f784d6392b5f36d72c672721eaa6fd3831 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <horytsky@adobe.com> Date: Wed, 14 Nov 2018 10:02:09 +0200 Subject: [PATCH 46/49] MAGETWO-96288: [Magento Cloud] Cannot update category positions via REST API --- .../Magento/Catalog/Model/Category/Link/SaveHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php index f8644c20335f5..cbf195f5829c9 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Category/Link/SaveHandlerTest.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Catalog\Model\Category\Link; +namespace Magento\Catalog\Model\Category\Link; use Magento\Catalog\Api\Data\CategoryLinkInterfaceFactory; use Magento\Catalog\Api\Data\ProductInterface; From 93e08a710bb5c9c94a62f4a0d7a3d02ad9fef673 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Wed, 14 Nov 2018 10:47:46 +0200 Subject: [PATCH 47/49] MAGETWO-73140: Anchor categories are showing products of disabled subcategories - Change temporary table --- .../Category/Product/AbstractAction.php | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index 5375faa9d9cd1..021276c674b6c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -126,6 +126,12 @@ abstract class AbstractAction */ private $queryGenerator; + /** + * Current store id. + * @var int + */ + private $currentStoreId = 0; + /** * @param ResourceConnection $resource * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -167,6 +173,7 @@ protected function reindex() { foreach ($this->storeManager->getStores() as $store) { if ($this->getPathFromCategoryId($store->getRootCategoryId())) { + $this->currentStoreId = $store->getId(); $this->reindexRootCategory($store); $this->reindexAnchorCategories($store); $this->reindexNonAnchorCategories($store); @@ -594,7 +601,7 @@ protected function getTemporaryTreeIndexTableName() if (empty($this->tempTreeIndexTableName)) { $this->tempTreeIndexTableName = $this->connection->getTableName('temp_catalog_category_tree_index') . '_' - . substr(md5(time() . random_int(0, 999999999)), 0, 8); + . substr(sha1(time() . random_int(0, 999999999)), 0, 8); } return $this->tempTreeIndexTableName; @@ -649,30 +656,47 @@ protected function makeTempCategoryTreeIndex() } /** - * Populate the temporary category tree index table + * Populate the temporary category tree index table. * * @param string $temporaryName + * @return void * @since 101.0.0 */ protected function fillTempCategoryTreeIndex($temporaryName) { - $offset = 0; - $limit = 500; - - $categoryTable = $this->getTable('catalog_category_entity'); - - $categoriesSelect = $this->connection->select() - ->from( - ['c' => $categoryTable], - ['entity_id', 'path'] - )->limit($limit, $offset); - - $categories = $this->connection->fetchAll($categoriesSelect); + $isActiveAttributeId = $this->config->getAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'is_active' + )->getId(); + $categoryMetadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\CategoryInterface::class); + $categoryLinkField = $categoryMetadata->getLinkField(); + $selects = $this->prepareSelectsByRange( + $this->connection->select() + ->from( + ['c' => $this->getTable('catalog_category_entity')], + ['entity_id', 'path'] + )->joinInner( + ['ccacd' => $this->getTable('catalog_category_entity_int')], + 'ccacd.' . $categoryLinkField . ' = c.' . $categoryLinkField + . ' AND ccacd.store_id = 0' . ' AND ccacd.attribute_id = ' . $isActiveAttributeId, + [] + )->joinLeft( + ['ccacs' => $this->getTable('catalog_category_entity_int')], + 'ccacs.' . $categoryLinkField . ' = c.' . $categoryLinkField + . ' AND ccacs.attribute_id = ccacd.attribute_id AND ccacs.store_id = ' + . $this->currentStoreId, + [] + )->where( + $this->connection->getIfNullSql('ccacs.value', 'ccacd.value') . ' = ?', + 1 + ), + 'entity_id' + ); - while ($categories) { + foreach ($selects as $select) { $values = []; - foreach ($categories as $category) { + foreach ($this->connection->fetchAll($select) as $category) { foreach (explode('/', $category['path']) as $parentId) { if ($parentId !== $category['entity_id']) { $values[] = [$parentId, $category['entity_id']]; @@ -683,15 +707,6 @@ protected function fillTempCategoryTreeIndex($temporaryName) if (count($values) > 0) { $this->connection->insertArray($temporaryName, ['parent_id', 'child_id'], $values); } - - $offset += $limit; - $categoriesSelect = $this->connection->select() - ->from( - ['c' => $categoryTable], - ['entity_id', 'path'] - )->limit($limit, $offset); - - $categories = $this->connection->fetchAll($categoriesSelect); } } From 45c254277a6304e9bee594cd2c4d8fda70cd6eea Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 14 Nov 2018 17:01:49 +0200 Subject: [PATCH 48/49] MAGETWO-86120: [2.2] Gift message selection does not display in shopping cart --- .../GiftMessage/view/frontend/web/js/view/gift-message.js | 5 ++--- .../Mftf/Test/StorefrontGuestCheckoutDisabledProductTest.xml | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js b/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js index d025f6974f35e..4c455c83a77a9 100644 --- a/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js +++ b/app/code/Magento/GiftMessage/view/frontend/web/js/view/gift-message.js @@ -31,8 +31,9 @@ define([ this.itemId = this.itemId || 'orderLevel'; model = new GiftMessage(this.itemId); - giftOptions.addOption(model); this.model = model; + this.isResultBlockVisible(); + giftOptions.addOption(model); this.model.getObservable('isClear').subscribe(function (value) { if (value == true) { //eslint-disable-line eqeqeq @@ -40,8 +41,6 @@ define([ self.model.getObservable('alreadyAdded')(true); } }); - - this.isResultBlockVisible(); }, /** diff --git a/app/code/Magento/Quote/Test/Mftf/Test/StorefrontGuestCheckoutDisabledProductTest.xml b/app/code/Magento/Quote/Test/Mftf/Test/StorefrontGuestCheckoutDisabledProductTest.xml index 0c20eb54d5446..a2f08353a4f3b 100644 --- a/app/code/Magento/Quote/Test/Mftf/Test/StorefrontGuestCheckoutDisabledProductTest.xml +++ b/app/code/Magento/Quote/Test/Mftf/Test/StorefrontGuestCheckoutDisabledProductTest.xml @@ -103,6 +103,7 @@ <click selector="{{AdminProductGridSection.firstRow}}" stepKey="clickOnProductPage"/> <waitForPageLoad stepKey="waitForProductPageLoad"/> <!-- Disabled child configurable product --> + <scrollToTopOfPage stepKey="scrollToShowEnableDisableControl"/> <click selector="{{AdminProductFormSection.enableProductAttributeLabel}}" stepKey="clickDisableProduct"/> <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveProduct"/> <waitForPageLoad stepKey="waitForProductPageSaved"/> From dae72c6f47f8dca699a5489db1a31b5e90f091e6 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Thu, 15 Nov 2018 08:49:29 +0200 Subject: [PATCH 49/49] MAGETWO-87985: Unit test changes --- .../DataProvider/Product/Form/Modifier/AbstractModifierTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php index 473f1aea33618..7a86f806abd26 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Form/Modifier/AbstractModifierTest.php @@ -67,7 +67,7 @@ protected function setUp() 'isLockedAttribute' ])->getMockForAbstractClass(); $this->storeMock = $this->getMockBuilder(StoreInterface::class) - ->setMethods(['load', 'getId', 'getConfig']) + ->setMethods(['load', 'getId', 'getConfig', 'getBaseCurrency', 'getBaseCurrencyCode']) ->getMockForAbstractClass(); $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) ->disableOriginalConstructor()