diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 12b3fd3..5a5b6bf 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -71,24 +71,24 @@ jobs: - name: Install module run: | - docker-compose exec -T \ + docker compose exec -T \ php composer config repositories.${{ env.PACKAGE_NAME }} \ --json '{"type":"path", "url":"./test-module", "options": {"symlink": true}}' - docker-compose exec -T \ + docker compose exec -T \ php composer require ${{ env.PACKAGE_NAME }}:* --no-interaction --no-update - name: Install dependencies and reset shop run: | - docker-compose exec -T php composer update --no-interaction - docker-compose exec -T php composer require vlucas/phpdotenv --no-interaction --dev - docker-compose exec -T php php vendor/bin/reset-shop + docker compose exec -T php composer update --no-interaction + docker compose exec -T php composer require vlucas/phpdotenv --no-interaction --dev + docker compose exec -T php php vendor/bin/reset-shop - name: Put module settings continue-on-error: true run: | mkdir -p source/var/configuration/environment/ echo "${{ secrets.MODULE_SETTINGS }}" > source/var/configuration/environment/1.yaml - docker-compose exec -T php php bin/oe-console oe:module:apply-configuration + docker compose exec -T php php bin/oe-console oe:module:apply-configuration - name: Create .env-file continue-on-error: true @@ -98,7 +98,7 @@ jobs: - name: Stop containers run: | - docker-compose down + docker compose down sleep 2 styles: @@ -175,7 +175,7 @@ jobs: - name: Run tests run: | - docker-compose exec -T \ + docker compose exec -T \ -e PARTIAL_MODULE_PATHS=${{ env.MODULE_PATH }} \ -e ACTIVATE_ALL_MODULES=1 \ -e RUN_TESTS_FOR_SHOP=0 \ @@ -224,13 +224,13 @@ jobs: - name: Install codeception dependencies run: | - docker-compose exec -T php composer require codeception/module-rest:^1.4.2 --dev --no-update - docker-compose exec -T php composer require codeception/module-phpbrowser:^1.0.2 --dev --no-update - docker-compose exec -T php composer update + docker compose exec -T php composer require codeception/module-rest:^1.4.2 --dev --no-update + docker compose exec -T php composer require codeception/module-phpbrowser:^1.0.2 --dev --no-update + docker compose exec -T php composer update - name: Run tests run: | - docker-compose exec -T \ + docker compose exec -T \ -e PARTIAL_MODULE_PATHS=${{ env.MODULE_PATH }} \ -e ACTIVATE_ALL_MODULES=1 \ -e RUN_TESTS_FOR_SHOP=0 \ @@ -241,7 +241,7 @@ jobs: - name: Stop containers if: always() run: | - docker-compose down + docker compose down sleep 2 - name: Upload log artifact diff --git a/CHANGELOG.md b/CHANGELOG.md index 52e9e74..88cd087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [2.1.6] - 2025-??-?? + +- request Adyen cancellation when finalizeOrder fails due to stock exceptions + ## [2.1.5] - 2024-03-05 - [0007571](https://bugs.oxid-esales.com/view.php?id=7571): Fix It is possible to complete a purchase (with the Adyen payment method) without paying diff --git a/src/Model/Order.php b/src/Model/Order.php index b14a505..282f163 100644 --- a/src/Model/Order.php +++ b/src/Model/Order.php @@ -12,6 +12,8 @@ use Doctrine\DBAL\Query\QueryBuilder; use OxidEsales\Eshop\Application\Model\Payment as EshopModelPayment; use OxidEsales\Eshop\Application\Model\Basket; +use OxidEsales\Eshop\Core\Exception\ArticleInputException; +use OxidEsales\Eshop\Core\Exception\NoArticleException; use OxidEsales\Eshop\Core\Registry; use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface; use OxidSolutionCatalysts\Adyen\Service\OrderIsAdyenCapturePossibleService; @@ -21,6 +23,7 @@ use OxidSolutionCatalysts\Adyen\Service\PaymentCapture; use OxidSolutionCatalysts\Adyen\Service\PaymentRefund; use OxidSolutionCatalysts\Adyen\Service\Module as ModuleService; +use OxidSolutionCatalysts\Adyen\Service\SessionSettings; use OxidSolutionCatalysts\Adyen\Traits\DataGetter; use OxidSolutionCatalysts\Adyen\Traits\ServiceContainer; @@ -28,6 +31,7 @@ * * @mixin \OxidEsales\Eshop\Application\Model\Order * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Order extends Order_parent { @@ -91,7 +95,16 @@ public function isAdyenOrderPaid(): bool */ public function finalizeOrder(Basket $basket, $user, $recalcOrder = false) { - $result = parent::finalizeOrder($basket, $user, $recalcOrder); + try { + $result = parent::finalizeOrder($basket, $user, $recalcOrder); + } catch (NoArticleException $oEx) { + $this->removeAdyenPaymentFromSession(); + throw $oEx; + } catch (ArticleInputException $oEx) { + $this->removeAdyenPaymentFromSession(); + throw $oEx; + } + $moduleService = $this->getServiceFromContainer(ModuleService::class); if ($moduleService->isAdyenPayment($this->getAdyenStringData('oxpaymenttype'))) { $pspReference = $this->getAdyenPSPReference(); @@ -469,4 +482,21 @@ public function setAdyenHistoryEntry( $adyenHistory->setAdyenAction($action); return (bool) $adyenHistory->save(); } + + protected function removeAdyenPaymentFromSession(): void + { + $session = $this->getServiceFromContainer(SessionSettings::class); + + // cancel authorization + $pspReference = $session->getPspReference(); + $reference = $session->getOrderReference(); + if ($pspReference && $reference) { + $paymentService = $this->getServiceFromContainer(PaymentCancel::class); + $paymentService->doAdyenCancel( + $pspReference, + $reference + ); + $session->deletePaymentSession(); + } + } }