Skip to content

Commit 834c1e2

Browse files
ACQE-8964: Create Shipment for Offline Payment Methods with Async Notification
- Test to Create Shipment for Offline Payment Methods with Async Notification
1 parent d9a883c commit 834c1e2

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Sales\Model\Order\Email\Sender;
9+
10+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
11+
use Magento\Checkout\Test\Fixture\PlaceOrder as PlaceOrderFixture;
12+
use Magento\Checkout\Test\Fixture\SetBillingAddress as SetBillingAddressFixture;
13+
use Magento\Checkout\Test\Fixture\SetDeliveryMethod as SetDeliveryMethodFixture;
14+
use Magento\Checkout\Test\Fixture\SetGuestEmail as SetGuestEmailFixture;
15+
use Magento\Checkout\Test\Fixture\SetPaymentMethod as SetPaymentMethodFixture;
16+
use Magento\Checkout\Test\Fixture\SetShippingAddress as SetShippingAddressFixture;
17+
use Magento\Framework\App\Area;
18+
use Magento\Framework\Exception\LocalizedException;
19+
use Magento\Framework\Exception\MailException;
20+
use Magento\Framework\Mail\EmailMessageInterface;
21+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
22+
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
23+
use Magento\Sales\Api\InvoiceRepositoryInterface;
24+
use Magento\Sales\Api\OrderRepositoryInterface;
25+
use Magento\Sales\Model\Order;
26+
use Magento\Sales\Model\Service\InvoiceService;
27+
use Magento\Sales\Model\Order\ShipmentFactory;
28+
use Magento\Sales\Api\ShipmentRepositoryInterface;
29+
use Magento\Shipping\Model\ShipmentNotifier;
30+
use Magento\TestFramework\Fixture\Config;
31+
use Magento\TestFramework\Fixture\DataFixture;
32+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
33+
use Magento\TestFramework\Helper\Bootstrap;
34+
use Magento\TestFramework\Mail\Template\TransportBuilderMock;
35+
use PHPUnit\Framework\TestCase;
36+
37+
/**
38+
* Test shipment creation with async email notification.
39+
*/
40+
class AdminShipmentAsyncEmailTest extends TestCase
41+
{
42+
/**
43+
* @var TransportBuilderMock
44+
*/
45+
private TransportBuilderMock $transportBuilder;
46+
47+
/**
48+
* @var EmailMessageInterface[]
49+
*/
50+
private array $sentEmails = [];
51+
52+
protected function setUp(): void
53+
{
54+
parent::setUp();
55+
56+
$objectManager = Bootstrap::getObjectManager();
57+
$this->transportBuilder = $objectManager->get(TransportBuilderMock::class);
58+
$this->sentEmails = [];
59+
60+
$this->transportBuilder->setOnMessageSentCallback(
61+
function (EmailMessageInterface $message): void {
62+
$this->sentEmails[] = $message;
63+
}
64+
);
65+
}
66+
67+
/**
68+
* Ensures shipment emails created in async mode are dispatched only after the cron runs.
69+
*
70+
* @return void
71+
* @throws LocalizedException
72+
* @throws MailException
73+
*/
74+
#[
75+
Config('payment/checkmo/active', '1'),
76+
Config('carriers/flatrate/active', '1'),
77+
Config('sales_email/general/async_sending', '1'),
78+
Config('sales_email/shipment/enabled', '1'),
79+
Config('sales_email/general/sending_limit', '10'),
80+
DataFixture(ProductFixture::class, as: 'product'),
81+
DataFixture(GuestCartFixture::class, as: 'cart'),
82+
DataFixture(AddProductToCartFixture::class, ['cart_id' => '$cart.id$', 'product_id' => '$product.id$']),
83+
DataFixture(SetBillingAddressFixture::class, ['cart_id' => '$cart.id$']),
84+
DataFixture(SetShippingAddressFixture::class, ['cart_id' => '$cart.id$']),
85+
DataFixture(SetGuestEmailFixture::class, ['cart_id' => '$cart.id$', 'email' => 'async-shipment@example.com']),
86+
DataFixture(SetDeliveryMethodFixture::class, ['cart_id' => '$cart.id$']),
87+
DataFixture(SetPaymentMethodFixture::class, ['cart_id' => '$cart.id$', 'method' => 'checkmo']),
88+
DataFixture(PlaceOrderFixture::class, ['cart_id' => '$cart.id$'], 'order'),
89+
]
90+
public function testShipmentEmailDispatchedByCron(): void
91+
{
92+
Bootstrap::getInstance()->loadArea(Area::AREA_ADMINHTML);
93+
94+
$fixtures = DataFixtureStorageManager::getStorage();
95+
/** @var Order $fixtureOrder */
96+
$fixtureOrder = $fixtures->get('order');
97+
98+
$objectManager = Bootstrap::getObjectManager();
99+
$orderRepository = $objectManager->get(OrderRepositoryInterface::class);
100+
$invoiceService = $objectManager->get(InvoiceService::class);
101+
$invoiceRepository = $objectManager->get(InvoiceRepositoryInterface::class);
102+
$shipmentRepository = $objectManager->get(ShipmentRepositoryInterface::class);
103+
$shipmentNotifier = $objectManager->get(ShipmentNotifier::class);
104+
$shipmentFactory = $objectManager->get(ShipmentFactory::class);
105+
106+
$order = $orderRepository->get((int)$fixtureOrder->getEntityId());
107+
$this->assertTrue($order->canInvoice(), 'Order must be invoiceable before creating a shipment.');
108+
109+
$invoice = $invoiceService->prepareInvoice($order);
110+
$invoice->register();
111+
$invoice->setSendEmail(false);
112+
$invoiceRepository->save($invoice);
113+
$orderRepository->save($order);
114+
115+
$this->assertTrue($order->canShip(), 'Order must be shippable after invoicing.');
116+
117+
$quantities = [];
118+
foreach ($order->getAllItems() as $orderItem) {
119+
if ($orderItem->getIsVirtual()) {
120+
continue;
121+
}
122+
$qtyToShip = $orderItem->getQtyOrdered() - $orderItem->getQtyShipped();
123+
if ($qtyToShip > 0) {
124+
$quantities[$orderItem->getItemId()] = $qtyToShip;
125+
}
126+
}
127+
$this->assertNotEmpty($quantities, 'At least one shippable item is required.');
128+
129+
$shipment = $shipmentFactory->create($order, $quantities);
130+
$shipment->register();
131+
$shipment->setSendEmail(true);
132+
133+
$shipmentRepository->save($shipment);
134+
$orderRepository->save($shipment->getOrder());
135+
136+
$notifyResult = $shipmentNotifier->notify($shipment);
137+
$this->assertFalse(
138+
$notifyResult,
139+
'ShipmentNotifier::notify should return false while the email is queued for async sending.'
140+
);
141+
$this->assertCount(
142+
0,
143+
$this->sentEmails,
144+
'No shipment email should be dispatched immediately.'
145+
);
146+
147+
$cron = $objectManager->get('SalesShipmentSendEmailsCron');
148+
$cron->execute();
149+
$cron->execute();
150+
151+
$this->assertCount(
152+
1,
153+
$this->sentEmails,
154+
'One shipment email should be dispatched after cron execution.'
155+
);
156+
$email = $this->sentEmails[0];
157+
$this->assertInstanceOf(EmailMessageInterface::class, $email);
158+
$this->assertStringContainsString('order has shipped', $email->getSubject());
159+
$this->assertEquals('async-shipment@example.com', $email->getTo()[0]->getEmail());
160+
}
161+
162+
protected function tearDown(): void
163+
{
164+
$this->transportBuilder->clean();
165+
$this->sentEmails = [];
166+
parent::tearDown();
167+
}
168+
}

0 commit comments

Comments
 (0)