diff --git a/mollie.php b/mollie.php index aa1affb7f..de16d96ce 100755 --- a/mollie.php +++ b/mollie.php @@ -27,6 +27,7 @@ use Mollie\Service\ExceptionService; use Mollie\ServiceProvider\LeagueServiceContainerProvider; use Mollie\Subscription\Handler\CustomerAddressUpdateHandler; +use Mollie\Subscription\Handler\UpdateSubscriptionCarrierHandler; use Mollie\Subscription\Install\AttributeInstaller; use Mollie\Subscription\Install\DatabaseTableInstaller; use Mollie\Subscription\Install\HookInstaller; @@ -1271,6 +1272,39 @@ public function hookActionObjectAddressDeleteAfter(array $params): void $this->addPreventDeleteErrorMessage(); } + public function hookActionCarrierUpdate(array $params): void + { + $oldCarrierId = $params['id_carrier'] ?? 0; + $newCarrier = $params['carrier'] ?? null; + + if (empty($oldCarrierId) || empty($newCarrier)) { + return; + } + + /** @var UpdateSubscriptionCarrierHandler $subscriptionCarrierUpdateHandler */ + $subscriptionCarrierUpdateHandler = $this->getService(UpdateSubscriptionCarrierHandler::class); + + /** @var ConfigurationAdapter $configuration */ + $configuration = $this->getService(ConfigurationAdapter::class); + + /** @var PrestaLoggerInterface $logger */ + $logger = $this->getService(PrestaLoggerInterface::class); + + if ((int) $oldCarrierId !== (int) $configuration->get(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID)) { + return; + } + + $failedSubscriptionOrderIdsToUpdate = $subscriptionCarrierUpdateHandler->run((int) $newCarrier->id); + + if (empty($failedSubscriptionOrderIdsToUpdate)) { + return; + } + + $logger->error('Failed to update subscription carrier for all orders.', [ + 'failed_subscription_order_ids' => json_encode($failedSubscriptionOrderIdsToUpdate), + ]); + } + public function hookActionFrontControllerAfterInit(): void { $this->frontControllerAfterInit(); diff --git a/src/Install/Installer.php b/src/Install/Installer.php index aec5a7671..15720d22d 100644 --- a/src/Install/Installer.php +++ b/src/Install/Installer.php @@ -171,6 +171,7 @@ public static function getHooks() 'actionObjectOrderPaymentAddAfter', 'displayProductAdditionalInfo', 'displayCustomerAccount', + 'actionCarrierUpdate', ]; } diff --git a/src/Install/Uninstall.php b/src/Install/Uninstall.php index e92cc9dd2..567261348 100644 --- a/src/Install/Uninstall.php +++ b/src/Install/Uninstall.php @@ -96,7 +96,6 @@ private function deleteConfig() Config::METHODS_CONFIG, Config::MOLLIE_MAIL_WHEN_COMPLETED, Config::MOLLIE_API_KEY_TEST, - Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID, Config::MOLLIE_SUBSCRIPTION_ENABLED, ]; diff --git a/src/Logger/PrestaLogger.php b/src/Logger/PrestaLogger.php index 2f603e7e6..e476f1c2a 100644 --- a/src/Logger/PrestaLogger.php +++ b/src/Logger/PrestaLogger.php @@ -87,7 +87,9 @@ public function info($message, array $context = []) public function debug($message, array $context = []) { - throw new NotImplementedException('not implemented method'); + // TODO implement single method, which handles logging + + $this->info($message, $context); } public function log($level, $message, array $context = []) diff --git a/subscription/Controller/Symfony/SubscriptionController.php b/subscription/Controller/Symfony/SubscriptionController.php index 8adfac607..7dc177088 100644 --- a/subscription/Controller/Symfony/SubscriptionController.php +++ b/subscription/Controller/Symfony/SubscriptionController.php @@ -15,11 +15,15 @@ namespace Mollie\Subscription\Controller\Symfony; use Exception; +use Mollie\Adapter\ConfigurationAdapter; use Mollie\Adapter\Shop; +use Mollie\Config\Config; +use Mollie\Logger\PrestaLoggerInterface; use Mollie\Subscription\Exception\SubscriptionApiException; use Mollie\Subscription\Filters\SubscriptionFilters; use Mollie\Subscription\Grid\SubscriptionGridDefinitionFactory; use Mollie\Subscription\Handler\SubscriptionCancellationHandler; +use Mollie\Subscription\Handler\UpdateSubscriptionCarrierHandler; use Mollie\Utility\PsVersionUtility; use PrestaShop\PrestaShop\Core\Form\FormHandlerInterface; use PrestaShop\PrestaShop\Core\Grid\GridFactoryInterface; @@ -96,6 +100,8 @@ public function submitOptionsAction(Request $request): RedirectResponse return $this->redirectToRoute('admin_subscription_index'); } + $this->updateSubscriptionCarrier($form->getData()['carrier']); + $formHandler->save($form->getData()); $this->addFlash( @@ -106,6 +112,34 @@ public function submitOptionsAction(Request $request): RedirectResponse return $this->redirectToRoute('admin_subscription_index'); } + private function updateSubscriptionCarrier(int $newCarrierId): void + { + /** @var ConfigurationAdapter $configuration */ + $configuration = $this->module->getService(ConfigurationAdapter::class); + $oldCarrierId = $configuration->get(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID); + + if (empty($oldCarrierId) || empty($newCarrierId)) { + $this->addFlash( + 'error', + $this->module->l('Carrier not found', self::FILE_NAME) + ); + } + + /** @var UpdateSubscriptionCarrierHandler $subscriptionCarrierUpdateHandler */ + $subscriptionCarrierUpdateHandler = $this->module->getService(UpdateSubscriptionCarrierHandler::class); + + /** @var PrestaLoggerInterface $logger */ + $logger = $this->module->getService(PrestaLoggerInterface::class); + + $failedSubscriptionOrderIdsToUpdate = $subscriptionCarrierUpdateHandler->run($newCarrierId); + + if (!empty($failedSubscriptionOrderIdsToUpdate)) { + $logger->error('Failed to update subscription carrier for all orders.', [ + 'failed_subscription_order_ids' => json_encode($failedSubscriptionOrderIdsToUpdate), + ]); + } + } + /** * Provides filters functionality. * diff --git a/subscription/Handler/UpdateSubscriptionCarrierHandler.php b/subscription/Handler/UpdateSubscriptionCarrierHandler.php new file mode 100644 index 000000000..fce320b69 --- /dev/null +++ b/subscription/Handler/UpdateSubscriptionCarrierHandler.php @@ -0,0 +1,213 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Subscription\Handler; + +use Mollie\Adapter\ConfigurationAdapter; +use Mollie\Adapter\Context; +use Mollie\Api\Types\SubscriptionStatus; +use Mollie\Config\Config; +use Mollie\Logger\PrestaLoggerInterface; +use Mollie\Service\MailService; +use Mollie\Subscription\Action\UpdateRecurringOrderAction; +use Mollie\Subscription\Action\UpdateSubscriptionAction; +use Mollie\Subscription\DTO\CloneOriginalSubscriptionCartData; +use Mollie\Subscription\DTO\SubscriptionOrderAmountProviderData; +use Mollie\Subscription\DTO\UpdateRecurringOrderData; +use Mollie\Subscription\DTO\UpdateSubscriptionData; +use Mollie\Subscription\Provider\SubscriptionOrderAmountProvider; +use Mollie\Subscription\Repository\RecurringOrderRepositoryInterface; + +if (!defined('_PS_VERSION_')) { + exit; +} + +class UpdateSubscriptionCarrierHandler +{ + /** @var ConfigurationAdapter */ + private $configuration; + /** @var RecurringOrderRepositoryInterface */ + private $recurringOrderRepository; + /** @var Context */ + private $context; + /** @var UpdateSubscriptionAction */ + private $updateSubscriptionAction; + /** @var UpdateRecurringOrderAction */ + private $updateRecurringOrderAction; + /** @var PrestaLoggerInterface */ + private $logger; + /** @var CloneOriginalSubscriptionCartHandler */ + private $cloneOriginalSubscriptionCartHandler; + /** @var SubscriptionOrderAmountProvider */ + private $subscriptionOrderAmountProvider; + /** @var MailService */ + private $mailService; + + public function __construct( + ConfigurationAdapter $configuration, + RecurringOrderRepositoryInterface $recurringOrderRepository, + Context $context, + UpdateSubscriptionAction $updateSubscriptionAction, + UpdateRecurringOrderAction $updateRecurringOrderAction, + PrestaLoggerInterface $logger, + CloneOriginalSubscriptionCartHandler $cloneOriginalSubscriptionCartHandler, + SubscriptionOrderAmountProvider $subscriptionOrderAmountProvider, + MailService $mailService + ) { + $this->configuration = $configuration; + $this->recurringOrderRepository = $recurringOrderRepository; + $this->context = $context; + $this->updateSubscriptionAction = $updateSubscriptionAction; + $this->updateRecurringOrderAction = $updateRecurringOrderAction; + $this->logger = $logger; + $this->cloneOriginalSubscriptionCartHandler = $cloneOriginalSubscriptionCartHandler; + $this->subscriptionOrderAmountProvider = $subscriptionOrderAmountProvider; + $this->mailService = $mailService; + } + + // TODO feature test this with mocked API request data + public function run(int $newCarrierId): array + { + $activeSubscriptionCarrierId = (int) $this->configuration->get(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID); + + // TODO rethink this. If process failed in any way, maybe merchant would like to repeat it again. We need to track individual orders if they were updated. + if ($newCarrierId === $activeSubscriptionCarrierId) { + $this->logger->debug('Same subscription carrier is saved'); + + return []; + } + + $this->configuration->updateValue( + Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID, + $newCarrierId + ); + + /** @var array $recurringOrders + */ + $recurringOrders = $this->recurringOrderRepository->getAllOrdersBasedOnStatuses( + [ + SubscriptionStatus::STATUS_PENDING, + SubscriptionStatus::STATUS_ACTIVE, + SubscriptionStatus::STATUS_SUSPENDED, + ], + $this->context->getShopId() + ); + + $failedSubscriptionOrderIdsToUpdate = []; + + foreach ($recurringOrders as $recurringOrder) { + try { + $duplicatedCart = $this->cloneOriginalSubscriptionCartHandler->run( + CloneOriginalSubscriptionCartData::create( + (int) $recurringOrder['id_cart'], + (int) $recurringOrder['id_recurring_product'], + (int) $recurringOrder['id_invoice_address'], + (int) $recurringOrder['id_delivery_address'] + ) + ); + } catch (\Throwable $exception) { + $failedSubscriptionOrderIdsToUpdate[] = (string) $recurringOrder['mollie_subscription_id']; + + $this->logger->error('Failed to clone subscription cart.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + continue; + } + + $subscriptionProduct = $duplicatedCart->getProducts()[0]; + + try { + $orderAmount = $this->subscriptionOrderAmountProvider->get( + SubscriptionOrderAmountProviderData::create( + (int) $duplicatedCart->id_address_delivery, + (int) $duplicatedCart->id, + (int) $duplicatedCart->id_customer, + $subscriptionProduct, + $newCarrierId, + (int) $duplicatedCart->id_currency, + (float) $subscriptionProduct['total_price_tax_incl'] + ) + ); + } catch (\Throwable $exception) { + $failedSubscriptionOrderIdsToUpdate[] = (string) $recurringOrder['mollie_subscription_id']; + + $this->logger->error('Failed to get subscription order amount.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + continue; + } + + try { + $this->updateSubscriptionAction->run(UpdateSubscriptionData::create( + (string) $recurringOrder['mollie_customer_id'], + (string) $recurringOrder['mollie_subscription_id'], + $orderAmount, + (int) $duplicatedCart->id_customer, + (int) $duplicatedCart->id, + $newCarrierId + )); + } catch (\Throwable $exception) { + $failedSubscriptionOrderIdsToUpdate[] = (string) $recurringOrder['mollie_subscription_id']; + + $this->logger->error('Failed to update subscription.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + continue; + } + + try { + $this->updateRecurringOrderAction->run(UpdateRecurringOrderData::create( + (int) $recurringOrder['id'], + $orderAmount->getValue() + )); + } catch (\Throwable $exception) { + $failedSubscriptionOrderIdsToUpdate[] = (string) $recurringOrder['mollie_subscription_id']; + + $this->logger->error('Failed to update recurring order record.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + continue; + } + + try { + $this->mailService->sendSubscriptionCarrierUpdateMail((int) $recurringOrder['id']); + } catch (\Throwable $exception) { + $failedSubscriptionOrderIdsToUpdate[] = (string) $recurringOrder['mollie_subscription_id']; + + $this->logger->error('Failed to send subscription carrier update mail.', [ + 'Exception message' => $exception->getMessage(), + 'Exception code' => $exception->getCode(), + ]); + + continue; + } + } + + return $failedSubscriptionOrderIdsToUpdate; + } +} diff --git a/subscription/Repository/RecurringOrderRepository.php b/subscription/Repository/RecurringOrderRepository.php index ae190d71f..3e70cb39e 100644 --- a/subscription/Repository/RecurringOrderRepository.php +++ b/subscription/Repository/RecurringOrderRepository.php @@ -26,4 +26,28 @@ public function __construct() { parent::__construct(\MolRecurringOrder::class); } + + public function getAllOrdersBasedOnStatuses(array $statuses, int $shopId): array + { + $query = new \DbQuery(); + + $query + ->select( + 'mro.id_mol_recurring_order as id, mro.mollie_subscription_id, + mro.mollie_customer_id, mro.id_cart, + mro.id_mol_recurring_orders_product as id_recurring_product, + mro.id_address_invoice, mro.id_delivery_address' + ) + ->from('mol_recurring_order', 'mro') + ->leftJoin( + 'orders', 'o', + 'o.id_order = mro.id_order' + ) + ->where('mro.status IN (\'' . implode("','", $statuses) . '\')') + ->where('o.id_shop = ' . $shopId); + + $result = \Db::getInstance()->executeS($query); + + return !empty($result) ? $result : []; + } } diff --git a/subscription/Repository/RecurringOrderRepositoryInterface.php b/subscription/Repository/RecurringOrderRepositoryInterface.php index e334effa3..7924a733f 100644 --- a/subscription/Repository/RecurringOrderRepositoryInterface.php +++ b/subscription/Repository/RecurringOrderRepositoryInterface.php @@ -22,4 +22,5 @@ interface RecurringOrderRepositoryInterface extends ReadOnlyRepositoryInterface { + public function getAllOrdersBasedOnStatuses(array $statuses, int $shopId): array; } diff --git a/tests/Unit/BaseTestCase.php b/tests/Unit/BaseTestCase.php index 742bc54ea..54388f5e3 100644 --- a/tests/Unit/BaseTestCase.php +++ b/tests/Unit/BaseTestCase.php @@ -15,6 +15,7 @@ use Mollie\Adapter\ConfigurationAdapter; use Mollie\Adapter\Context; use Mollie\Factory\ModuleFactory; +use Mollie\Logger\PrestaLoggerInterface; use Mollie\Repository\OrderRepositoryInterface; use Mollie\Shared\Core\Shared\Repository\CurrencyRepositoryInterface; use PHPUnit\Framework\TestCase; @@ -37,6 +38,10 @@ class BaseTestCase extends TestCase public $orderRepository; /** @var CurrencyRepositoryInterface */ public $currencyRepository; + /** @var \Cart */ + public $cart; + /** @var PrestaLoggerInterface */ + public $logger; protected function setUp(): void { @@ -47,6 +52,8 @@ protected function setUp(): void $this->moduleFactory = $this->mock(ModuleFactory::class); $this->orderRepository = $this->mock(OrderRepositoryInterface::class); $this->currencyRepository = $this->mock(CurrencyRepositoryInterface::class); + $this->cart = $this->mock(\Cart::class); + $this->logger = $this->mock(PrestaLoggerInterface::class); parent::setUp(); } diff --git a/tests/Unit/Subscription/Handler/UpdateSubscriptionCarrierHandlerTest.php b/tests/Unit/Subscription/Handler/UpdateSubscriptionCarrierHandlerTest.php new file mode 100644 index 000000000..8929b9c7f --- /dev/null +++ b/tests/Unit/Subscription/Handler/UpdateSubscriptionCarrierHandlerTest.php @@ -0,0 +1,427 @@ + + * @copyright Mollie B.V. + * @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md + * + * @see https://github.com/mollie/PrestaShop + * @codingStandardsIgnoreStart + */ + +namespace Mollie\Tests\Unit\Subscription\Handler; + +use Mollie\Exception\MollieException; +use Mollie\Service\MailService; +use Mollie\Subscription\Action\UpdateRecurringOrderAction; +use Mollie\Subscription\Action\UpdateSubscriptionAction; +use Mollie\Subscription\DTO\Object\Amount; +use Mollie\Subscription\Handler\CloneOriginalSubscriptionCartHandler; +use Mollie\Subscription\Handler\UpdateSubscriptionCarrierHandler; +use Mollie\Subscription\Provider\SubscriptionOrderAmountProvider; +use Mollie\Subscription\Repository\RecurringOrderRepositoryInterface; +use Mollie\Tests\Unit\BaseTestCase; + +class UpdateSubscriptionCarrierHandlerTest extends BaseTestCase +{ + /** @var RecurringOrderRepositoryInterface */ + private $recurringOrderRepository; + /** @var UpdateSubscriptionAction */ + private $updateSubscriptionAction; + /** @var UpdateRecurringOrderAction */ + private $updateRecurringOrderAction; + /** @var CloneOriginalSubscriptionCartHandler */ + private $cloneOriginalSubscriptionCartHandler; + /** @var SubscriptionOrderAmountProvider */ + private $subscriptionOrderAmountProvider; + /** @var MailService */ + private $mailService; + + public function setUp(): void + { + parent::setUp(); + + $this->recurringOrderRepository = $this->mock(RecurringOrderRepositoryInterface::class); + $this->updateSubscriptionAction = $this->mock(UpdateSubscriptionAction::class); + $this->updateRecurringOrderAction = $this->mock(UpdateRecurringOrderAction::class); + $this->cloneOriginalSubscriptionCartHandler = $this->mock(CloneOriginalSubscriptionCartHandler::class); + $this->subscriptionOrderAmountProvider = $this->mock(SubscriptionOrderAmountProvider::class); + $this->mailService = $this->mock(MailService::class); + } + + public function testItSuccessfullyHandles(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cart->id = 3; + $this->cart->id_customer = 1; + $this->cart->id_address_delivery = 5; + $this->cart->id_currency = 1; + + $this->cart->expects($this->once())->method('getProducts')->willReturn([ + [ + 'total_price_tax_incl' => 10.00, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willReturn($this->cart); + + $this->subscriptionOrderAmountProvider->expects($this->once())->method('get')->willReturn( + new Amount(20.00, 'EUR') + ); + + $this->updateSubscriptionAction->expects($this->once())->method('run'); + + $this->updateRecurringOrderAction->expects($this->once())->method('run'); + + $this->mailService->expects($this->once())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertEmpty($result); + } + + public function testItUnsuccessfullyHandlesMatchingCarrierId(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->never())->method('updateValue'); + + $this->context->expects($this->never())->method('getShopId'); + + $this->recurringOrderRepository->expects($this->never())->method('getAllOrdersBasedOnStatuses'); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->never())->method('run'); + + $this->subscriptionOrderAmountProvider->expects($this->never())->method('get'); + + $this->updateSubscriptionAction->expects($this->never())->method('run'); + + $this->updateRecurringOrderAction->expects($this->never())->method('run'); + + $this->mailService->expects($this->never())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(1); + + $this->assertEmpty($result); + } + + public function testItUnsuccessfullyHandlesFailedToHandleOriginalSubscriptionCartCloning(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willThrowException(new MollieException('', 0)); + + $this->subscriptionOrderAmountProvider->expects($this->never())->method('get'); + + $this->updateSubscriptionAction->expects($this->never())->method('run'); + + $this->updateRecurringOrderAction->expects($this->never())->method('run'); + + $this->mailService->expects($this->never())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertCount(1, $result); + } + + public function testItUnsuccessfullyHandlesFailedToProvideSubscriptionOrderAmount(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cart->id = 3; + $this->cart->id_customer = 1; + $this->cart->id_address_delivery = 5; + $this->cart->id_currency = 1; + + $this->cart->expects($this->once())->method('getProducts')->willReturn([ + [ + 'total_price_tax_incl' => 10.00, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willReturn($this->cart); + + $this->subscriptionOrderAmountProvider->expects($this->once())->method('get')->willThrowException(new MollieException('', 0)); + + $this->updateSubscriptionAction->expects($this->never())->method('run'); + + $this->updateRecurringOrderAction->expects($this->never())->method('run'); + + $this->mailService->expects($this->never())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertCount(1, $result); + } + + public function testItUnsuccessfullyHandlesFailedToUpdateSubscription(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cart->id = 3; + $this->cart->id_customer = 1; + $this->cart->id_address_delivery = 5; + $this->cart->id_currency = 1; + + $this->cart->expects($this->once())->method('getProducts')->willReturn([ + [ + 'total_price_tax_incl' => 10.00, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willReturn($this->cart); + + $this->subscriptionOrderAmountProvider->expects($this->once())->method('get')->willReturn( + new Amount(20.00, 'EUR') + ); + + $this->updateSubscriptionAction->expects($this->once())->method('run')->willThrowException(new MollieException('', 0)); + + $this->updateRecurringOrderAction->expects($this->never())->method('run'); + + $this->mailService->expects($this->never())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertCount(1, $result); + } + + public function testItUnsuccessfullyHandlesFailedToUpdateRecurringOrder(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cart->id = 3; + $this->cart->id_customer = 1; + $this->cart->id_address_delivery = 5; + $this->cart->id_currency = 1; + + $this->cart->expects($this->once())->method('getProducts')->willReturn([ + [ + 'total_price_tax_incl' => 10.00, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willReturn($this->cart); + + $this->subscriptionOrderAmountProvider->expects($this->once())->method('get')->willReturn( + new Amount(20.00, 'EUR') + ); + + $this->updateSubscriptionAction->expects($this->once())->method('run'); + + $this->updateRecurringOrderAction->expects($this->once())->method('run')->willThrowException(new MollieException('', 0)); + + $this->mailService->expects($this->never())->method('sendSubscriptionCarrierUpdateMail'); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertCount(1, $result); + } + + public function testItUnsuccessfullyHandlesFailedToSendSubscriptionCarrierUpdateMail(): void + { + $this->configuration->expects($this->once())->method('get')->willReturn(1); + $this->configuration->expects($this->once())->method('updateValue'); + + $this->context->expects($this->once())->method('getShopId')->willReturn(1); + + $this->recurringOrderRepository->expects($this->once())->method('getAllOrdersBasedOnStatuses')->willReturn([ + [ + 'id' => 1, + 'mollie_customer_id' => 'test-mollie-customer-id', + 'mollie_subscription_id' => 'test-mollie-subscription-id', + 'id_cart' => 2, + 'id_recurring_product' => 3, + 'id_invoice_address' => 4, + 'id_delivery_address' => 5, + ], + ]); + + $this->cart->id = 3; + $this->cart->id_customer = 1; + $this->cart->id_address_delivery = 5; + $this->cart->id_currency = 1; + + $this->cart->expects($this->once())->method('getProducts')->willReturn([ + [ + 'total_price_tax_incl' => 10.00, + ], + ]); + + $this->cloneOriginalSubscriptionCartHandler->expects($this->once())->method('run')->willReturn($this->cart); + + $this->subscriptionOrderAmountProvider->expects($this->once())->method('get')->willReturn( + new Amount(20.00, 'EUR') + ); + + $this->updateSubscriptionAction->expects($this->once())->method('run'); + + $this->updateRecurringOrderAction->expects($this->once())->method('run'); + + $this->mailService->expects($this->once())->method('sendSubscriptionCarrierUpdateMail')->willThrowException(new MollieException('', 0)); + + $updateSubscriptionCarrierHandler = new UpdateSubscriptionCarrierHandler( + $this->configuration, + $this->recurringOrderRepository, + $this->context, + $this->updateSubscriptionAction, + $this->updateRecurringOrderAction, + $this->logger, + $this->cloneOriginalSubscriptionCartHandler, + $this->subscriptionOrderAmountProvider, + $this->mailService + ); + + $result = $updateSubscriptionCarrierHandler->run(99); + + $this->assertCount(1, $result); + } +}