Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MC-33893: 2.3.4 Invoice always sent (if exist) when order placed #32580

Merged
merged 5 commits into from
Mar 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions app/code/Magento/Quote/Observer/SendInvoiceEmailObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
zakdma marked this conversation as resolved.
Show resolved Hide resolved
declare(strict_types=1);

namespace Magento\Quote\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Quote\Model\Quote;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Email\Container\InvoiceIdentity;
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
use Psr\Log\LoggerInterface;

/**
* Class responsive for sending invoice emails when order created through storefront.
*/
class SendInvoiceEmailObserver implements ObserverInterface
{
/**
* @var LoggerInterface
*/
private $logger;

/**
* @var InvoiceSender
*/
private $invoiceSender;

/**
* @var InvoiceIdentity
*/
private $invoiceIdentity;

/**
* @param LoggerInterface $logger
* @param InvoiceSender $invoiceSender
* @param InvoiceIdentity $invoiceIdentity
*/
public function __construct(
LoggerInterface $logger,
InvoiceSender $invoiceSender,
InvoiceIdentity $invoiceIdentity
) {
$this->logger = $logger;
$this->invoiceSender = $invoiceSender;
$this->invoiceIdentity = $invoiceIdentity;
}

/**
* Send invoice email if allowed.
*
* @param Observer $observer
*
* @return void
*/
public function execute(Observer $observer)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify return type to method.

Suggested change
public function execute(Observer $observer)
public function execute(Observer $observer): void

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not allowed to do that because declared interface method ObserverInterface::execute() have no such return type hinting.

{
if (!$this->isInvoiceEmailAllowed()) {
return;
}

/** @var Quote $quote */
$quote = $observer->getEvent()->getQuote();
/** @var Order $order */
$order = $observer->getEvent()->getOrder();

/**
* a flag to set that there will be redirect to third party after confirmation
*/
$redirectUrl = $quote->getPayment()->getOrderPlaceRedirectUrl();
if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
try {
$invoice = current($order->getInvoiceCollection()->getItems());
if ($invoice) {
$this->invoiceSender->send($invoice);
}
} catch (\Throwable $e) {
$this->logger->critical($e);
}
}
}

/**
* Is invoice email sending enabled
*
* @return bool
*/
private function isInvoiceEmailAllowed(): bool
{
return $this->invoiceIdentity->isEnabled();
}
}
21 changes: 4 additions & 17 deletions app/code/Magento/Quote/Observer/SubmitObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
use Magento\Framework\Event\ObserverInterface;
use Magento\Quote\Model\Quote;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
use Psr\Log\LoggerInterface;

/**
* Class responsive for sending order and invoice emails when it's created through storefront.
* Class responsive for sending order emails when it's created through storefront.
*/
class SubmitObserver implements ObserverInterface
{
Expand All @@ -28,28 +27,20 @@ class SubmitObserver implements ObserverInterface
*/
private $orderSender;

/**
* @var InvoiceSender
*/
private $invoiceSender;

/**
* @param LoggerInterface $logger
* @param OrderSender $orderSender
* @param InvoiceSender $invoiceSender
*/
public function __construct(
LoggerInterface $logger,
OrderSender $orderSender,
InvoiceSender $invoiceSender
OrderSender $orderSender
) {
$this->logger = $logger;
$this->orderSender = $orderSender;
$this->invoiceSender = $invoiceSender;
}

/**
* Send order and invoice email.
* Send order email.
*
* @param Observer $observer
*
Expand All @@ -69,11 +60,7 @@ public function execute(Observer $observer)
if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
try {
$this->orderSender->send($order);
$invoice = current($order->getInvoiceCollection()->getItems());
if ($invoice) {
$this->invoiceSender->send($invoice);
}
} catch (\Exception $e) {
} catch (\Throwable $e) {
$this->logger->critical($e);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Quote\Test\Unit\Observer;

use Magento\Framework\Event;
use Magento\Framework\Event\Observer;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\Quote\Payment;
use Magento\Quote\Observer\SubmitObserver;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
use Magento\Sales\Model\Order\Invoice;
use Magento\Sales\Model\ResourceModel\Order\Invoice\Collection;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Magento\Sales\Model\Order\Email\Container\InvoiceIdentity;
use Magento\Quote\Observer\SendInvoiceEmailObserver;

/**
* Test for sending invoice email during order place on frontend
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class SendInvoiceEmailObserverTest extends TestCase
{
/**
* @var SendInvoiceEmailObserver
*/
private $model;

/**
* @var LoggerInterface|MockObject
*/
private $loggerMock;

/**
* @var InvoiceSender|MockObject
*/
private $invoiceSenderMock;

/**
* @var InvoiceIdentity|MockObject
*/
private $invoiceIdentityMock;

/**
* @var Observer|MockObject
*/
private $observerMock;

/**
* @var Quote|MockObject
*/
private $quoteMock;

/**
* @var Order|MockObject
*/
private $orderMock;

/**
* @var Payment|MockObject
*/
private $paymentMock;

/**
* @inheirtDoc
*/
protected function setUp(): void
{
$this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
$this->quoteMock = $this->createMock(Quote::class);
$this->orderMock = $this->createMock(Order::class);
$this->paymentMock = $this->createMock(Payment::class);
$this->invoiceSenderMock = $this->createMock(InvoiceSender::class);
$this->invoiceIdentityMock = $this->getMockBuilder(InvoiceIdentity::class)
->disableOriginalConstructor()
->setMethods(['isEnabled'])
->getMock();
$eventMock = $this->getMockBuilder(Event::class)
->disableOriginalConstructor()
->setMethods(['getQuote', 'getOrder'])
->getMock();
$this->observerMock = $this->createPartialMock(Observer::class, ['getEvent']);
$this->observerMock->expects($this->any())->method('getEvent')->willReturn($eventMock);
$eventMock->expects($this->any())->method('getQuote')->willReturn($this->quoteMock);
$eventMock->expects($this->any())->method('getOrder')->willReturn($this->orderMock);
$this->quoteMock->expects($this->any())->method('getPayment')->willReturn($this->paymentMock);
$this->model = new SendInvoiceEmailObserver(
$this->loggerMock,
$this->invoiceSenderMock,
$this->invoiceIdentityMock
);
}

/**
* Tests successful email sending.
*/
public function testSendEmail()
{
$this->invoiceIdentityMock
->expects($this->once())
->method('isEnabled')
->willReturn(true);

$this->paymentMock->method('getOrderPlaceRedirectUrl')->willReturn('');

$invoice = $this->createMock(Invoice::class);
$invoiceCollection = $this->createMock(Collection::class);
$invoiceCollection->method('getItems')
->willReturn([$invoice]);
$this->orderMock->method('getInvoiceCollection')
->willReturn($invoiceCollection);
$this->quoteMock
->expects($this->any())
->method('getPayment')
->willReturn($this->paymentMock);

$this->orderMock->method('getCanSendNewEmailFlag')->willReturn(true);
$this->invoiceSenderMock->expects($this->once())
->method('send')
->with($invoice)
->willReturn(true);
$this->loggerMock->expects($this->never())
->method('critical');

$this->model->execute($this->observerMock);
}

/**
* Tests email sending disabled by configuration.
*/
public function testSendEmailDisabled()
{
$this->invoiceIdentityMock
->expects($this->once())
->method('isEnabled')
->willReturn(false);

$this->paymentMock
->expects($this->never())
->method('getOrderPlaceRedirectUrl');
$this->orderMock
->expects($this->never())
->method('getInvoiceCollection');

$this->quoteMock
->expects($this->never())
->method('getPayment');

$this->orderMock
->expects($this->never())
->method('getCanSendNewEmailFlag');
$this->loggerMock->expects($this->never())
->method('critical');

$this->model->execute($this->observerMock);
}

/**
* Tests failing email sending.
*/
public function testFailToSendEmail()
{
$this->invoiceIdentityMock
->expects($this->once())
->method('isEnabled')
->willReturn(true);
$this->paymentMock->expects($this->once())->method('getOrderPlaceRedirectUrl')->willReturn('');

$invoice = $this->createMock(Invoice::class);
$invoiceCollection = $this->createMock(Collection::class);
$invoiceCollection->method('getItems')
->willReturn([$invoice]);
$this->orderMock->method('getInvoiceCollection')
->willReturn($invoiceCollection);

$this->orderMock->expects($this->once())->method('getCanSendNewEmailFlag')->willReturn(true);
$this->invoiceSenderMock->expects($this->once())->method('send')->willThrowException(
new \Exception('Some email sending Error')
);
$this->loggerMock->expects($this->once())->method('critical');
$this->model->execute($this->observerMock);
}

/**
* Tests send email when redirect.
*/
public function testSendEmailWhenRedirectUrlExists()
{
$this->invoiceIdentityMock
->expects($this->once())
->method('isEnabled')
->willReturn(true);

$this->paymentMock->expects($this->once())->method('getOrderPlaceRedirectUrl')->willReturn(false);
$this->orderMock->expects($this->once())->method('getCanSendNewEmailFlag');
$this->invoiceSenderMock->expects($this->never())->method('send');
$this->loggerMock->expects($this->never())->method('critical');
$this->model->execute($this->observerMock);
}
}
Loading