customerAuthenticationHeader = $objectManager->get( GetCustomerAuthenticationHeader::class ); $this->productRepository = $objectManager->get(ProductRepositoryInterface::class); $this->creditMemoFactory = $objectManager->get(CreditmemoFactory::class); $this->order = $objectManager->create(Order::class); $this->searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); $this->orderCollection = $objectManager->get(OrderCollection::class); $this->orderRepository = $objectManager->get(OrderRepositoryInterface::class); $this->creditMemoService = $objectManager->get(CreditmemoService::class); } protected function tearDown(): void { $this->cleanUpCreditMemos(); $this->deleteOrder(); } /** * @magentoApiDataFixture Magento/Sales/_files/customer_creditmemo_with_two_items.php * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testCreditMemoForLoggedInCustomerQuery(): void { $response = $this->getCustomerOrderWithCreditMemoQuery(); $expectedCreditMemoData = [ [ 'comments' => [ ['message' => 'some_comment'] ], 'items' => [ [ 'product_name' => 'Simple Related Product', 'product_sku' => 'simple', 'product_sale_price' => [ 'value' => 10 ], 'discounts' => [], 'quantity_refunded' => 1 ], [ 'product_name' => 'Simple Product With Related Product', 'product_sku' => 'simple_with_cross', 'product_sale_price' => [ 'value' => 10 ], 'discounts' => [], 'quantity_refunded' => 1 ] ], 'total' => [ 'subtotal' => [ 'value' => 20 ], 'grand_total' => [ 'value' => 20, 'currency' => 'USD' ], 'base_grand_total' => [ 'value' => 10, 'currency' => 'EUR' ], 'total_shipping' => [ 'value' => 0 ], 'total_tax' => [ 'value' => 0 ], 'shipping_handling' => [ 'amount_including_tax' => [ 'value' => 0 ], 'amount_excluding_tax' => [ 'value' => 0 ], 'total_amount' => [ 'value' => 0 ], 'taxes' => [], 'discounts' => [], ], 'adjustment' => [ 'value' => 1.23 ] ] ] ]; $firstOrderItem = current($response['customer']['orders']['items'] ?? []); $this->assertArrayHasKey('credit_memos', $firstOrderItem); $creditMemos = $firstOrderItem['credit_memos']; $this->assertResponseFields($creditMemos, $expectedCreditMemoData); } /** * Test customer refund details from order for bundle product with a partial refund * * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/Bundle/_files/bundle_product_two_dropdown_options.php * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testCreditMemoForBundledProductsWithPartialRefund() { //Place order with bundled product /** @var CustomerPlaceOrder $bundleProductOrderFixture */ $bundleProductOrderFixture = Bootstrap::getObjectManager()->create(CustomerPlaceOrder::class); $placeOrderResponse = $bundleProductOrderFixture->placeOrderWithBundleProduct( ['email' => 'customer@example.com', 'password' => 'password'], ['sku' => 'bundle-product-two-dropdown-options', 'quantity' => 2] ); $orderNumber = $placeOrderResponse['placeOrder']['order']['order_number']; $this->prepareInvoice($orderNumber, 2); $order = $this->order->loadByIncrementId($orderNumber); /** @var Order\Item $orderItem */ $orderItem = current($order->getAllItems()); $orderItem->setQtyRefunded(1); $order->addItem($orderItem); $order->save(); // Create a credit memo $creditMemo = $this->creditMemoFactory->createByOrder($order, $order->getData()); $creditMemo->setOrder($order); $creditMemo->setState(1); $creditMemo->setSubtotal(15); $creditMemo->setBaseSubTotal(15); $creditMemo->setShippingAmount(10); $creditMemo->setBaseGrandTotal(23); $creditMemo->setGrandTotal(23); $creditMemo->setAdjustment(-2.00); $creditMemo->addComment("Test comment for partial refund", false, true); $creditMemo->save(); $this->creditMemoService->refund($creditMemo, true); $response = $this->getCustomerOrderWithCreditMemoQuery(); $expectedInvoicesData = [ [ 'items' => [ [ 'product_name' => 'Bundle Product With Two dropdown options', 'product_sku' => 'bundle-product-two-dropdown-options-simple1-simple2', 'product_sale_price' => [ 'value' => 15 ], 'discounts' => [], 'bundle_options' => [ [ 'label' => 'Drop Down Option 1', 'values' => [ [ 'product_name' => 'Simple Product1', 'product_sku' => 'simple1', 'quantity' => 1, 'price' => ['value' => 1, 'currency' => 'USD'] ] ] ], [ 'label' => 'Drop Down Option 2', 'values' => [ [ 'product_name' => 'Simple Product2', 'product_sku' => 'simple2', 'quantity' => 2, 'price' => ['value' => 2, 'currency' => 'USD'] ] ] ] ], 'quantity_invoiced' => 2 ], ] ] ]; $expectedCreditMemoData = [ [ 'comments' => [ ['message' => 'Test comment for partial refund'] ], 'items' => [ [ 'product_name' => 'Bundle Product With Two dropdown options', 'product_sku' => 'bundle-product-two-dropdown-options-simple1-simple2', 'product_sale_price' => [ 'value' => 15 ], 'discounts' => [], 'bundle_options' => [ [ 'label' => 'Drop Down Option 1', 'values' => [ [ 'product_name' => 'Simple Product1', 'product_sku' => 'simple1', 'quantity' => 1, 'price' => ['value' => 1, 'currency' => 'USD'] ] ] ], [ 'label' => 'Drop Down Option 2', 'values' => [ [ 'product_name' => 'Simple Product2', 'product_sku' => 'simple2', 'quantity' => 2, 'price' => ['value' => 2, 'currency' => 'USD'] ] ] ] ], 'quantity_refunded' => 1 ], ], 'total' => [ 'subtotal' => [ 'value' => 15 ], 'grand_total' => [ 'value' => 23, 'currency' => 'USD' ], 'base_grand_total' => [ 'value' => 23, 'currency' => 'USD' ], 'total_shipping' => [ 'value' => 10 ], 'total_tax' => [ 'value' => 0 ], 'shipping_handling' => [ 'amount_including_tax' => [ 'value' => 10 ], 'amount_excluding_tax' => [ 'value' => 10 ], 'total_amount' => [ 'value' => 10 ], 'taxes' => [], 'discounts' => [], ], 'adjustment' => [ 'value' => 2 ] ] ] ]; $firstOrderItem = current($response['customer']['orders']['items'] ?? []); $this->assertArrayHasKey('invoices', $firstOrderItem); $invoices = $firstOrderItem['invoices']; $this->assertResponseFields($invoices, $expectedInvoicesData); $this->assertArrayHasKey('credit_memos', $firstOrderItem); $creditMemos = $firstOrderItem['credit_memos']; $this->assertResponseFields($creditMemos, $expectedCreditMemoData); } /** * Test customer order with credit memo details for bundle products with taxes and discounts * @magentoApiDataFixture Magento/Customer/_files/customer.php * @magentoApiDataFixture Magento/Bundle/_files/bundle_product_two_dropdown_options.php * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php * @magentoApiDataFixture Magento/SalesRule/_files/cart_rule_10_percent_off_with_discount_on_shipping.php * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_calculation_shipping_excludeTax_order_display_settings.php * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function testCreditMemoForBundleProductWithTaxesAndDiscounts() { //Place order with bundled product /** @var CustomerPlaceOrder $bundleProductOrderFixture */ $bundleProductOrderFixture = Bootstrap::getObjectManager()->create(CustomerPlaceOrder::class); $placeOrderResponse = $bundleProductOrderFixture->placeOrderWithBundleProduct( ['email' => 'customer@example.com', 'password' => 'password'], ['sku' => 'bundle-product-two-dropdown-options', 'quantity' => 2] ); $orderNumber = $placeOrderResponse['placeOrder']['order']['order_number']; $this->prepareInvoice($orderNumber, 2); $order = $this->order->loadByIncrementId($orderNumber); /** @var Order\Item $orderItem */ $orderItem = current($order->getAllItems()); $orderItem->setQtyRefunded(1); $order->addItem($orderItem); $order->save(); $creditMemo = $this->creditMemoFactory->createByOrder($order, $order->getData()); $creditMemo->setOrder($order); $creditMemo->setState(1); $creditMemo->setSubtotal(15); $creditMemo->setBaseSubTotal(15); $creditMemo->setShippingAmount(10); $creditMemo->setTaxAmount(1.69); $creditMemo->setBaseGrandTotal(24.19); $creditMemo->setGrandTotal(24.19); $creditMemo->setAdjustment(0.00); $creditMemo->setDiscountAmount(-2.5); $creditMemo->setDiscountDescription('Discount Label for 10% off'); $creditMemo->addComment("Test comment for refund with taxes and discount", false, true); $creditMemo->save(); $this->creditMemoService->refund($creditMemo, true); $response = $this->getCustomerOrderWithCreditMemoQuery(); $expectedCreditMemoData = [ [ 'comments' => [ ['message' => 'Test comment for refund with taxes and discount'] ], 'items' => [ [ 'product_name' => 'Bundle Product With Two dropdown options', 'product_sku' => 'bundle-product-two-dropdown-options-simple1-simple2', 'product_sale_price' => [ 'value' => 15 ], 'discounts' => [ [ 'amount' => [ 'value' => 3, 'currency' => "USD" ], 'label' => 'Discount Label for 10% off' ] ], 'bundle_options' => [ [ 'label' => 'Drop Down Option 1', 'values' => [ [ 'product_name' => 'Simple Product1', 'product_sku' => 'simple1', 'quantity' => 1, 'price' => ['value' => 1, 'currency' => 'USD'] ] ] ], [ 'label' => 'Drop Down Option 2', 'values' => [ [ 'product_name' => 'Simple Product2', 'product_sku' => 'simple2', 'quantity' => 2, 'price' => ['value' => 2, 'currency' => 'USD'] ] ] ] ], 'quantity_refunded' => 1 ], ], 'total' => [ 'subtotal' => [ 'value' => 15 ], 'grand_total' => [ 'value' => 24.19, 'currency' => 'USD' ], 'base_grand_total' => [ 'value' => 24.19, 'currency' => 'USD' ], 'total_shipping' => [ 'value' => 10 ], 'total_tax' => [ 'value'=> 1.69 ], 'shipping_handling' => [ 'amount_including_tax' => [ 'value' => 10.75 ], 'amount_excluding_tax' => [ 'value' => 10 ], 'total_amount' => [ 'value' => 10 ], 'taxes'=> [ 0 => [ 'amount' => ['value' => 0.67], 'title' => 'US-TEST-*-Rate-1', 'rate' => 7.5 ] ], 'discounts' => [ [ 'amount'=> ['value'=> 1] ] ], ], 'adjustment' => [ 'value' => 0 ] ] ] ]; $firstOrderItem = current($response['customer']['orders']['items'] ?? []); $this->assertArrayHasKey('credit_memos', $firstOrderItem); $creditMemos = $firstOrderItem['credit_memos']; $this->assertResponseFields($creditMemos, $expectedCreditMemoData); } /** * Prepare invoice for the order * * @param string $orderNumber * @param int|null $qty */ private function prepareInvoice(string $orderNumber, int $qty = null) { /** @var \Magento\Sales\Model\Order $order */ $order = Bootstrap::getObjectManager() ->create(\Magento\Sales\Model\Order::class)->loadByIncrementId($orderNumber); $orderItem = current($order->getItems()); $orderService = Bootstrap::getObjectManager()->create( \Magento\Sales\Api\InvoiceManagementInterface::class ); $invoice = $orderService->prepareInvoice($order, [$orderItem->getId() => $qty]); $invoice->register(); $order = $invoice->getOrder(); $order->setIsInProcess(true); $transactionSave = Bootstrap::getObjectManager() ->create(\Magento\Framework\DB\Transaction::class); $transactionSave->addObject($invoice)->addObject($order)->save(); } /** * @return void */ private function deleteOrder(): void { /** @var \Magento\Framework\Registry $registry */ $registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); $registry->unregister('isSecureArea'); $registry->register('isSecureArea', true); /** @var $order \Magento\Sales\Model\Order */ $orderCollection = Bootstrap::getObjectManager()->create(OrderCollection::class); foreach ($orderCollection as $order) { $this->orderRepository->delete($order); } $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); } /** * @return void */ private function cleanUpCreditMemos(): void { /** @var \Magento\Framework\Registry $registry */ $registry = Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class); $registry->unregister('isSecureArea'); $registry->register('isSecureArea', true); $creditmemoRepository = Bootstrap::getObjectManager()->get(CreditmemoRepositoryInterface::class); $creditmemoCollection = Bootstrap::getObjectManager()->create(Collection::class); foreach ($creditmemoCollection as $creditmemo) { $creditmemoRepository->delete($creditmemo); } $registry->unregister('isSecureArea'); $registry->register('isSecureArea', false); } /** * Get CustomerOrder with credit memo details * * @return array * @throws AuthenticationException * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ private function getCustomerOrderWithCreditMemoQuery(): array { $query = <<graphQlQuery( $query, [], '', $this->customerAuthenticationHeader->execute($currentEmail, $currentPassword) ); return $response; } }