Skip to content

Commit

Permalink
Merge pull request #2429 from Adyen/develop
Browse files Browse the repository at this point in the history
Release 9.0.6
  • Loading branch information
peterojo authored Jan 12, 2024
2 parents 2ef729f + 2bcff1a commit cb6288b
Show file tree
Hide file tree
Showing 16 changed files with 367 additions and 37 deletions.
4 changes: 3 additions & 1 deletion Console/Command/EnablePaymentMethodsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Adyen\Payment\Helper\PaymentMethodsFactory;
use Adyen\Payment\Helper\ConfigFactory;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down Expand Up @@ -32,7 +33,7 @@ protected function configure(): void
/**
* @throws \Exception
*/
protected function execute(InputInterface $input, OutputInterface $output): void
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Starting enabling payment methods.');
$paymentMethods = $this->paymentMethodsFactory->create();
Expand All @@ -47,5 +48,6 @@ protected function execute(InputInterface $input, OutputInterface $output): void
}

$output->writeln('Completed enabling payment methods.');
return Cli::RETURN_SUCCESS;
}
}
8 changes: 7 additions & 1 deletion Console/Command/WebhookProcessorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Adyen\Payment\Console\Command;

use Adyen\Payment\Cron\WebhookProcessor;
use Magento\Framework\Console\Cli;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down Expand Up @@ -32,7 +33,12 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln('Starting webhook processor.');
$this->webhookProcessor->execute();
try {
$this->webhookProcessor->execute();
} catch (\Exception $e) {
return Cli::RETURN_FAILURE;
}
$output->writeln('Completed webhook processor execution.');
return Cli::RETURN_SUCCESS;
}
}
2 changes: 0 additions & 2 deletions Gateway/Request/RecurringDataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ public function build(array $buildSubject): array
$body = $this->adyenRequestsHelper->buildCardRecurringData($storeId, $payment);
} elseif ($this->paymentMethodsHelper->isAlternativePaymentMethod($method)) {
$body = $this->vaultHelper->buildPaymentMethodRecurringData($payment, $storeId);
} elseif ($method === PaymentMethods::ADYEN_ONE_CLICK) {
$body = $this->adyenRequestsHelper->buildAdyenTokenizedPaymentRecurringData($storeId, $payment);
} elseif ($method !== PaymentMethods::ADYEN_PAY_BY_LINK) {
$this->adyenLogger->addAdyenWarning(
sprintf('Unknown payment method: %s', $payment->getMethod()),
Expand Down
16 changes: 13 additions & 3 deletions Gateway/Request/ShopperInteractionDataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Adyen\Payment\Gateway\Request;

use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider;
use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider;
use Magento\Framework\App\State;
Expand All @@ -26,10 +27,14 @@ class ShopperInteractionDataBuilder implements BuilderInterface
const SHOPPER_INTERACTION_ECOMMERCE = 'Ecommerce';

private State $appState;
private StateData $stateData;

public function __construct(Context $context)
{
public function __construct(
Context $context,
StateData $stateData
) {
$this->appState = $context->getAppState();
$this->stateData = $stateData;
}

/**
Expand All @@ -42,6 +47,7 @@ public function build(array $buildSubject)
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$order = $payment->getOrder();
$paymentMethod = $payment->getMethodInstance()->getCode();

if ($paymentMethod == AdyenPayByLinkConfigProvider::CODE) {
Expand All @@ -52,11 +58,15 @@ public function build(array $buildSubject)
// Ecommerce is the default shopperInteraction
$shopperInteraction = self::SHOPPER_INTERACTION_ECOMMERCE;

// Check if it's a tokenised payment or not.
$stateData = $this->stateData->getStateData($order->getQuoteId());
$storedPaymentMethodId = $this->stateData->getStoredPaymentMethodIdFromStateData($stateData);

if ($paymentMethod == AdyenMotoConfigProvider::CODE &&
$this->appState->getAreaCode() == \Magento\Framework\App\Area::AREA_ADMINHTML) {
// Backend CC orders are MOTO
$shopperInteraction = self::SHOPPER_INTERACTION_MOTO;
} elseif (str_contains($paymentMethod, '_vault')) {
} elseif (str_contains($paymentMethod, '_vault') || isset($storedPaymentMethodId)) {
// Vault is ContAuth
$shopperInteraction = self::SHOPPER_INTERACTION_CONTAUTH;
}
Expand Down
13 changes: 11 additions & 2 deletions Helper/Creditmemo.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,17 @@ public function linkAndUpdateAdyenCreditmemos(
$adyenCreditmemo[CreditmemoInterface::ENTITY_ID],
CreditmemoInterface::ENTITY_ID
);
$currAdyenCreditmemo->setCreditmemoId($magentoCreditmemo->getEntityId());
$this->adyenCreditmemoResourceModel->save($currAdyenCreditmemo);

if ($currAdyenCreditmemo->getCreditmemoId() !== null) {
continue;
}

if ($currAdyenCreditmemo->getAmount() == $magentoCreditmemo->getGrandTotal()) {
$currAdyenCreditmemo->setCreditmemoId($magentoCreditmemo->getEntityId());
$this->adyenCreditmemoResourceModel->save($currAdyenCreditmemo);
break;
}

}
}
}
Expand Down
8 changes: 8 additions & 0 deletions Helper/Order.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@ public function finalizeOrder(MagentoOrder $order, Notification $notification):
'merchantReference' => $notification->getMerchantReference()
]);
}
} else {
/*
* Set order status back to pre_payment_authorized if the order state is payment_review.
* Otherwise, capture-cancel-refund is not possible.
*/
if ($order->getState() === MagentoOrder::STATE_PAYMENT_REVIEW) {
$order = $this->setPrePaymentAuthorized($order);
}
}

return $order;
Expand Down
4 changes: 3 additions & 1 deletion Helper/Requests.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,9 @@ public function buildCardRecurringData(int $storeId, $payment): array
$request['storePaymentMethod'] = $storePaymentMethod;
}

if ($storePaymentMethod) {
$storedPaymentMethodId = $this->stateData->getStoredPaymentMethodIdFromStateData($stateData);

if ($storePaymentMethod || isset($storedPaymentMethodId)) {
$recurringProcessingModel = $payment->getAdditionalInformation('recurringProcessingModel');

if (isset($recurringProcessingModel)) {
Expand Down
5 changes: 5 additions & 0 deletions Helper/StateData.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,9 @@ public function removeStateData(int $stateDataId, ?int $quoteId = null): bool
return true;
}
}

public function getStoredPaymentMethodIdFromStateData(array $stateData): ?string
{
return $stateData['paymentMethod']['storedPaymentMethodId'] ?? null;
}
}
13 changes: 11 additions & 2 deletions Helper/Vault.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,24 @@ class Vault
private PaymentTokenRepositoryInterface $paymentTokenRepository;
private Config $config;
private PaymentMethods $paymentMethodsHelper;
private StateData $stateData;

public function __construct(
AdyenLogger $adyenLogger,
PaymentTokenManagement $paymentTokenManagement,
PaymentTokenFactoryInterface $paymentTokenFactory,
PaymentTokenRepositoryInterface $paymentTokenRepository,
Config $config,
PaymentMethods $paymentMethodsHelper
PaymentMethods $paymentMethodsHelper,
StateData $stateData
) {
$this->adyenLogger = $adyenLogger;
$this->paymentTokenManagement = $paymentTokenManagement;
$this->paymentTokenFactory = $paymentTokenFactory;
$this->paymentTokenRepository = $paymentTokenRepository;
$this->config = $config;
$this->paymentMethodsHelper = $paymentMethodsHelper;
$this->stateData = $stateData;
}

/**
Expand Down Expand Up @@ -144,11 +147,17 @@ public function buildPaymentMethodRecurringData(InfoInterface $payment, int $sto
$requestRpm = $payment->getAdditionalInformation('recurringProcessingModel');
$configuredRpm = $this->getPaymentMethodRecurringProcessingModel($paymentMethod->getCode(), $storeId);

$stateData = $this->stateData->getStateData($payment->getOrder()->getQuoteId());
$storedPaymentMethodId = $this->stateData->getStoredPaymentMethodIdFromStateData($stateData);

$recurringProcessingModel = $requestRpm ?? $configuredRpm;

if (isset($recurringProcessingModel)) {
$request['storePaymentMethod'] = true;
$request['recurringProcessingModel'] = $recurringProcessingModel;

if (is_null($storedPaymentMethodId)) {
$request['storePaymentMethod'] = true;
}
}

return $request;
Expand Down
2 changes: 1 addition & 1 deletion Model/Notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ public function setCreatedAt(DateTime $createdAt): NotificationInterface

public function getUpdatedAt(): ?string
{
$updatedAt = $this->getData(self::CREATED_AT);
$updatedAt = $this->getData(self::UPDATED_AT);

if ($updatedAt instanceOf Datetime) {
return $updatedAt->format('Y-m-d H:i:s');
Expand Down
42 changes: 21 additions & 21 deletions Plugin/PaymentVaultDeleteToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,29 @@ public function beforeDelete(PaymentTokenRepositoryInterface $subject, PaymentTo
$paymentMethodCode = $paymentToken->getPaymentMethodCode();
$storeId = $this->storeManager->getStore()->getStoreId();

if (is_null($paymentMethodCode) || !$this->vaultHelper->isAdyenPaymentCode($paymentMethodCode)) {
return [$paymentToken];
}

$request = $this->createDisableTokenRequest($paymentToken);
if (!is_null($paymentMethodCode) && $this->vaultHelper->isAdyenPaymentCode($paymentMethodCode)) {
$request = $this->createDisableTokenRequest($paymentToken);

try {
$client = $this->dataHelper->initializeAdyenClient($storeId);
$recurringService = $this->dataHelper->createAdyenRecurringService($client);
$recurringService->disable($request);
} catch (AdyenException $e) {
$this->adyenLogger->error(sprintf(
'Error while attempting to disable token with id %s: %s',
$paymentToken->getEntityId(),
$e->getMessage()
));
} catch (NoSuchEntityException $e) {
$this->adyenLogger->error(sprintf(
'No such entity while attempting to disable token with id %s: %s',
$paymentToken->getEntityId(),
$e->getMessage()
));
try {
$client = $this->dataHelper->initializeAdyenClient($storeId);
$recurringService = $this->dataHelper->createAdyenRecurringService($client);
$recurringService->disable($request);
} catch (AdyenException $e) {
$this->adyenLogger->error(sprintf(
'Error while attempting to disable token with id %s: %s',
$paymentToken->getEntityId(),
$e->getMessage()
));
} catch (NoSuchEntityException $e) {
$this->adyenLogger->error(sprintf(
'No such entity while attempting to disable token with id %s: %s',
$paymentToken->getEntityId(),
$e->getMessage()
));
}
}

return [$paymentToken];
}

private function createDisableTokenRequest(PaymentTokenInterface $paymentToken): array
Expand Down
123 changes: 123 additions & 0 deletions Test/Unit/Gateway/Request/ShopperInteractionDataBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/

namespace Adyen\Payment\Test\Gateway\Request;

use Adyen\Payment\Gateway\Request\ShopperInteractionDataBuilder;
use Adyen\Payment\Helper\StateData;
use Adyen\Payment\Model\Method\Adapter;
use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider;
use Adyen\Payment\Model\Ui\AdyenCcConfigProvider;
use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider;
use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Payment\Gateway\Data\PaymentDataObject;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Payment;

class ShopperInteractionDataBuilderTest extends AbstractAdyenTestCase
{
private $shopperInteractionDataBuilder;
private $appState;
private $stateData;

protected function setUp(): void
{
$this->objectManager = new ObjectManager($this);

$this->appState = $this->createMock(State::class);
$this->stateData = $this->createPartialMock(StateData::class, [
'getStateData'
]);

$this->shopperInteractionDataBuilder = $this->objectManager->getObject(
ShopperInteractionDataBuilder::class, [
'appState' => $this->appState,
'stateData' => $this->stateData
]
);
}

public function testPayByLinkRequest()
{
$buildSubject = [
'payment' => $this->createConfiguredMock(PaymentDataObject::class, [
'getPayment' => $this->createConfiguredMock(Payment::class, [
'getMethodInstance' => $this->createConfiguredMock(Adapter::class, [
'getCode' => AdyenPayByLinkConfigProvider::CODE
])
])
])
];

$this->assertEmpty($this->shopperInteractionDataBuilder->build($buildSubject));
}

public function testMotoRequest()
{
$buildSubject = [
'payment' => $this->createConfiguredMock(PaymentDataObject::class, [
'getPayment' => $this->createConfiguredMock(Payment::class, [
'getMethodInstance' => $this->createConfiguredMock(Adapter::class, [
'getCode' => AdyenMotoConfigProvider::CODE
]),
'getOrder' => $this->createConfiguredMock(Order::class, [
'getQuoteId' => 1
])
])
])
];

$this->appState->method('getAreaCode')->willReturn(Area::AREA_ADMINHTML);
$this->stateData->method('getStateData')->willReturn([]);

$request = $this->shopperInteractionDataBuilder->build($buildSubject);

$this->assertArrayHasKey('shopperInteraction', $request['body']);
$this->assertEquals(
ShopperInteractionDataBuilder::SHOPPER_INTERACTION_MOTO,
$request['body']['shopperInteraction']
);
}

public function testRecurringRequest()
{
$buildSubject = [
'payment' => $this->createConfiguredMock(PaymentDataObject::class, [
'getPayment' => $this->createConfiguredMock(Payment::class, [
'getMethodInstance' => $this->createConfiguredMock(Adapter::class, [
'getCode' => AdyenCcConfigProvider::CODE
]),
'getOrder' => $this->createConfiguredMock(Order::class, [
'getQuoteId' => 1
])
])
])
];

$this->appState->method('getAreaCode')->willReturn(Area::AREA_ADMINHTML);
$this->stateData->method('getStateData')->willReturn([
'paymentMethod' => [
'storedPaymentMethodId' => hash('md5', time())
]
]);

$request = $this->shopperInteractionDataBuilder->build($buildSubject);

$this->assertArrayHasKey('shopperInteraction', $request['body']);
$this->assertEquals(
ShopperInteractionDataBuilder::SHOPPER_INTERACTION_CONTAUTH,
$request['body']['shopperInteraction']
);
}
}
Loading

0 comments on commit cb6288b

Please sign in to comment.