magento2-docker/dev/tests/api-functional/testsuite/Magento/GraphQl/Sales/CreditmemoTest.php

650 lines
25 KiB
PHP
Executable File

<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace Magento\GraphQl\Sales;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Exception\AuthenticationException;
use Magento\GraphQl\GetCustomerAuthenticationHeader;
use Magento\GraphQl\Sales\Fixtures\CustomerPlaceOrder;
use Magento\Sales\Api\CreditmemoRepositoryInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\CreditmemoFactory;
use Magento\Sales\Model\ResourceModel\Order\Collection as OrderCollection;
use Magento\Sales\Model\ResourceModel\Order\Creditmemo\Collection;
use Magento\Sales\Model\Service\CreditmemoService;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;
/**
* Test for credit memo functionality
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class CreditmemoTest extends GraphQlAbstract
{
/**
* @var GetCustomerAuthenticationHeader
*/
private $customerAuthenticationHeader;
/** @var CreditmemoFactory */
private $creditMemoFactory;
/** @var Order */
private $order;
/** @var OrderCollection */
private $orderCollection;
/** @var CreditmemoService */
private $creditMemoService;
/** @var ProductRepositoryInterface */
private $productRepository;
/** @var OrderRepositoryInterface */
private $orderRepository;
/** @var SearchCriteriaBuilder */
private $searchCriteriaBuilder;
/**
* Set up
*/
protected function setUp(): void
{
$objectManager = Bootstrap::getObjectManager();
$this->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 =
<<<QUERY
query {
customer {
orders {
items {
invoices {
items {
product_name
product_sku
product_sale_price {
value
}
... on BundleInvoiceItem {
bundle_options {
label
values {
product_sku
product_name
quantity
price {
value
currency
}
}
}
}
discounts { amount{value currency} label }
quantity_invoiced
discounts { amount{value currency} label }
}
}
credit_memos {
comments {
message
}
items {
product_name
product_sku
product_sale_price {
value
}
... on BundleCreditMemoItem {
bundle_options {
label
values {
product_sku
product_name
quantity
price {
value
currency
}
}
}
}
discounts { amount{value currency} label }
quantity_refunded
}
total {
subtotal {
value
}
base_grand_total {
value
currency
}
grand_total {
value
currency
}
total_shipping {
value
}
total_tax {
value
}
shipping_handling {
amount_including_tax{value}
amount_excluding_tax{value}
total_amount{value}
taxes {amount{value} title rate}
discounts {amount{value}}
}
adjustment {
value
}
}
}
}
}
}
}
QUERY;
$currentEmail = 'customer@example.com';
$currentPassword = 'password';
$response = $this->graphQlQuery(
$query,
[],
'',
$this->customerAuthenticationHeader->execute($currentEmail, $currentPassword)
);
return $response;
}
}