From 34ecd22341ba95e13c6dd7407dd74d6b20318487 Mon Sep 17 00:00:00 2001
From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com>
Date: Tue, 5 Jan 2021 18:44:58 +0200
Subject: [PATCH 1/2] Fix and test coverage

---
 .../Sales/Model/Order/Invoice/Total/Tax.php   |  9 +-
 ...eInvoiceWithZeroGrandTotalCheckoutTest.xml | 82 +++++++++++++++++++
 .../Test/Mftf/Data/SalesRuleData.xml          |  4 +
 3 files changed, 93 insertions(+), 2 deletions(-)
 create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/CreateInvoiceWithZeroGrandTotalCheckoutTest.xml

diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
index 6e12f10f0c679..2d024633aa3c3 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
@@ -118,8 +118,13 @@ public function collect(\Magento\Sales\Model\Order\Invoice $invoice)
         $invoice->setDiscountTaxCompensationAmount($taxDiscountCompensationAmt);
         $invoice->setBaseDiscountTaxCompensationAmount($baseTaxDiscountCompensationAmt);
 
-        $invoice->setGrandTotal($invoice->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation);
-        $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation);
+        $grandTotal = $invoice->getGrandTotal() + $invoice->getDiscountAmount() < 0.0001
+            ? 0 : $invoice->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation;
+        $baseGrandTotal = $invoice->getBaseGrandTotal() + $invoice->getBaseDiscountAmount() < 0.0001
+            ? 0 : $invoice->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation;
+
+        $invoice->setGrandTotal($grandTotal);
+        $invoice->setBaseGrandTotal($baseGrandTotal);
 
         return $this;
     }
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateInvoiceWithZeroGrandTotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateInvoiceWithZeroGrandTotalCheckoutTest.xml
new file mode 100644
index 0000000000000..a1420c73c2420
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateInvoiceWithZeroGrandTotalCheckoutTest.xml
@@ -0,0 +1,82 @@
+<?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="CreateInvoiceWithZeroGrandTotalCheckoutTest">
+        <annotations>
+            <stories value="Create Invoice for Offline Payment Methods"/>
+            <title value="Create invoice with zero grandTotal checkout test"/>
+            <description value="Create invoice with with zero grandTotal checkout"/>
+            <severity value="CRITICAL"/>
+            <testCaseId value="MC-*"/>
+            <group value="sales"/>
+            <group value="mtf_migrated"/>
+        </annotations>
+        <before>
+            <createData entity="Simple_US_Customer_CA" stepKey="createCustomer"/>
+            <createData entity="SimpleProduct2" stepKey="createSimpleProduct">
+                <field key="price">10</field>
+            </createData>
+            <!-- Create sales rule discount 100% with coupon -->
+            <createData entity="SalesRuleSpecificCouponWithHundredPercentDiscount" stepKey="createCartPriceRule"/>
+            <createData entity="SimpleSalesRuleCoupon" stepKey="createCouponForCartPriceRule">
+                <requiredEntity createDataKey="createCartPriceRule"/>
+            </createData>
+            <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShippingMethod"/>
+            <!-- Catalog Prices and Apply Discount On Prices switched to Including Tax -->
+            <magentoCLI command="config:set tax/calculation/price_includes_tax 1"  stepKey="setCatalogPriceConfigToIncludingTax"/>
+            <magentoCLI command="config:set tax/calculation/discount_tax 1"  stepKey="setApplyDiscountOnPricesConfigToIncludingTax"/>
+            <!--Create tax rate for US-CA-*-->
+            <createData entity="defaultTaxRate" stepKey="taxRate"/>
+            <!-- Login as admin -->
+            <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/>
+            <!--Create tax rule-->
+            <actionGroup ref="AdminCreateTaxRuleActionGroup" stepKey="createTaxRule">
+                <argument name="taxRate" value="$$taxRate$$"/>
+                <argument name="taxRule" value="SimpleTaxRule"/>
+            </actionGroup>
+        </before>
+        <after>
+            <actionGroup ref="AdminDeleteTaxRule" stepKey="deleteTaxRule">
+                <argument name="taxRuleCode" value="{{SimpleTaxRule.code}}" />
+            </actionGroup>
+            <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
+            <deleteData createDataKey="taxRate" stepKey="deleteTaxRate"/>
+            <createData entity="FreeShippinMethodDefault" stepKey="disableFreeShippingMethod"/>
+            <deleteData createDataKey="createCartPriceRule" stepKey="deleteCartPriceRule"/>
+            <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/>
+            <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/>
+            <!-- Catalog Prices and Apply Discount On Prices switched to Excluding Tax -->
+            <magentoCLI command="config:set tax/calculation/price_includes_tax 0"  stepKey="setCatalogPriceConfigToExcludingTax"/>
+            <magentoCLI command="config:set tax/calculation/discount_tax 0"  stepKey="setApplyDiscountOnPricesConfigToExcludingTax"/>
+        </after>
+        <!-- Create order -->
+        <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="goToCreateOrderPage">
+            <argument name="customer" value="$$createCustomer$$"/>
+        </actionGroup>
+        <actionGroup ref="AddSimpleProductToOrderActionGroup" stepKey="addProductToOrder">
+            <argument name="product" value="$$createSimpleProduct$$"/>
+        </actionGroup>
+        <actionGroup ref="AdminApplyCouponToOrderActionGroup" stepKey="applyCoupon">
+            <argument name="couponCode" value="$$createCouponForCartPriceRule.code$$"/>
+        </actionGroup>
+        <actionGroup ref="OrderSelectFreeShippingActionGroup" stepKey="selectFreeShippingOption"/>
+        <actionGroup ref="AdminSubmitOrderActionGroup" stepKey="submitOrder"/>
+        <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId"/>
+        <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="goToOrdersPage"/>
+        <actionGroup ref="FilterOrderGridByIdActionGroup" stepKey="filterOrdersGridById">
+            <argument name="orderId" value="$getOrderId"/>
+        </actionGroup>
+        <click selector="{{AdminDataGridTableSection.firstRow}}" stepKey="openFilteredOrder"/>
+        <actionGroup ref="AdminClickInvoiceButtonOrderViewActionGroup" stepKey="clickInvoiceTab"/>
+        <!-- Check that invoice item row total and order grand total are equal zero -->
+        <see selector="{{AdminInvoiceTotalSection.itemTotalPrice}}" userInput="$0.00" stepKey="seeCorrectItemRowTotal"/>
+        <see selector="{{AdminInvoiceTotalSection.grandTotal}}" userInput="$0.00" stepKey="seeCorrectOrderGrandTotal"/>
+    </test>
+</tests>
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml
index 4a39e1237841d..10f2cb0dd4726 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml
@@ -197,6 +197,10 @@
         <data key="simple_free_shipping">1</data>
     </entity>
 
+    <entity name="SalesRuleSpecificCouponWithHundredPercentDiscount" extends="SalesRuleSpecificCouponWithPercentDiscount">
+        <data key="discount_amount">100</data>
+    </entity>
+
     <entity name="ActiveSalesRuleForNotLoggedIn" type="SalesRule">
         <data key="name" unique="suffix">SimpleSalesRule</data>
         <data key="description">Sales Rule Description</data>

From 3d100eb48ca679c0195824a0c129d44dc2970efd Mon Sep 17 00:00:00 2001
From: Gabriel Galvao da Gama <galvaoda@adobe.com>
Date: Wed, 31 Mar 2021 12:27:00 +0100
Subject: [PATCH 2/2] Set discount as last totals collector

---
 app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php | 9 ++-------
 app/code/Magento/Sales/etc/sales.xml                     | 4 ++--
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
index 2d024633aa3c3..6e12f10f0c679 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Total/Tax.php
@@ -118,13 +118,8 @@ public function collect(\Magento\Sales\Model\Order\Invoice $invoice)
         $invoice->setDiscountTaxCompensationAmount($taxDiscountCompensationAmt);
         $invoice->setBaseDiscountTaxCompensationAmount($baseTaxDiscountCompensationAmt);
 
-        $grandTotal = $invoice->getGrandTotal() + $invoice->getDiscountAmount() < 0.0001
-            ? 0 : $invoice->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation;
-        $baseGrandTotal = $invoice->getBaseGrandTotal() + $invoice->getBaseDiscountAmount() < 0.0001
-            ? 0 : $invoice->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation;
-
-        $invoice->setGrandTotal($grandTotal);
-        $invoice->setBaseGrandTotal($baseGrandTotal);
+        $invoice->setGrandTotal($invoice->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation);
+        $invoice->setBaseGrandTotal($invoice->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation);
 
         return $this;
     }
diff --git a/app/code/Magento/Sales/etc/sales.xml b/app/code/Magento/Sales/etc/sales.xml
index 203412a2cfd49..9635ede469a2f 100644
--- a/app/code/Magento/Sales/etc/sales.xml
+++ b/app/code/Magento/Sales/etc/sales.xml
@@ -9,21 +9,21 @@
     <section name="order_invoice">
         <group name="totals">
             <item name="subtotal" instance="Magento\Sales\Model\Order\Invoice\Total\Subtotal" sort_order="50"/>
-            <item name="discount" instance="Magento\Sales\Model\Order\Invoice\Total\Discount" sort_order="100"/>
             <item name="shipping" instance="Magento\Sales\Model\Order\Invoice\Total\Shipping" sort_order="150"/>
             <item name="tax" instance="Magento\Sales\Model\Order\Invoice\Total\Tax" sort_order="200"/>
             <item name="cost_total" instance="Magento\Sales\Model\Order\Invoice\Total\Cost" sort_order="250"/>
             <item name="grand_total" instance="Magento\Sales\Model\Order\Invoice\Total\Grand" sort_order="350"/>
+            <item name="discount" instance="Magento\Sales\Model\Order\Invoice\Total\Discount" sort_order="500"/>
         </group>
     </section>
     <section name="order_creditmemo">
         <group name="totals">
             <item name="subtotal" instance="Magento\Sales\Model\Order\Creditmemo\Total\Subtotal" sort_order="50"/>
-            <item name="discount" instance="Magento\Sales\Model\Order\Creditmemo\Total\Discount" sort_order="150"/>
             <item name="shipping" instance="Magento\Sales\Model\Order\Creditmemo\Total\Shipping" sort_order="200"/>
             <item name="tax" instance="Magento\Sales\Model\Order\Creditmemo\Total\Tax" sort_order="250"/>
             <item name="cost_total" instance="Magento\Sales\Model\Order\Creditmemo\Total\Cost" sort_order="300"/>
             <item name="grand_total" instance="Magento\Sales\Model\Order\Creditmemo\Total\Grand" sort_order="400"/>
+            <item name="discount" instance="Magento\Sales\Model\Order\Creditmemo\Total\Discount" sort_order="500"/>
         </group>
     </section>
     <order>