Skip to content

Commit da8009e

Browse files
committed
MAGETWO-80324: Payment Failed Email is not generated
1 parent 9d75bca commit da8009e

File tree

21 files changed

+931
-375
lines changed

21 files changed

+931
-375
lines changed

app/code/Magento/Authorizenet/Model/Directpost.php

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
namespace Magento\Authorizenet\Model;
77

88
use Magento\Authorizenet\Model\TransactionService;
9+
use Magento\Framework\App\ObjectManager;
910
use Magento\Framework\HTTP\ZendClientFactory;
1011
use Magento\Payment\Model\Method\ConfigInterface;
1112
use Magento\Payment\Model\Method\TransparentInterface;
1213
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
14+
use Magento\Sales\Api\PaymentFailuresInterface;
1315

1416
/**
1517
* Authorize.net DirectPost payment method model.
@@ -124,6 +126,16 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra
124126
*/
125127
private $psrLogger;
126128

129+
/**
130+
* @var PaymentFailuresInterface
131+
*/
132+
private $paymentFailures;
133+
134+
/**
135+
* @var \Magento\Sales\Model\Order
136+
*/
137+
private $order;
138+
127139
/**
128140
* @param \Magento\Framework\Model\Context $context
129141
* @param \Magento\Framework\Registry $registry
@@ -147,6 +159,7 @@ class Directpost extends \Magento\Authorizenet\Model\Authorizenet implements Tra
147159
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
148160
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
149161
* @param array $data
162+
* @param PaymentFailuresInterface|null $paymentFailures
150163
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
151164
*/
152165
public function __construct(
@@ -171,7 +184,8 @@ public function __construct(
171184
\Magento\Sales\Api\TransactionRepositoryInterface $transactionRepository,
172185
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
173186
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
174-
array $data = []
187+
array $data = [],
188+
PaymentFailuresInterface $paymentFailures = null
175189
) {
176190
$this->orderFactory = $orderFactory;
177191
$this->storeManager = $storeManager;
@@ -180,6 +194,8 @@ public function __construct(
180194
$this->orderSender = $orderSender;
181195
$this->transactionRepository = $transactionRepository;
182196
$this->_code = static::METHOD_CODE;
197+
$this->paymentFailures = $paymentFailures ? : ObjectManager::getInstance()
198+
->get(PaymentFailuresInterface::class);
183199

184200
parent::__construct(
185201
$context,
@@ -564,13 +580,10 @@ public function process(array $responseData)
564580
$this->validateResponse();
565581

566582
$response = $this->getResponse();
567-
//operate with order
568-
$orderIncrementId = $response->getXInvoiceNum();
569583
$responseText = $this->dataHelper->wrapGatewayError($response->getXResponseReasonText());
570584
$isError = false;
571-
if ($orderIncrementId) {
572-
/* @var $order \Magento\Sales\Model\Order */
573-
$order = $this->orderFactory->create()->loadByIncrementId($orderIncrementId);
585+
if ($this->getOrderIncrementId()) {
586+
$order = $this->getOrderFromResponse();
574587
//check payment method
575588
$payment = $order->getPayment();
576589
if (!$payment || $payment->getMethod() != $this->getCode()) {
@@ -635,9 +648,10 @@ public function checkResponseCode()
635648
return true;
636649
case self::RESPONSE_CODE_DECLINED:
637650
case self::RESPONSE_CODE_ERROR:
638-
throw new \Magento\Framework\Exception\LocalizedException(
639-
$this->dataHelper->wrapGatewayError($this->getResponse()->getXResponseReasonText())
640-
);
651+
$errorMessage = $this->dataHelper->wrapGatewayError($this->getResponse()->getXResponseReasonText());
652+
$order = $this->getOrderFromResponse();
653+
$this->paymentFailures->handle($order->getQuoteId(), $errorMessage);
654+
throw new \Magento\Framework\Exception\LocalizedException($errorMessage);
641655
default:
642656
throw new \Magento\Framework\Exception\LocalizedException(
643657
__('There was a payment authorization error.')
@@ -988,9 +1002,37 @@ protected function getTransactionResponse($transactionId)
9881002
private function getPsrLogger()
9891003
{
9901004
if (null === $this->psrLogger) {
991-
$this->psrLogger = \Magento\Framework\App\ObjectManager::getInstance()
1005+
$this->psrLogger = ObjectManager::getInstance()
9921006
->get(\Psr\Log\LoggerInterface::class);
9931007
}
9941008
return $this->psrLogger;
9951009
}
1010+
1011+
/**
1012+
* Fetch order by increment id from response.
1013+
*
1014+
* @return \Magento\Sales\Model\Order
1015+
*/
1016+
private function getOrderFromResponse()
1017+
{
1018+
if (!$this->order) {
1019+
$this->order = $this->orderFactory->create();
1020+
1021+
if ($incrementId = $this->getOrderIncrementId()) {
1022+
$this->order = $this->order->loadByIncrementId($incrementId);
1023+
}
1024+
}
1025+
1026+
return $this->order;
1027+
}
1028+
1029+
/**
1030+
* Fetch order increment id from response.
1031+
*
1032+
* @return string
1033+
*/
1034+
private function getOrderIncrementId()
1035+
{
1036+
return $this->getResponse()->getXInvoiceNum();
1037+
}
9961038
}

app/code/Magento/Authorizenet/Test/Unit/Model/DirectpostTest.php

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66
namespace Magento\Authorizenet\Test\Unit\Model;
77

8+
use Magento\Sales\Api\PaymentFailuresInterface;
89
use Magento\Framework\Simplexml\Element;
910
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
1011
use Magento\Authorizenet\Model\Directpost;
@@ -74,6 +75,11 @@ class DirectpostTest extends \PHPUnit_Framework_TestCase
7475
*/
7576
protected $requestFactory;
7677

78+
/**
79+
* @var PaymentFailuresInterface|\PHPUnit_Framework_MockObject_MockObject
80+
*/
81+
private $paymentFailures;
82+
7783
protected function setUp()
7884
{
7985
$this->scopeConfigMock = $this->getMockBuilder('Magento\Framework\App\Config\ScopeConfigInterface')
@@ -104,6 +110,12 @@ protected function setUp()
104110
->setMethods(['getTransactionDetails'])
105111
->getMock();
106112

113+
$this->paymentFailures = $this->getMockBuilder(
114+
PaymentFailuresInterface::class
115+
)
116+
->disableOriginalConstructor()
117+
->getMock();
118+
107119
$this->requestFactory = $this->getRequestFactoryMock();
108120
$httpClientFactoryMock = $this->getHttpClientFactoryMock();
109121

@@ -117,7 +129,8 @@ protected function setUp()
117129
'responseFactory' => $this->responseFactoryMock,
118130
'transactionRepository' => $this->transactionRepositoryMock,
119131
'transactionService' => $this->transactionServiceMock,
120-
'httpClientFactory' => $httpClientFactoryMock
132+
'httpClientFactory' => $httpClientFactoryMock,
133+
'paymentFailures' => $this->paymentFailures
121134
]
122135
);
123136
}
@@ -313,12 +326,15 @@ public function checkResponseCodeSuccessDataProvider()
313326
}
314327

315328
/**
329+
* Checks response failures behaviour.
330+
*
316331
* @param bool $responseCode
332+
* @param int $failuresHandlerCalls
317333
*
318334
* @expectedException \Magento\Framework\Exception\LocalizedException
319335
* @dataProvider checkResponseCodeFailureDataProvider
320336
*/
321-
public function testCheckResponseCodeFailure($responseCode)
337+
public function testCheckResponseCodeFailure($responseCode, $failuresHandlerCalls)
322338
{
323339
$reasonText = 'reason text';
324340

@@ -333,6 +349,23 @@ public function testCheckResponseCodeFailure($responseCode)
333349
->with($reasonText)
334350
->willReturn(__('Gateway error: %1', $reasonText));
335351

352+
$orderMock = $this->getMockBuilder(Order::class)
353+
->disableOriginalConstructor()
354+
->getMock();
355+
356+
$orderMock->expects($this->exactly($failuresHandlerCalls))
357+
->method('getQuoteId')
358+
->willReturn(1);
359+
360+
$this->paymentFailures->expects($this->exactly($failuresHandlerCalls))
361+
->method('handle')
362+
->with(1);
363+
364+
$reflection = new \ReflectionClass($this->directpost);
365+
$order = $reflection->getProperty('order');
366+
$order->setAccessible(true);
367+
$order->setValue($this->directpost, $orderMock);
368+
336369
$this->directpost->checkResponseCode();
337370
}
338371

@@ -342,9 +375,9 @@ public function testCheckResponseCodeFailure($responseCode)
342375
public function checkResponseCodeFailureDataProvider()
343376
{
344377
return [
345-
['responseCode' => Directpost::RESPONSE_CODE_DECLINED],
346-
['responseCode' => Directpost::RESPONSE_CODE_ERROR],
347-
['responseCode' => 999999]
378+
['responseCode' => Directpost::RESPONSE_CODE_DECLINED, 1],
379+
['responseCode' => Directpost::RESPONSE_CODE_ERROR, 1],
380+
['responseCode' => 999999, 0]
348381
];
349382
}
350383

app/code/Magento/Checkout/Helper/Data.php

Lines changed: 12 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Magento\Quote\Model\Quote\Item\AbstractItem;
1010
use Magento\Store\Model\Store;
1111
use Magento\Store\Model\ScopeInterface;
12+
use Magento\Sales\Api\PaymentFailuresInterface;
1213

1314
/**
1415
* Checkout default helper
@@ -52,6 +53,11 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
5253
*/
5354
protected $priceCurrency;
5455

56+
/**
57+
* @var PaymentFailuresInterface
58+
*/
59+
private $paymentFailures;
60+
5561
/**
5662
* @param \Magento\Framework\App\Helper\Context $context
5763
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -60,6 +66,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
6066
* @param \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder
6167
* @param \Magento\Framework\Translate\Inline\StateInterface $inlineTranslation
6268
* @param PriceCurrencyInterface $priceCurrency
69+
* @param PaymentFailuresInterface|null $paymentFailures
6370
* @codeCoverageIgnore
6471
*/
6572
public function __construct(
@@ -69,14 +76,17 @@ public function __construct(
6976
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
7077
\Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
7178
\Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
72-
PriceCurrencyInterface $priceCurrency
79+
PriceCurrencyInterface $priceCurrency,
80+
PaymentFailuresInterface $paymentFailures = null
7381
) {
7482
$this->_storeManager = $storeManager;
7583
$this->_checkoutSession = $checkoutSession;
7684
$this->_localeDate = $localeDate;
7785
$this->_transportBuilder = $transportBuilder;
7886
$this->inlineTranslation = $inlineTranslation;
7987
$this->priceCurrency = $priceCurrency;
88+
$this->paymentFailures = $paymentFailures ? : \Magento\Framework\App\ObjectManager::getInstance()
89+
->get(PaymentFailuresInterface::class);
8090
parent::__construct($context);
8191
}
8292

@@ -202,126 +212,10 @@ public function getBaseSubtotalInclTax($item)
202212
* @param string $message
203213
* @param string $checkoutType
204214
* @return $this
205-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
206-
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
207215
*/
208216
public function sendPaymentFailedEmail($checkout, $message, $checkoutType = 'onepage')
209217
{
210-
$this->inlineTranslation->suspend();
211-
212-
$template = $this->scopeConfig->getValue(
213-
'checkout/payment_failed/template',
214-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
215-
$checkout->getStoreId()
216-
);
217-
218-
$copyTo = $this->_getEmails('checkout/payment_failed/copy_to', $checkout->getStoreId());
219-
$copyMethod = $this->scopeConfig->getValue(
220-
'checkout/payment_failed/copy_method',
221-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
222-
$checkout->getStoreId()
223-
);
224-
$bcc = [];
225-
if ($copyTo && $copyMethod == 'bcc') {
226-
$bcc = $copyTo;
227-
}
228-
229-
$_receiver = $this->scopeConfig->getValue(
230-
'checkout/payment_failed/receiver',
231-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
232-
$checkout->getStoreId()
233-
);
234-
$sendTo = [
235-
[
236-
'email' => $this->scopeConfig->getValue(
237-
'trans_email/ident_' . $_receiver . '/email',
238-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
239-
$checkout->getStoreId()
240-
),
241-
'name' => $this->scopeConfig->getValue(
242-
'trans_email/ident_' . $_receiver . '/name',
243-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
244-
$checkout->getStoreId()
245-
),
246-
],
247-
];
248-
249-
if ($copyTo && $copyMethod == 'copy') {
250-
foreach ($copyTo as $email) {
251-
$sendTo[] = ['email' => $email, 'name' => null];
252-
}
253-
}
254-
$shippingMethod = '';
255-
if ($shippingInfo = $checkout->getShippingAddress()->getShippingMethod()) {
256-
$data = explode('_', $shippingInfo);
257-
$shippingMethod = $data[0];
258-
}
259-
260-
$paymentMethod = '';
261-
if ($paymentInfo = $checkout->getPayment()) {
262-
$paymentMethod = $paymentInfo->getMethod();
263-
}
264-
265-
$items = '';
266-
foreach ($checkout->getAllVisibleItems() as $_item) {
267-
/* @var $_item \Magento\Quote\Model\Quote\Item */
268-
$items .=
269-
$_item->getProduct()->getName() . ' x ' . $_item->getQty() . ' ' . $checkout->getStoreCurrencyCode()
270-
. ' ' . $_item->getProduct()->getFinalPrice(
271-
$_item->getQty()
272-
) . "\n";
273-
}
274-
$total = $checkout->getStoreCurrencyCode() . ' ' . $checkout->getGrandTotal();
275-
276-
foreach ($sendTo as $recipient) {
277-
$transport = $this->_transportBuilder->setTemplateIdentifier(
278-
$template
279-
)->setTemplateOptions(
280-
[
281-
'area' => \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE,
282-
'store' => Store::DEFAULT_STORE_ID
283-
]
284-
)->setTemplateVars(
285-
[
286-
'reason' => $message,
287-
'checkoutType' => $checkoutType,
288-
'dateAndTime' => $this->_localeDate->formatDateTime(
289-
new \DateTime(),
290-
\IntlDateFormatter::MEDIUM,
291-
\IntlDateFormatter::MEDIUM
292-
),
293-
'customer' => $checkout->getCustomerFirstname() . ' ' . $checkout->getCustomerLastname(),
294-
'customerEmail' => $checkout->getCustomerEmail(),
295-
'billingAddress' => $checkout->getBillingAddress(),
296-
'shippingAddress' => $checkout->getShippingAddress(),
297-
'shippingMethod' => $this->scopeConfig->getValue(
298-
'carriers/' . $shippingMethod . '/title',
299-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
300-
),
301-
'paymentMethod' => $this->scopeConfig->getValue(
302-
'payment/' . $paymentMethod . '/title',
303-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
304-
),
305-
'items' => nl2br($items),
306-
'total' => $total,
307-
]
308-
)->setFrom(
309-
$this->scopeConfig->getValue(
310-
'checkout/payment_failed/identity',
311-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
312-
$checkout->getStoreId()
313-
)
314-
)->addTo(
315-
$recipient['email'],
316-
$recipient['name']
317-
)->addBcc(
318-
$bcc
319-
)->getTransport();
320-
321-
$transport->sendMessage();
322-
}
323-
324-
$this->inlineTranslation->resume();
218+
$this->paymentFailures->handle($checkout->getId(), $message, $checkoutType);
325219

326220
return $this;
327221
}

0 commit comments

Comments
 (0)