diff --git a/Api/Repository/AdyenNotificationRepositoryInterface.php b/Api/Repository/AdyenNotificationRepositoryInterface.php index 67453ec80b..8fd0ae3c37 100644 --- a/Api/Repository/AdyenNotificationRepositoryInterface.php +++ b/Api/Repository/AdyenNotificationRepositoryInterface.php @@ -3,7 +3,7 @@ * * Adyen Payment Module * - * Copyright (c) 2024 Adyen N.V. + * Copyright (c) 2025 Adyen N.V. * This file is open source and available under the MIT license. * See the LICENSE file for more info. * @@ -12,28 +12,11 @@ namespace Adyen\Payment\Api\Repository; -use Adyen\Payment\Api\Data\NotificationInterface; -use Magento\Framework\Api\SearchCriteriaInterface; -use Magento\Framework\Api\SearchResultsInterface; -use Magento\Framework\Exception\LocalizedException; - interface AdyenNotificationRepositoryInterface { /** - * Retrieve Adyen Notification entities which match a specified criteria. - * - * @param SearchCriteriaInterface $searchCriteria - * @return SearchResultsInterface - * - * @throws LocalizedException - */ - public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface; - - /** - * Deletes a specified Adyen notification. - * - * @param NotificationInterface $entity The notification ID. - * @return bool + * @param array $entityIds + * @return void */ - public function delete(NotificationInterface $entity): bool; + public function deleteByIds(array $entityIds): void; } diff --git a/Cron/Providers/ProcessedWebhooksProvider.php b/Cron/Providers/ProcessedWebhooksProvider.php index 8020f4e36a..b4baf78d6d 100644 --- a/Cron/Providers/ProcessedWebhooksProvider.php +++ b/Cron/Providers/ProcessedWebhooksProvider.php @@ -11,49 +11,46 @@ namespace Adyen\Payment\Cron\Providers; -use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; use Adyen\Payment\Helper\Config; -use Adyen\Payment\Logger\AdyenLogger; -use Magento\Framework\Api\SearchCriteriaBuilder; -use Magento\Framework\Exception\LocalizedException; +use Adyen\Payment\Model\ResourceModel\Notification\Collection; +use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory; class ProcessedWebhooksProvider implements WebhooksProviderInterface { + /** + * @param CollectionFactory $notificationCollectionFactory + * @param Config $configHelper + */ public function __construct( - private readonly AdyenNotificationRepositoryInterface $adyenNotificationRepository, - private readonly SearchCriteriaBuilder $searchCriteriaBuilder, - private readonly Config $configHelper, - private readonly AdyenLogger $adyenLogger + private readonly CollectionFactory $notificationCollectionFactory, + private readonly Config $configHelper ) { } + /** + * Provides the `entity_id`s of the processed webhooks limited by the removal time + * + * @return array + */ public function provide(): array { $numberOfDays = $this->configHelper->getProcessedWebhookRemovalTime(); - $dateFrom = date('Y-m-d H:i:s', time() - $numberOfDays * 24 * 60 * 60); - - $searchCriteria = $this->searchCriteriaBuilder - ->addFilter('done', 1) - ->addFilter('processing', 0) - ->addFilter('created_at', $dateFrom, 'lteq') - ->setPageSize(self::BATCH_SIZE) - ->create(); - - try { - $items = $this->adyenNotificationRepository->getList($searchCriteria); - return $items->getItems(); - } catch (LocalizedException $e) { - $errorMessage = sprintf( - __('An error occurred while providing webhooks older than %s days!'), - $numberOfDays - ); - - $this->adyenLogger->error($errorMessage); + /** @var Collection $notificationCollection */ + $notificationCollection = $this->notificationCollectionFactory->create(); + $notificationCollection->getProcessedWebhookIdsByTimeLimit($numberOfDays, self::BATCH_SIZE); + if ($notificationCollection->getSize() > 0) { + return $notificationCollection->getColumnValues('entity_id'); + } else { return []; } } + /** + * Returns the provider name + * + * @return string + */ public function getProviderName(): string { return "Adyen processed webhooks provider"; diff --git a/Cron/RemoveProcessedWebhooks.php b/Cron/RemoveProcessedWebhooks.php index 894176aa4a..a71662a0c7 100644 --- a/Cron/RemoveProcessedWebhooks.php +++ b/Cron/RemoveProcessedWebhooks.php @@ -15,7 +15,6 @@ use Adyen\Payment\Cron\Providers\WebhooksProviderInterface; use Adyen\Payment\Helper\Config; use Adyen\Payment\Logger\AdyenLogger; -use Adyen\Payment\Model\Notification; use Exception; class RemoveProcessedWebhooks @@ -44,27 +43,17 @@ public function execute(): void $numberOfItemsRemoved = 0; foreach ($this->providers as $provider) { - /** @var Notification $notificationToCleanup */ - foreach ($provider->provide() as $notificationToCleanup) { - try { - $isSuccessfullyDeleted = $this->adyenNotificationRepository->delete($notificationToCleanup); - - if ($isSuccessfullyDeleted) { - $message = __( - '%1: Notification with entity_id %2 has been deleted because it was processed %3 days ago.', - $provider->getProviderName(), - $notificationToCleanup->getEntityId(), - $this->configHelper->getProcessedWebhookRemovalTime() - ); - $this->adyenLogger->addAdyenNotification($message); + $webhookIdsToRemove = $provider->provide(); + $numberOfWebhooksProvided = count($webhookIdsToRemove); - $numberOfItemsRemoved++; - } + if ($numberOfWebhooksProvided > 0) { + try { + $this->adyenNotificationRepository->deleteByIds($webhookIdsToRemove); + $numberOfItemsRemoved += $numberOfWebhooksProvided; } catch (Exception $e) { $message = __( - '%1: An error occurred while deleting the notification with entity_id %2: %3', + '%1: An error occurred while deleting webhooks! %2', $provider->getProviderName(), - $notificationToCleanup->getEntityId(), $e->getMessage() ); @@ -73,11 +62,23 @@ public function execute(): void } } - $successMessage = __( - '%1 processed webhooks have been removed by the RemoveProcessedWebhooks cronjob.', - $numberOfItemsRemoved - ); - $this->adyenLogger->addAdyenNotification($successMessage); + if ($numberOfItemsRemoved > 0) { + $successMessage = __( + '%1 processed webhooks have been removed by the RemoveProcessedWebhooks cronjob.', + $numberOfItemsRemoved + ); + + $this->adyenLogger->addAdyenNotification($successMessage); + } else { + $debugMessage = __( + 'There is no webhooks to be removed by RemoveProcessedWebhooks cronjob.', + $numberOfItemsRemoved + ); + + $this->adyenLogger->addAdyenDebug($debugMessage); + } + + } else { $message = __('Processed webhook removal feature is disabled. The cronjob has been skipped!'); $this->adyenLogger->addAdyenDebug($message); diff --git a/Model/AdyenNotificationRepository.php b/Model/AdyenNotificationRepository.php index 277d12be60..27f9dc3153 100644 --- a/Model/AdyenNotificationRepository.php +++ b/Model/AdyenNotificationRepository.php @@ -3,7 +3,7 @@ * * Adyen Payment module (https://www.adyen.com/) * - * Copyright (c) 2024 Adyen N.V. (https://www.adyen.com/) + * Copyright (c) 2025 Adyen N.V. (https://www.adyen.com/) * See LICENSE.txt for license details. * * Author: Adyen @@ -11,52 +11,34 @@ namespace Adyen\Payment\Model; -use Adyen\Payment\Api\Data\NotificationInterface; use Adyen\Payment\Api\Repository\AdyenNotificationRepositoryInterface; use Adyen\Payment\Model\ResourceModel\Notification\CollectionFactory; -use Magento\Framework\Api\Search\SearchResultFactory; -use Magento\Framework\Api\SearchCriteria\CollectionProcessor; -use Magento\Framework\Api\SearchCriteriaInterface; -use Magento\Framework\Api\SearchResultsInterface; use Magento\Framework\ObjectManagerInterface; class AdyenNotificationRepository implements AdyenNotificationRepositoryInterface { /** - * @param SearchResultFactory $searchResultsFactory - * @param CollectionFactory $collectionFactory - * @param CollectionProcessor $collectionProcessor * @param ObjectManagerInterface $objectManager * @param string $resourceModel */ public function __construct( - private readonly SearchResultFactory $searchResultsFactory, - private readonly CollectionFactory $collectionFactory, - private readonly CollectionProcessor $collectionProcessor, private readonly ObjectManagerInterface $objectManager, private readonly string $resourceModel ) { } /** - * @param SearchCriteriaInterface $searchCriteria - * @return SearchResultsInterface + * Delete multiple entities with the given IDs + * + * @param array $entityIds + * @return void */ - public function getList(SearchCriteriaInterface $searchCriteria): SearchResultsInterface + public function deleteByIds(array $entityIds): void { - $searchResult = $this->searchResultsFactory->create(); - $collection = $this->collectionFactory->create(); - $this->collectionProcessor->process($searchCriteria, $collection); - $searchResult->setItems($collection->getItems()); - $searchResult->setTotalCount($collection->getSize()); + if (empty($entityIds)) { + return; + } - return $searchResult; - } - - public function delete(NotificationInterface $entity): bool - { $resource = $this->objectManager->get($this->resourceModel); - $resource->delete($entity); - - return true; + $resource->deleteByIds($entityIds); } } diff --git a/Model/ResourceModel/Notification.php b/Model/ResourceModel/Notification.php index 33f92f285f..6dec30c10c 100755 --- a/Model/ResourceModel/Notification.php +++ b/Model/ResourceModel/Notification.php @@ -11,7 +11,10 @@ namespace Adyen\Payment\Model\ResourceModel; -class Notification extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Model\ResourceModel\Db\AbstractDb; + +class Notification extends AbstractDb { /** * Construct @@ -49,4 +52,27 @@ public function getNotification($pspReference, $eventCode, $success, $originalRe return $this->getConnection()->fetchAll($select); } + + /** + * Deletes the rows corresponding to the given `entity_id`s + * + * @param array $entitiyIds + * @return void + * @throws LocalizedException + */ + public function deleteByIds(array $entitiyIds): void + { + if (empty($entitiyIds)) { + return; + } + + $tableName = $this->getMainTable(); + + $connection = $this->getConnection(); + $select = $connection->select() + ->from(['notification' => $tableName]) + ->where('notification.entity_id IN (?)', $entitiyIds); + + $connection->query($select->deleteFromSelect('notification')); + } } diff --git a/Model/ResourceModel/Notification/Collection.php b/Model/ResourceModel/Notification/Collection.php index c033d5c407..b1c9b2461e 100755 --- a/Model/ResourceModel/Notification/Collection.php +++ b/Model/ResourceModel/Notification/Collection.php @@ -65,4 +65,28 @@ public function notificationsToProcessFilter() return $this; } + + /** + * Returns the `entity_id`s of the processed webhooks with the given time limit. + * + * @param int $processedWebhookRemovalTime + * @param int|null $batchSize + * @return $this + */ + public function getProcessedWebhookIdsByTimeLimit( + int $processedWebhookRemovalTime, + ?int $batchSize = null + ): Collection { + $dateFrom = date('Y-m-d H:i:s', time() - $processedWebhookRemovalTime * 24 * 60 * 60); + + $this->addFieldToFilter('created_at', ['lteq' => $dateFrom]); + $this->addFieldToFilter('done', 1); + $this->addFieldToFilter('processing', 0); + + if (isset($batchSize)) { + $this->setPageSize($batchSize); + } + + return $this; + } } diff --git a/etc/crontab.xml b/etc/crontab.xml index 468e53d0a9..54b875b0c8 100755 --- a/etc/crontab.xml +++ b/etc/crontab.xml @@ -25,7 +25,7 @@ 0 0 * * * - 0 0 * * * + */1 * * * *