diff --git a/.github/Dockerfile b/.github/Dockerfile index 61f2bbaf5..8170eec15 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -45,7 +45,7 @@ RUN a2enmod ssl RUN a2ensite default-ssl.conf #can be removed if not needed WORKDIR /var/www/html COPY config/php.ini /usr/local/etc/php/ -COPY config/install_magento.sh /tmp/install_magento.sh +COPY scripts/install_magento.sh /tmp/install_magento.sh RUN if [ -x "$(command -v apache2-foreground)" ]; then a2enmod rewrite; fi @@ -55,4 +55,4 @@ ADD "https://github.com/magento/magento2-sample-data/archive/refs/tags/${MAGENTO RUN chmod +x /tmp/install_magento.sh -CMD ["bash", "/tmp/install_magento.sh"] \ No newline at end of file +CMD ["bash", "/tmp/install_magento.sh"] diff --git a/.github/Makefile b/.github/Makefile index c437dc72b..179e2ec80 100644 --- a/.github/Makefile +++ b/.github/Makefile @@ -30,6 +30,7 @@ configure: n98-magerun2.phar bin/magento config:set payment/adyen_abstract/demo_mode 1 bin/magento adyen:enablepaymentmethods:run bin/magento config:set payment/adyen_abstract/has_holder_name 1 + bin/magento config:set payment/adyen_pay_by_link/active 1 bin/magento config:set payment/adyen_pay_by_link/days_to_expire 5 bin/magento config:set payment/adyen_giving/active 1 bin/magento config:set payment/adyen_giving/charity_description 'test' @@ -70,30 +71,15 @@ plugin: install configure flush fs: find var generated vendor pub/static pub/media app/etc -type f -exec chmod g+w {} + find var generated vendor pub/static pub/media app/etc -type d -exec chmod g+ws {} + + chmod 777 -R var chown -R www-data:www-data . chmod u+x bin/magento echo "memory_limit = -1" > /usr/local/etc/php/conf.d/memory.ini -# Deploy sample data -sampledata: - composer config http-basic.repo.magento.com "${MAGENTO_USERNAME}" "${MAGENTO_PASSWORD}" - composer config repositories.magento composer https://repo.magento.com/ - bin/magento sampledata:deploy - bin/magento setup:upgrade - # Production mode production: bin/magento deploy:mode:set production -# JavaScript bundling -bundlejs: - bin/magento config:set dev/js/enable_js_bundling 1 - bin/magento config:set dev/js/minify_files 1 - bin/magento config:set dev/static/sign 1 - bin/magento config:set dev/js/merge_files 0 - bin/magento setup:static-content:deploy - bin/magento cache:clean config - MAGENTO_ROOT=/var/www/html GRAPHQL_XML=${MAGENTO_ROOT}/dev/tests/api-functional/phpunit_graphql.xml.dist GRAPHQL_PHP=/data/extensions/workdir/Test/phpunit_graphql.php @@ -111,16 +97,6 @@ restapi: --configuration ${MAGENTO_ROOT}/dev/tests/api-functional/phpunit_rest.xml.dist \ ${MAGENTO_ROOT}/vendor/adyen/module-payment/Test/api-functional/Webapi -# Destroy services -clean: - docker-compose -f workflows/templates/docker-compose.yml down --volumes --rmi local - docker-compose -f docker-compose.yml -f docker-compose.mftf.yml down --volumes --rmi local - -# Docker image build -image: - docker-compose -f workflows/templates/docker-compose.yml -f docker-compose.e2e.yml build - docker-compose -f docker-compose.yml -f docker-compose.mftf.yml build - # Setup environment to run functional tests (https://devdocs.magento.com/mftf/docs/getting-started.html) setup-mftf: bin/magento config:set currency/options/allow USD,EUR @@ -153,19 +129,3 @@ setup-mftf: # Magento Functional Testing Framework mftf: vendor/bin/mftf run:group --remove -- AdyenMagentoSuite || vendor/bin/mftf run:failed - -# Simulate a full CI build -ci: - docker-compose -f workflows/templates/docker-compose.yml run --rm web make magento - docker-compose -f workflows/templates/docker-compose.yml up -d web - - docker exec magento2-container make fs - docker exec magento2-container make sys-check - docker exec -u www-data magento2-container make plugin - docker exec magento2-container /etc/init.d/cron stop - docker exec -u www-data magento2-container make unit - docker exec magento2-container make graphql - docker exec -u www-data magento2-container make production - docker exec magento2-container make fs - - docker-compose -f workflows/templates/docker-compose.yml run --rm playwright /e2e.sh diff --git a/.github/docker-compose.e2e.yml b/.github/docker-compose.e2e.yml index f5e35ca5b..e0842a2bd 100644 --- a/.github/docker-compose.e2e.yml +++ b/.github/docker-compose.e2e.yml @@ -1,7 +1,7 @@ version: '3' services: playwright: - image: mcr.microsoft.com/playwright:v1.41.2-focal + image: mcr.microsoft.com/playwright:v1.40.1 shm_size: 1gb ipc: host cap_add: @@ -22,7 +22,8 @@ services: - GOOGLE_PASSWORD - WEBHOOK_USERNAME - WEBHOOK_PASSWORD - volumes: - - ../../scripts/e2e.sh:/e2e.sh - - ../../../test-report:/tmp/test-report + - ./scripts/e2e.sh:/e2e.sh + - ../test-report:/tmp/test-report +networks: + backend: diff --git a/.github/docker-compose.yml b/.github/docker-compose.yml index e8ca61ded..955277350 100644 --- a/.github/docker-compose.yml +++ b/.github/docker-compose.yml @@ -29,31 +29,37 @@ services: - PHP_VERSION=${PHP_VERSION} - MAGENTO_VERSION=${MAGENTO_VERSION} container_name: magento2-container + extra_hosts: + - "magento2.test.com:127.0.0.1" networks: backend: aliases: - magento2.test.com environment: - - DB_SERVER=mariadb - - ELASTICSEARCH_SERVER=elasticsearch - - MAGENTO_HOST=magento2.test.com - - VIRTUAL_HOST=magento2.test.com - - ADMIN_URLEXT=admin - - DONATION_ACCOUNT - - ADMIN_USERNAME - - ADMIN_PASSWORD - - ADYEN_MERCHANT - - ADYEN_API_KEY - - ADYEN_CLIENT_KEY - - PHP_VERSION - - MAGENTO_VERSION - - WEBHOOK_USERNAME - - WEBHOOK_PASSWORD + DB_SERVER: mariadb + ELASTICSEARCH_SERVER: elasticsearch + MAGENTO_HOST: magento2.test.com + VIRTUAL_HOST: magento2.test.com + COMPOSER_MEMORY_LIMIT: -1 + DEPLOY_SAMPLEDATA: + DONATION_ACCOUNT: + ADMIN_USERNAME: + ADMIN_PASSWORD: + ADYEN_MERCHANT: + ADYEN_API_KEY: + ADYEN_CLIENT_KEY: + PHP_VERSION: + MAGENTO_VERSION: depends_on: - db - elastic volumes: - ../:/data/extensions/workdir - ./Makefile:/var/www/html/Makefile + - composer:/usr/local/bin + - magento:/var/www/html networks: backend: +volumes: + magento: + composer: diff --git a/.github/scripts/e2e.sh b/.github/scripts/e2e.sh index 55c97f69c..6fa230612 100755 --- a/.github/scripts/e2e.sh +++ b/.github/scripts/e2e.sh @@ -8,6 +8,7 @@ cd adyen-integration-tools-tests git checkout $INTEGRATION_TESTS_BRANCH rm -rf package-lock.json npm i +npx playwright install option="$1" diff --git a/.github/config/install_magento.sh b/.github/scripts/install_magento.sh similarity index 100% rename from .github/config/install_magento.sh rename to .github/scripts/install_magento.sh diff --git a/.github/workflows/e2e-test-dispatch.yml b/.github/workflows/e2e-test-dispatch.yml index ecca65096..2ff1d8d02 100644 --- a/.github/workflows/e2e-test-dispatch.yml +++ b/.github/workflows/e2e-test-dispatch.yml @@ -31,22 +31,22 @@ jobs: env: PHP_VERSION: "8.1" MAGENTO_VERSION: "2.4.5" + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} ADMIN_PASSWORD: ${{secrets.MAGENTO_ADMIN_PASSWORD}} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + DEPLOY_SAMPLEDATA: 1 steps: - uses: actions/checkout@v3 - name: Install Magento - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm web make magento + run: docker-compose -f .github/docker-compose.yml run --rm web make magento - name: Start web server in background - run: docker-compose -f .github/workflows/templates/docker-compose.yml up -d web - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} - + run: docker-compose -f .github/docker-compose.yml up -d web + - name: Setup permissions run: docker exec magento2-container make fs @@ -94,7 +94,7 @@ jobs: run: docker exec magento2-container make fs - name: Run E2E tests - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm playwright /e2e.sh ${{inputs.testGroup}} + run: docker-compose -f .github/docker-compose.e2e.yml run --rm playwright /e2e.sh ${{inputs.testGroup}} env: INTEGRATION_TESTS_BRANCH: ${{inputs.testBranch}} MAGENTO_ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} @@ -102,9 +102,6 @@ jobs: MAGENTO_BASE_URL: ${{secrets.MAGENTO_BASE_URL}} PAYPAL_USERNAME: ${{secrets.PLAYWRIGHT_PAYPAL_USERNAME}} PAYPAL_PASSWORD: ${{secrets.PLAYWRIGHT_PAYPAL_PASSWORD}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} GOOGLE_USERNAME: ${{secrets.GOOGLE_USERNAME}} GOOGLE_PASSWORD: ${{secrets.GOOGLE_PASSWORD}} WEBHOOK_USERNAME: admin diff --git a/.github/workflows/e2e-test-express-checkout.yml b/.github/workflows/e2e-test-express-checkout.yml index 195af205b..91e505b3f 100644 --- a/.github/workflows/e2e-test-express-checkout.yml +++ b/.github/workflows/e2e-test-express-checkout.yml @@ -21,21 +21,21 @@ jobs: env: PHP_VERSION: "8.1" MAGENTO_VERSION: "2.4.5" + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} ADMIN_PASSWORD: ${{secrets.MAGENTO_ADMIN_PASSWORD}} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + DEPLOY_SAMPLEDATA: 1 steps: - uses: actions/checkout@v3 - name: Install Magento - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm web make magento + run: docker-compose -f .github/docker-compose.yml run --rm web make magento - name: Start web server in background - run: docker-compose -f .github/workflows/templates/docker-compose.yml up -d web - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + run: docker-compose -f .github/docker-compose.yml up -d web - name: Setup permissions run: docker exec magento2-container make fs @@ -59,7 +59,7 @@ jobs: run: docker exec magento2-container make fs - name: Run E2E tests - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm playwright /e2e.sh express-checkout + run: docker-compose -f .github/docker-compose.e2e.yml run --rm playwright /e2e.sh express-checkout env: INTEGRATION_TESTS_BRANCH: develop MAGENTO_ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} @@ -67,9 +67,6 @@ jobs: MAGENTO_BASE_URL: ${{secrets.MAGENTO_BASE_URL}} PAYPAL_USERNAME: ${{secrets.PLAYWRIGHT_PAYPAL_USERNAME}} PAYPAL_PASSWORD: ${{secrets.PLAYWRIGHT_PAYPAL_PASSWORD}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} GOOGLE_USERNAME: ${{secrets.GOOGLE_USERNAME}} GOOGLE_PASSWORD: ${{secrets.GOOGLE_PASSWORD}} WEBHOOK_USERNAME: admin diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index ca67010fc..b3b2cee25 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -18,21 +18,21 @@ jobs: env: PHP_VERSION: "8.1" MAGENTO_VERSION: "2.4.5" + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} ADMIN_PASSWORD: ${{secrets.MAGENTO_ADMIN_PASSWORD}} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + DEPLOY_SAMPLEDATA: 1 steps: - uses: actions/checkout@v3 - name: Install Magento - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm web make magento + run: docker-compose -f .github/docker-compose.yml run --rm web make magento - name: Start web server in background - run: docker-compose -f .github/workflows/templates/docker-compose.yml up -d web - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + run: docker-compose -f .github/docker-compose.yml up -d web - name: Setup permissions run: docker exec magento2-container make fs @@ -72,7 +72,7 @@ jobs: run: docker exec magento2-container make fs - name: Run E2E tests - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm playwright /e2e.sh standard + run: docker-compose -f .github/docker-compose.e2e.yml run --rm playwright /e2e.sh standard env: INTEGRATION_TESTS_BRANCH: develop MAGENTO_ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} @@ -80,9 +80,6 @@ jobs: MAGENTO_BASE_URL: ${{secrets.MAGENTO_BASE_URL}} PAYPAL_USERNAME: ${{secrets.PLAYWRIGHT_PAYPAL_USERNAME}} PAYPAL_PASSWORD: ${{secrets.PLAYWRIGHT_PAYPAL_PASSWORD}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} WEBHOOK_USERNAME: admin WEBHOOK_PASSWORD: 1234 diff --git a/.github/workflows/graphql-test.yml b/.github/workflows/graphql-test.yml index ef1627349..2193cea74 100644 --- a/.github/workflows/graphql-test.yml +++ b/.github/workflows/graphql-test.yml @@ -15,20 +15,20 @@ jobs: MAGENTO_VERSION: ${{ matrix.magento-version }} ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} ADMIN_PASSWORD: ${{secrets.MAGENTO_ADMIN_PASSWORD}} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + DEPLOY_SAMPLEDATA: 1 steps: - uses: actions/checkout@v3 - name: Install Magento - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm web make magento + run: docker-compose -f .github/docker-compose.yml run --rm web make magento - name: Start web server in background - run: docker-compose -f .github/workflows/templates/docker-compose.yml up -d web - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + run: docker-compose -f .github/docker-compose.yml up -d web - name: Setup permissions run: docker exec magento2-container make fs diff --git a/.github/workflows/mftf-test.yml b/.github/workflows/mftf-test.yml index 74b27cb0b..a413c452b 100644 --- a/.github/workflows/mftf-test.yml +++ b/.github/workflows/mftf-test.yml @@ -2,7 +2,7 @@ name: Functional Tests on: workflow_dispatch: pull_request: - branches: [main] + branches: [main, develop] jobs: build: @@ -17,16 +17,16 @@ jobs: MAGENTO_VERSION: ${{ matrix.magento-version }} ADMIN_USERNAME: ${{ secrets.MAGENTO_ADMIN_USERNAME }} ADMIN_PASSWORD: ${{ secrets.MAGENTO_ADMIN_PASSWORD }} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + ADMIN_URLEXT: admin steps: - uses: actions/checkout@v3 - name: Start services run: docker-compose -f .github/docker-compose.yml -f .github/docker-compose.mftf.yml up -d - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} # Temp solution to wait for install script to run - name: Sleep for 120 seconds diff --git a/.github/workflows/restapi-test.yml b/.github/workflows/restapi-test.yml index ba4607099..ee855613c 100644 --- a/.github/workflows/restapi-test.yml +++ b/.github/workflows/restapi-test.yml @@ -15,20 +15,20 @@ jobs: MAGENTO_VERSION: ${{ matrix.magento-version }} ADMIN_USERNAME: ${{secrets.MAGENTO_ADMIN_USERNAME}} ADMIN_PASSWORD: ${{secrets.MAGENTO_ADMIN_PASSWORD}} + DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} + ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} + ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} + ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + DEPLOY_SAMPLEDATA: 1 steps: - uses: actions/checkout@v3 - name: Install Magento - run: docker-compose -f .github/workflows/templates/docker-compose.yml run --rm web make magento + run: docker-compose -f .github/docker-compose.yml run --rm web make magento - name: Start web server in background - run: docker-compose -f .github/workflows/templates/docker-compose.yml up -d web - env: - DONATION_ACCOUNT: ${{secrets.DONATION_ACCOUNT}} - ADYEN_MERCHANT: ${{secrets.ADYEN_MERCHANT}} - ADYEN_API_KEY: ${{secrets.ADYEN_API_KEY}} - ADYEN_CLIENT_KEY: ${{secrets.ADYEN_CLIENT_KEY}} + run: docker-compose -f .github/docker-compose.yml up -d web - name: Setup permissions run: docker exec magento2-container make fs diff --git a/.github/workflows/templates/docker-compose.yml b/.github/workflows/templates/docker-compose.yml deleted file mode 100644 index 18a967c9c..000000000 --- a/.github/workflows/templates/docker-compose.yml +++ /dev/null @@ -1,92 +0,0 @@ -version: '3' - -services: - db: - image: mariadb:10.4 - container_name: mariadb - environment: - MARIADB_ROOT_PASSWORD: root_password - MARIADB_DATABASE: magento - MARIADB_USER: magento - MARIADB_PASSWORD: magento - networks: - - backend - elastic: - image: elasticsearch:7.17.13 - container_name: elasticsearch - ports: - - 9200:9200 - - 9300:9300 - environment: - - "discovery.type=single-node" - - ES_JAVA_OPTS=-Xms750m -Xmx750m - networks: - - backend - web: - build: - context: ../../ - args: - - PHP_VERSION=${PHP_VERSION} - - MAGENTO_VERSION=${MAGENTO_VERSION} - container_name: magento2-container - extra_hosts: - - "magento2.test.com:127.0.0.1" - environment: - DB_SERVER: mariadb - ELASTICSEARCH_SERVER: elasticsearch - MAGENTO_HOST: magento2.test.com - VIRTUAL_HOST: magento2.test.com - COMPOSER_MEMORY_LIMIT: -1 - DEPLOY_SAMPLEDATA: 1 - DONATION_ACCOUNT: - ADMIN_USERNAME: - ADMIN_PASSWORD: - ADYEN_MERCHANT: - ADYEN_API_KEY: - ADYEN_CLIENT_KEY: - PHP_VERSION: - MAGENTO_VERSION: - WEBHOOK_PASSWORD: - WEBHOOK_USERNAME: - depends_on: - - db - - elastic - volumes: - - ../../../:/data/extensions/workdir - - composer:/usr/local/bin - - magento:/var/www/html - - ../../Makefile:/var/www/html/Makefile - networks: - backend: - aliases: - - magento2.test.com - playwright: - image: mcr.microsoft.com/playwright:focal - shm_size: 1gb - ipc: host - cap_add: - - SYS_ADMIN - networks: - - backend - environment: - - INTEGRATION_TESTS_BRANCH - - MAGENTO_BASE_URL - - MAGENTO_ADMIN_USERNAME - - MAGENTO_ADMIN_PASSWORD - - PAYPAL_USERNAME - - PAYPAL_PASSWORD - - ADYEN_API_KEY - - ADYEN_CLIENT_KEY - - ADYEN_MERCHANT - - GOOGLE_USERNAME - - GOOGLE_PASSWORD - - WEBHOOK_USERNAME - - WEBHOOK_PASSWORD - volumes: - - ../../scripts/e2e.sh:/e2e.sh - - ../../../test-report:/tmp/test-report -networks: - backend: -volumes: - magento: - composer: diff --git a/Controller/Return/Index.php b/Controller/Return/Index.php index a679a6557..9c424ff5f 100755 --- a/Controller/Return/Index.php +++ b/Controller/Return/Index.php @@ -92,6 +92,7 @@ public function execute(): void { // Receive all params as this could be a GET or POST request $redirectResponse = $this->getRequest()->getParams(); + $storeId = $this->storeManager->getStore()->getId(); if ($redirectResponse) { $result = $this->validateRedirectResponse($redirectResponse); @@ -104,9 +105,9 @@ public function execute(): void $successPath = $failPath = 'multishipping/checkout/success'; $setQuoteAsActive = true; } else { - $successPath = $this->configHelper->getAdyenAbstractConfigData('custom_success_redirect_path') ?? + $successPath = $this->configHelper->getAdyenAbstractConfigData('custom_success_redirect_path', $storeId) ?? 'checkout/onepage/success'; - $failPath = $this->configHelper->getAdyenAbstractConfigData('return_path'); + $failPath = $this->configHelper->getAdyenAbstractConfigData('return_path', $storeId); $setQuoteAsActive = false; } @@ -114,7 +115,7 @@ public function execute(): void $this->session->getQuote()->setIsActive($setQuoteAsActive)->save(); // Add OrderIncrementId to redirect parameters for headless support. - $redirectParams = $this->configHelper->getAdyenAbstractConfigData('custom_success_redirect_path') + $redirectParams = $this->configHelper->getAdyenAbstractConfigData('custom_success_redirect_path', $storeId) ? ['_query' => ['utm_nooverride' => '1', 'order_increment_id' => $this->order->getIncrementId()]] : ['_query' => ['utm_nooverride' => '1']]; $this->_redirect($successPath, $redirectParams); @@ -134,7 +135,7 @@ public function execute(): void $this->_redirect($failPath, ['_query' => ['utm_nooverride' => '1']]); } } else { - $this->_redirect($this->configHelper->getAdyenAbstractConfigData('return_path')); + $this->_redirect($this->configHelper->getAdyenAbstractConfigData('return_path', $storeId)); } } diff --git a/Gateway/Request/CheckoutDataBuilder.php b/Gateway/Request/CheckoutDataBuilder.php index e7661e8b4..3c53d55ca 100644 --- a/Gateway/Request/CheckoutDataBuilder.php +++ b/Gateway/Request/CheckoutDataBuilder.php @@ -16,11 +16,9 @@ use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\StateData; use Adyen\Payment\Helper\OpenInvoice; -use Adyen\Payment\Model\Ui\AdyenBoletoConfigProvider; use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; use Adyen\Payment\Observer\AdyenCcDataAssignObserver; use Adyen\Payment\Observer\AdyenPaymentMethodDataAssignObserver; -use Magento\Catalog\Helper\Image; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Payment\Gateway\Data\PaymentDataObject; use Magento\Payment\Gateway\Helper\SubjectReader; @@ -40,28 +38,32 @@ class CheckoutDataBuilder implements BuilderInterface /** * @var Data */ - private $adyenHelper; + private Data $adyenHelper; /** * @var CartRepositoryInterface */ - private $cartRepository; + private CartRepositoryInterface $cartRepository; /** * @var ChargedCurrency */ - private $chargedCurrency; + private ChargedCurrency $chargedCurrency; /** * @var StateData */ - private $stateData; + private StateData $stateData; - /** @var Config */ - private $configHelper; + /** + * @var Config + */ + private Config $configHelper; - /** @var OpenInvoice */ - private $openInvoiceHelper; + /** + * @var OpenInvoice + */ + private OpenInvoice $openInvoiceHelper; /** * CheckoutDataBuilder constructor. diff --git a/Helper/PaymentMethods.php b/Helper/PaymentMethods.php index 3e21ae4f0..c358103ef 100644 --- a/Helper/PaymentMethods.php +++ b/Helper/PaymentMethods.php @@ -13,9 +13,15 @@ use Adyen\AdyenException; use Adyen\Client; +use Adyen\ConnectionException; use Adyen\Payment\Logger\AdyenLogger; use Adyen\Payment\Model\Notification; +use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider; +use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; +use Adyen\Payment\Model\Ui\AdyenPosCloudConfigProvider; use Adyen\Util\ManualCapture; +use Exception; +use Magento\Framework\App\Area; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; @@ -54,6 +60,15 @@ class PaymentMethods extends AbstractHelper const ADYEN_GROUP_ALTERNATIVE_PAYMENT_METHODS = 'adyen-alternative-payment-method'; + /* + * Following payment methods should be enabled with their own configuration path. + */ + const EXCLUDED_PAYMENT_METHODS = [ + AdyenPayByLinkConfigProvider::CODE, + AdyenPosCloudConfigProvider::CODE, + AdyenMotoConfigProvider::CODE + ]; + protected CartRepositoryInterface $quoteRepository; protected ScopeConfigInterface $config; protected Data $adyenHelper; @@ -116,7 +131,7 @@ public function getPaymentMethods(int $quoteId, ?string $country = null, ?string $quote = $this->quoteRepository->getActive($quoteId); // If quote cannot be found early return the empty paymentMethods array if (empty($quote)) { - return []; + return ''; } $this->setQuote($quote); @@ -153,6 +168,10 @@ public function togglePaymentMethodsActivation(?bool $isActive =null): array } foreach ($this->getAdyenPaymentMethods() as $paymentMethod) { + if (in_array($paymentMethod, self::EXCLUDED_PAYMENT_METHODS)) { + continue; + } + $value = $isActive ? '1': '0'; $field = 'active'; $this->configHelper->setConfigData($value, $field, $paymentMethod); @@ -199,12 +218,12 @@ protected function getCurrentPaymentAmount(): float $total = $this->chargedCurrency->getQuoteAmountCurrency($this->getQuote())->getAmount(); if (!is_numeric($total)) { - throw new \Exception( + $exceptionMessage = sprintf( 'Cannot retrieve a valid grand total from quote ID: `%s`. Expected a numeric value.', $this->getQuote()->getEntityId() - ) ); + throw new AdyenException($exceptionMessage); } $total = (float)$total; @@ -212,14 +231,13 @@ protected function getCurrentPaymentAmount(): float if ($total >= 0) { return $total; } - - throw new \Exception( + $exceptionMessage = sprintf( 'Cannot retrieve a valid grand total from quote ID: `%s`. Expected a float >= `0`, got `%f`.', $this->getQuote()->getEntityId(), $total - ) - ); + ); + throw new AdyenException($exceptionMessage); } protected function getCurrentCountryCode(Store $store): string @@ -263,7 +281,7 @@ protected function getPaymentMethodsResponse(array $requestParams, Store $store) // return empty result return []; } - catch (\Adyen\ConnectionException $e) { + catch (ConnectionException $e) { $this->adyenLogger->error( "Connection to the endpoint failed. Check the Adyen Live endpoint prefix configuration." ); @@ -337,7 +355,7 @@ protected function showLogosPaymentMethods(array $paymentMethods, array $payment // Explicitly setting theme $themeCode = "Magento/blank"; - $themeId = $this->design->getConfigurationDesignTheme(\Magento\Framework\App\Area::AREA_FRONTEND); + $themeId = $this->design->getConfigurationDesignTheme(Area::AREA_FRONTEND); if (!empty($themeId)) { $theme = $this->themeProvider->getThemeById($themeId); if ($theme && !empty($theme->getCode())) { @@ -348,7 +366,7 @@ protected function showLogosPaymentMethods(array $paymentMethods, array $payment $params = []; $params = array_merge( [ - 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, + 'area' => Area::AREA_FRONTEND, '_secure' => $this->request->isSecure(), 'theme' => $themeCode ], @@ -674,8 +692,8 @@ public function getBoletoStatus(Order $order, Notification $notification, string // check if paid amount is the same as orginal amount $originalAmount = isset($boletobancario['originalAmount']) ? - trim((string) $boletobancario['originalAmount']) : - ""; + trim((string) $boletobancario['originalAmount']) : + ""; $paidAmount = isset($boletobancario['paidAmount']) ? trim((string) $boletobancario['paidAmount']) : ""; if ($originalAmount != $paidAmount) { diff --git a/Helper/Webhook.php b/Helper/Webhook.php index ce8c3009c..39f74c54e 100644 --- a/Helper/Webhook.php +++ b/Helper/Webhook.php @@ -421,7 +421,9 @@ private function updateAdyenAttributes(Order $order, Notification $notification) * the previous notification was authorisation : true do not update pspreference */ if (!$notification->isSuccessful()) { - $previousAdyenEventCode = $order->getData('adyen_notification_event_code'); + $previousAdyenEventCode = $this->orderRepository + ->get($order->getId()) + ->getData('adyen_notification_event_code'); if ($previousAdyenEventCode != "AUTHORISATION : TRUE") { $this->updateOrderPaymentWithAdyenAttributes($order->getPayment(), $notification, $additionalData); } diff --git a/Model/Config/Backend/PaymentMethodsStatus.php b/Model/Config/Backend/PaymentMethodsStatus.php index d3e9debfc..199a1f8e7 100644 --- a/Model/Config/Backend/PaymentMethodsStatus.php +++ b/Model/Config/Backend/PaymentMethodsStatus.php @@ -12,12 +12,8 @@ namespace Adyen\Payment\Model\Config\Backend; use Adyen\Payment\Helper\PaymentMethods; -use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider; -use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; -use Adyen\Payment\Model\Ui\AdyenPosCloudConfigProvider; use Magento\Framework\App\Cache\TypeListInterface; use Magento\Framework\App\Config\ScopeConfigInterface; -use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\App\Config\Value; use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Model\Context; @@ -27,29 +23,17 @@ class PaymentMethodsStatus extends Value { protected PaymentMethods $paymentMethodsHelper; - private WriterInterface $configWriter; - - /* - * Following payment methods should be enabled with their own configuration path. - */ - const EXCLUDED_PAYMENT_METHODS = [ - AdyenPayByLinkConfigProvider::CODE, - AdyenPosCloudConfigProvider::CODE, - AdyenMotoConfigProvider::CODE - ]; public function __construct( Context $context, Registry $registry, ScopeConfigInterface $config, TypeListInterface $cacheTypeList, - WriterInterface $configWriter, PaymentMethods $paymentMethodsHelper, AbstractResource $resource = null, AbstractDb $resourceCollection = null, array $data = [] ) { - $this->configWriter = $configWriter; $this->paymentMethodsHelper = $paymentMethodsHelper; parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data); @@ -57,20 +41,7 @@ public function __construct( public function afterSave(): PaymentMethodsStatus { - $value = $this->getValue(); - $adyenPaymentMethods = $this->paymentMethodsHelper->getAdyenPaymentMethods(); - - foreach ($adyenPaymentMethods as $adyenPaymentMethod) { - // Exclude following payment methods. They need to use their own configuration path. - if (in_array($adyenPaymentMethod, self::EXCLUDED_PAYMENT_METHODS)) { - continue; - } - - $this->configWriter->save( - 'payment/' . $adyenPaymentMethod . '/active', - $value, - ); - } + $this->paymentMethodsHelper->togglePaymentMethodsActivation((bool) $this->getValue()); return $this; } diff --git a/Model/Ui/AdyenCcConfigProvider.php b/Model/Ui/AdyenCcConfigProvider.php index aaead157b..ece2d81ee 100755 --- a/Model/Ui/AdyenCcConfigProvider.php +++ b/Model/Ui/AdyenCcConfigProvider.php @@ -103,8 +103,10 @@ public function getConfig(): array $storeId = $this->storeManager->getStore()->getId(); $cardRecurringEnabled = $this->vaultHelper->getPaymentMethodRecurringActive(self::CODE, $storeId); + $methodTitle = $this->configHelper->getConfigData('title', Config::XML_ADYEN_CC, $storeId); $config['payment']['adyenCc']['methodCode'] = self::CODE; + $config['payment']['adyenCc']['title'] = __($methodTitle); $config['payment']['adyenCc']['locale'] = $this->adyenHelper->getStoreLocale($storeId); $config['payment']['adyenCc']['isCardRecurringEnabled'] = $cardRecurringEnabled; $config['payment']['adyenCc']['icons'] = $this->getIcons(); diff --git a/Setup/Recurring.php b/Setup/RecurringData.php similarity index 73% rename from Setup/Recurring.php rename to Setup/RecurringData.php index c324843bf..1b67f63f2 100644 --- a/Setup/Recurring.php +++ b/Setup/RecurringData.php @@ -4,11 +4,12 @@ use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Helper\PaymentMethodsFactory; -use Magento\Framework\Setup\InstallSchemaInterface; +use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\SchemaSetupInterface; -class Recurring implements InstallSchemaInterface +class RecurringData implements InstallDataInterface { private PaymentMethodsFactory $paymentMethodsFactory; @@ -19,7 +20,7 @@ public function __construct( $this->paymentMethodsFactory = $paymentMethodsFactory; } - public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $paymentMethods = $this->paymentMethodsFactory->create(); @@ -28,3 +29,4 @@ public function install(SchemaSetupInterface $setup, ModuleContextInterface $con $setup->endSetup(); } } + diff --git a/Test/Unit/Controller/Return/IndexTest.php b/Test/Unit/Controller/Return/IndexTest.php index bdad75ca4..6b91a1e8f 100644 --- a/Test/Unit/Controller/Return/IndexTest.php +++ b/Test/Unit/Controller/Return/IndexTest.php @@ -29,6 +29,7 @@ use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Payment; use Magento\Sales\Model\OrderFactory; +use Magento\Store\Api\Data\StoreInterface; use Magento\Store\Model\StoreManagerInterface; class IndexTest extends AbstractAdyenTestCase @@ -41,6 +42,7 @@ class IndexTest extends AbstractAdyenTestCase private $quoteMock; private $orderEntityMock; private $paymentEntityMock; + private $storeMock; private $contextMock; private $orderFactoryMock; @@ -52,6 +54,8 @@ class IndexTest extends AbstractAdyenTestCase private $paymentsDetailsHelperMock; private $paymentResponseHandlerMock; + const STORE_ID = 1; + protected function setUp(): void { // Constructor argument mocks @@ -92,10 +96,13 @@ protected function setUp(): void $this->contextMock->method('getResponse')->willReturn($this->contextResponseMock); $this->configHelperMock->method('getAdyenAbstractConfigData')->will( $this->returnValueMap([ - ['return_path', null, '/checkout/cart'], - ['custom_success_redirect_path', null, null] + ['return_path', self::STORE_ID, '/checkout/cart'], + ['custom_success_redirect_path', self::STORE_ID, null] ]) ); + $this->storeMock = $this->createMock(StoreInterface::class); + $this->storeMock->method('getId')->willReturn(self::STORE_ID); + $this->storeManagerMock->method('getStore')->willReturn($this->storeMock); $this->indexControllerMock = new Index( $this->contextMock, diff --git a/Test/Unit/Helper/PaymentMethodsTest.php b/Test/Unit/Helper/PaymentMethodsTest.php index 647b5bedd..2220072df 100644 --- a/Test/Unit/Helper/PaymentMethodsTest.php +++ b/Test/Unit/Helper/PaymentMethodsTest.php @@ -11,14 +11,18 @@ namespace Adyen\Payment\Test\Unit\Helper; +use Adyen\Client; +use Adyen\ConnectionException; use Adyen\Payment\Helper\ChargedCurrency; use Adyen\Payment\Helper\Config; use Adyen\Payment\Helper\Data as AdyenDataHelper; use Adyen\Payment\Helper\Data; use Adyen\Payment\Helper\PaymentMethods; use Adyen\Payment\Logger\AdyenLogger; +use Adyen\Payment\Model\AdyenAmountCurrency; use Adyen\Payment\Model\Notification; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Adyen\Service\Checkout; use Adyen\Util\ManualCapture; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Helper\Context; @@ -26,14 +30,23 @@ use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\View\Asset\File; use Magento\Framework\View\Asset\Repository; use Magento\Framework\View\Asset\Source; +use Magento\Framework\View\Design\ThemeInterface; use Magento\Framework\View\DesignInterface; use Magento\Framework\View\Design\Theme\ThemeProviderInterface; use Magento\Payment\Helper\Data as MagentoDataHelper; use Magento\Payment\Model\MethodInterface; use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote\Address; use Magento\Sales\Model\Order; +use Magento\Quote\Model\Quote; +use Magento\Store\Model\Store; +use ReflectionClass; +use Adyen\AdyenException; +use Exception; +use ReflectionMethod; class PaymentMethodsTest extends AbstractAdyenTestCase { @@ -60,7 +73,12 @@ protected function setUp(): void { $this->contextMock = $this->createMock(Context::class); $this->quoteRepositoryMock = $this->createMock(CartRepositoryInterface::class); - $this->configMock = $this->createMock(ScopeConfigInterface::class); + $this->configMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->billingAddressMock = $this->getMockBuilder(Address::class) + ->disableOriginalConstructor() + ->getMock(); $this->adyenHelperMock = $this->createMock(Data::class); $this->localeResolverMock = $this->createMock(ResolverInterface::class); $this->adyenLoggerMock = $this->createMock(AdyenLogger::class); @@ -75,6 +93,23 @@ protected function setUp(): void $this->manualCaptureMock = $this->createMock(ManualCapture::class); $this->serializerMock = $this->createMock(SerializerInterface::class); $this->adyenDataHelperMock = $this->createMock(AdyenDataHelper::class); + $this->amountCurrencyMock = $this->createMock(AdyenAmountCurrency::class); + $this->methodMock = $this->createMock(MethodInterface::class); + $this->orderMock = $this->createMock(Order::class); + $this->notificationMock = $this->createMock(Notification::class); + $this->orderPaymentMock = $this->getMockBuilder(Order\Payment::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->storeMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $this->quoteMock = $this->getMockBuilder(Quote::class) + ->addMethods(['getCustomerId']) + ->onlyMethods(['getStore','getBillingAddress','getEntityId']) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager = new ObjectManager($this); // Instantiate the PaymentMethods helper class with the mocked dependencies $this->paymentMethodsHelper = new PaymentMethods( @@ -108,30 +143,23 @@ public function testCompareOrderAndWebhookPaymentMethods( $ccType = null ) { - $objectManager = new ObjectManager($this); - $paymentMethodsHelper = $objectManager->getObject(PaymentMethods::class, []); - $methodMock = $this->createMock(MethodInterface::class); - $methodMock->method('getConfigData') + $paymentMethodsHelper = $this->objectManager->getObject(PaymentMethods::class, []); + $this->methodMock->method('getConfigData') ->willReturnMap([ ['group', null, PaymentMethods::ADYEN_GROUP_ALTERNATIVE_PAYMENT_METHODS], ['is_wallet', null, '0'] ]); - $methodMock->method('getCode')->willReturn($orderPaymentMethod); - - $paymentMock = $this->createMock(Order\Payment::class); - $paymentMock->method('getMethodInstance')->willReturn($methodMock); - $paymentMock->method('getMethod')->willReturn($orderPaymentMethod); - $paymentMock->method('getCcType')->willReturn($ccType); - - $orderMock = $this->createMock(Order::class); - $orderMock->method('getPayment')->willReturn($paymentMock); + $this->methodMock->method('getCode')->willReturn($orderPaymentMethod); - $notificationMock = $this->createMock(Notification::class); - $notificationMock->method('getPaymentMethod')->willReturn($notificationPaymentMethod); + $this->orderPaymentMock->method('getMethodInstance')->willReturn($this->methodMock); + $this->orderPaymentMock->method('getMethod')->willReturn($orderPaymentMethod); + $this->orderPaymentMock->method('getCcType')->willReturn($ccType); + $this->orderMock->method('getPayment')->willReturn($this->orderPaymentMock); + $this->notificationMock->method('getPaymentMethod')->willReturn($notificationPaymentMethod); $this->assertEquals( $assert, - $paymentMethodsHelper->compareOrderAndWebhookPaymentMethods($orderMock, $notificationMock) + $paymentMethodsHelper->compareOrderAndWebhookPaymentMethods($this->orderMock, $this->notificationMock) ); } @@ -170,7 +198,10 @@ public function testTogglePaymentMethodsActivation() [ 'adyen_cc' => [], 'adyen_oneclick' => [], - 'adyen_cc_vault' => [] + 'adyen_cc_vault' => [], + 'adyen_pos_cloud' => [], + 'adyen_moto' => [], + 'adyen_pay_by_link' => [], ]); $this->configHelperMock @@ -188,4 +219,1061 @@ public function testTogglePaymentMethodsActivation() $paymentMethods ); } + + //Successfully retrieve payment methods for a valid quote ID. getPaymentMethods + public function testSuccessfullyRetrievePaymentMethodsForValidQuoteId() + { + $quoteId = 123; // Example valid quote ID + $country = 'US'; // Example country + $shopperLocale = 'en_US'; // Example shopper locale + $storeId = 1; + + $this->storeMock->expects($this->any()) + ->method('getId') + ->willReturn($storeId); + + // Mock the getId method of the quote to return the quoteId + $this->quoteMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + + // Mock the quote repository to return the quote mock + $this->quoteRepositoryMock->expects($this->once()) + ->method('getActive') + ->with($quoteId) + ->willReturn($this->quoteMock); + + // Perform the test + $result = $this->paymentMethodsHelper->getPaymentMethods($quoteId, $country, $shopperLocale); + + $this->assertNotEmpty($result); + } + + public function testRetrievePaymentMethodsWithInvalidQuoteId() + { + $invalidQuoteId = 999; // Example invalid quote ID + $country = 'US'; // Example country + $shopperLocale = 'en_US'; // Example shopper locale + + // Mock the quote repository to return null for an invalid quote ID + $this->quoteRepositoryMock->expects($this->once()) + ->method('getActive') + ->with($invalidQuoteId) + ->willReturn(null); + + // Perform the test + $result = $this->paymentMethodsHelper->getPaymentMethods($invalidQuoteId, $country, $shopperLocale); + + // Assert that the result is an array + $this->assertEmpty($result); + } + + public function testGetAdyenPaymentMethods() + { + // Mock the Data helper class + $dataHelperMock = $this->getMockBuilder(MagentoDataHelper::class) + ->disableOriginalConstructor() + ->getMock(); + + // Define the list of payment methods to be returned by the mock + $paymentMethods = [ + 'adyen_cc' => [], + 'adyen_oneclick' => [], + 'paypal' => [], // Non-Adyen payment method + 'adyen_sepa' => [], + ]; + + // Set up the expected filtered Adyen payment methods + $expectedAdyenPaymentMethods = [ + 'adyen_cc', + 'adyen_oneclick', + 'adyen_sepa', + ]; + + // Set up the mock to return the predefined list of payment methods + $dataHelperMock->expects($this->once()) + ->method('getPaymentMethodList') + ->willReturn($paymentMethods); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'dataHelper' => $dataHelperMock, + ] + ); + + // Call the getAdyenPaymentMethods() method + $actualAdyenPaymentMethods = $paymentMethods->getAdyenPaymentMethods(); + + // Assert that the returned array contains only the expected Adyen payment methods + $this->assertEquals($expectedAdyenPaymentMethods, $actualAdyenPaymentMethods); + + } + + public function testIsAdyenPayment() + { + // Define the list of Adyen payment methods + $adyenPaymentMethods = [ + 'adyen_cc' => [], + 'adyen_oneclick' => [], + 'paypal' => [], // Non-Adyen payment method + 'adyen_sepa' => [], + ]; + + // Set up the mock to return the predefined list of Adyen payment methods + $this->dataHelperMock->expects($this->exactly(2)) + ->method('getPaymentMethodList') + ->willReturn($adyenPaymentMethods); + + // Test for an Adyen payment method code + $this->assertTrue($this->paymentMethodsHelper->isAdyenPayment('adyen_cc')); + + // Test for a non-Adyen payment method code + $this->assertFalse($this->paymentMethodsHelper->isAdyenPayment('paypal')); + } + + /** + * @throws ReflectionExceptionAlias + */ + private function getPrivateMethod(string $className, string $methodName): ReflectionMethod + { + $reflectionClass = new ReflectionClass($className); + $method = $reflectionClass->getMethod($methodName); + $method->setAccessible(true); + return $method; + } + + public function testFetchPaymentMethodsWhenMerchantAccountEmpty() + { + $country = 'US'; + $shopperLocale = 'en_US'; + + // Invoke the private method + $fetchPaymentMethodsMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'fetchPaymentMethods' + ); + + $storeId = 1; + + $this->storeMock->expects($this->any()) + ->method('getId') + ->willReturn($storeId); + + // Mock the getId method of the quote to return the quoteId + $this->quoteMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + + $paymentMethodsHelper = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + ] + ); + + // Call the protected method with the necessary parameters + $result = $fetchPaymentMethodsMethod->invoke($paymentMethodsHelper, $country, $shopperLocale); + + // Assert the result + $this->assertIsString($result); // Ensure the result is a string + + $this->assertEquals(json_encode([]), $result); + } + + public function testFetchPaymentMethodsWithEmptyResponseFromAdyenApi() + { + $quoteId = 1; + $storeId = 1; + $amountValue = 100; + $adyenClientMock = $this->createMock(Client::class); + $checkoutServiceMock = $this->createMock(Checkout::class); + // Setup test scenario + $this->storeMock->expects($this->any()) + ->method('getId') + ->willReturn($quoteId); + + // Mock the getId method of the quote to return the quoteId + $this->quoteMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + $this->configHelperMock->expects($this->once()) + ->method('getAdyenAbstractConfigData') + ->with('merchant_account', $storeId) // Ensure it's called with the expected parameters + ->willReturn('mocked_merchant_account'); // Define the return value for the mocked method + $this->adyenHelperMock->method('initializeAdyenClient')->willReturn($adyenClientMock); + $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); + $this->amountCurrencyMock->method('getAmount')->willReturn($amountValue); + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + $this->billingAddressMock->expects($this->once()) + ->method('getCountryId') + ->willReturn('NL'); + $this->quoteMock + ->method('getBillingAddress') + ->willReturn($this->billingAddressMock); + // Simulate successful API call + $checkoutServiceMock->expects($this->once()) + ->method('paymentMethods') + ->willThrowException(new AdyenException("The Payment methods response is empty check your Adyen configuration in Magento.")); + + $fetchPaymentMethodsMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'fetchPaymentMethods' + ); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + 'chargedCurrency' => $this->chargedCurrencyMock, + 'adyenHelper' => $this->adyenHelperMock + ] + ); + + // Execute method of the tested class + $result = $fetchPaymentMethodsMethod->invoke($paymentMethods, null, null); + + // Assert conditions + $this->assertEquals(json_encode([]), $result); + } + + public function testSuccessfulRetrievalOfPaymentMethods() + { + $expectedResult = [ + 'paymentMethods' => [ + '0' => [ + 'type' => 'method1' + ], + '1' => [ + 'type' => 'method1' + ] + ] + ]; + + $adyenClientMock = $this->createMock(Client::class); + $checkoutServiceMock = $this->createMock(Checkout::class); + $quoteId = 1; + $storeId = 1; + $amountValue = '100'; + + $requestParams = [ + "channel" => "Web", + "merchantAccount" => 'MagentoMerchantTest', + "shopperReference" => 'SomeShopperRef', + "countryCode" => 'NL', + "shopperLocale" => 'nl-NL', + "amount" => [ + "currency" => 'EUR', + "value" => $amountValue + ] + ]; + + $paymentMethodsExtraDetails['type']['configuration'] = [ + 'amount' => [ + 'value' => $amountValue, + 'currency' => 'EUR' + ], + 'currency' => 'EUR', + ]; + + // Create a partial mock for your class + $paymentMethodsMock = $this->getMockBuilder(PaymentMethods::class) + ->onlyMethods(['getPaymentMethodsRequest', 'addExtraConfigurationToPaymentMethods']) // Specify the method(s) to mock + ->disableOriginalConstructor() + ->getMock(); + + // Set up the expectation for the mocked method + $paymentMethodsMock->expects($this->any()) + ->method('getPaymentMethodsRequest') + ->willReturn($requestParams); + + $paymentMethodsMock->expects($this->any()) + ->method('addExtraConfigurationToPaymentMethods') + ->willReturn($paymentMethodsExtraDetails); + + $this->adyenHelperMock->method('initializeAdyenClient')->willReturn($adyenClientMock); + + $this->adyenHelperMock->method('createAdyenCheckoutService')->willReturn($checkoutServiceMock); + + // Simulate successful API call + $checkoutServiceMock->expects($this->once()) + ->method('paymentMethods') + ->willReturn($expectedResult); + + $this->storeMock->expects($this->any()) + ->method('getId') + ->willReturn($quoteId); + + // Mock the getId method of the quote to return the quoteId + $this->quoteMock->expects($this->any()) + ->method('getStore') + ->willReturn($this->storeMock); + + $this->configHelperMock->expects($this->once()) + ->method('getAdyenAbstractConfigData') + ->with('merchant_account', $storeId) // Ensure it's called with the expected parameters + ->willReturn('mocked_merchant_account'); // Define the return value for the mocked method + + + $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); + $this->amountCurrencyMock->method('getAmount')->willReturn($amountValue); + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + + $this->adyenHelperMock->expects($this->once()) + ->method('logResponse') + ->with($expectedResult); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + 'chargedCurrency' => $this->chargedCurrencyMock, + 'adyenHelper' => $this->adyenHelperMock, + 'paymentMethods' => $paymentMethodsMock, + ] + ); + $fetchPaymentMethodsMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'fetchPaymentMethods' + ); + $result = $fetchPaymentMethodsMethod->invoke($paymentMethods, 'NL', 'nl_NL'); + + $this->assertJson($result); + } + + public function testGetCurrentCountryCodeWithBillingAddressSet() + { + $this->billingAddressMock->expects($this->once()) + ->method('getCountryId') + ->willReturn('NL'); // Simulate the billing address country is set to US + $this->quoteMock->expects($this->once()) + ->method('getBillingAddress') + ->willReturn($this->billingAddressMock); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock + ] + ); + + $getCurrentCountryCodeMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentCountryCode' + ); + + $result = $getCurrentCountryCodeMethod->invoke($paymentMethods, $this->storeMock); + + // Assert that the expected country code is returned + $this->assertEquals('NL', $result); + } + + public function testGetCurrentCountryCodeWithNoBillingAddressSet() + { + $storeMock = $this->getMockBuilder(Store::class) + ->disableOriginalConstructor() + ->getMock(); + $mockNoCountry = null; + + // Set up expectations for the mocked objects + $billingAddressMock = $this->getMockBuilder(Address::class) + ->disableOriginalConstructor() + ->getMock(); + $billingAddressMock->expects($this->once()) + ->method('getCountryId') + ->willReturn($mockNoCountry); + $this->quoteMock->expects($this->once()) + ->method('getBillingAddress') + ->willReturn($billingAddressMock); + + $this->configMock->expects($this->any()) + ->method('getValue') + ->willReturn('GB'); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'config' => $this->configMock, + ] + ); + + $getCurrentCountryCodeMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentCountryCode' + ); + + $result = $getCurrentCountryCodeMethod->invoke($paymentMethods, $storeMock); + + // Assert that the expected country code is returned + $this->assertEquals('GB', $result); + } + + public function testGetCurrentPaymentAmountWithValidPositiveNumber() + { + // Create a mock for AdyenAmountCurrency + $this->amountCurrencyMock->method('getAmount')->willReturn(100); // Valid positive number + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + + // Create an instance of PaymentMethods with mocked dependencies + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'chargedCurrency' => $this->chargedCurrencyMock + ] + ); + + $getCurrentPaymentAmountMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentPaymentAmount' + ); + $result = $getCurrentPaymentAmountMethod->invoke($paymentMethods); + + // Assert that the expected positive float is returned + $this->assertEquals(100.0, $result); + } + + public function testGetCurrentPaymentAmountWithNonNumericValue() + { + $this->amountCurrencyMock->method('getAmount')->willReturn('invalid_value'); + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + + $this->quoteMock->expects($this->once()) + ->method('getEntityId') + ->willReturn(1); + + // Create an instance of PaymentMethods with mocked dependencies + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, // Inject the mocked quote + 'chargedCurrency' => $this->chargedCurrencyMock // Inject the mocked chargedCurrency + ] + ); + + $getCurrentPaymentAmountMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentPaymentAmount' + ); + + // Assert that an Exception is thrown when the total amount is not a valid number + try { + $getCurrentPaymentAmountMethod->invoke($paymentMethods); + } catch (Exception $e) { + $this->assertInstanceOf(Exception::class, $e); + $this->assertEquals("Cannot retrieve a valid grand total from quote ID: `1`. Expected a numeric value.", $e->getMessage()); + return; + } + + // If no exception is thrown, fail the test + $this->fail('An expected exception has not been raised.'); + } + + public function testGetCurrentPaymentAmountWithNegativeNumber() + { + $this->amountCurrencyMock->method('getAmount')->willReturn(-100); // Negative number + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + + // Create an instance of PaymentMethods with mocked dependencies + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, // Inject the mocked quote + 'chargedCurrency' => $this->chargedCurrencyMock // Inject the mocked chargedCurrency + ] + ); + $getCurrentPaymentAmountMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentPaymentAmount' + ); + + // Assert that an Exception is thrown when the total amount is negative + $this->expectException(Exception::class); + $getCurrentPaymentAmountMethod->invoke($paymentMethods); + } + + public function testGetCurrentShopperReferenceWithCustomerId() + { + $this->quoteMock->expects($this->any()) + ->method('getCustomerId') + ->willReturn(123); + + // Create an instance of PaymentMethods with the mocked Quote + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock + ] + ); + + $getCurrentShopperReferenceMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentShopperReference' + ); + + // Call the method and assert that it returns the expected shopper reference + $result = $getCurrentShopperReferenceMethod->invoke($paymentMethods); + $this->assertEquals('123', $result); // Expecting the customerId to be cast to string + } + + public function testGetCurrentShopperReferenceWithoutCustomerId() + { + $this->quoteMock->method('getCustomerId')->willReturn(null); + + // Create an instance of PaymentMethods with the mocked Quote + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock + ] + ); + $getCurrentShopperReferenceMethod = $this->getPrivateMethod( + PaymentMethods::class, + 'getCurrentShopperReference' + ); + + // Call the method and assert that it returns null when customerId is not set + $result = $getCurrentShopperReferenceMethod->invoke($paymentMethods); + $this->assertNull($result); + } + + public function testIsBankTransfer() + { + // Test with bank transfer payment method + $paymentMethod = 'bankTransferNL'; + $this->assertTrue($this->paymentMethodsHelper->isBankTransfer($paymentMethod)); + + // Test with non-bank transfer payment method + $paymentMethod = 'adyen_cc'; + $this->assertFalse($this->paymentMethodsHelper->isBankTransfer($paymentMethod)); + } + + public function testIsWalletPaymentMethodTrue() + { + $this->methodMock->method('getConfigData') + ->with('is_wallet') + ->willReturn(true); + $this->assertTrue($this->paymentMethodsHelper->isWalletPaymentMethod($this->methodMock)); + + } + + public function testIsWalletPaymentMethodFalse() + { + // Non-wallet payment method + $this->methodMock->method('getConfigData') + ->with('is_wallet') + ->willReturn(false); + $this->assertFalse($this->paymentMethodsHelper->isWalletPaymentMethod($this->methodMock)); + } + + public function testGetBoletoStatus() + { + // Test with valid boleto data + $this->notificationMock->method('getAdditionalData') + ->willReturn(json_encode(['boletobancario' => ['originalAmount' => 'BRL 100', 'paidAmount' => 'BRL 90']])); + $status = $this->paymentMethodsHelper->getBoletoStatus($this->orderMock, $this->notificationMock, 'pending'); + $this->assertEquals('pending', $status); + + // Test with overpaid boleto + $this->notificationMock->method('getAdditionalData') + ->willReturn(json_encode(['boletobancario' => ['originalAmount' => 'BRL 100', 'paidAmount' => 'BRL 110']])); + $status = $this->paymentMethodsHelper->getBoletoStatus($this->orderMock, $this->notificationMock, 'overpaid'); + $this->assertEquals('overpaid', $status); + + // Test with underpaid boleto + $this->notificationMock->method('getAdditionalData') + ->willReturn(json_encode(['boletobancario' => ['originalAmount' => 'BRL 100', 'paidAmount' => 'BRL 80']])); + $status = $this->paymentMethodsHelper->getBoletoStatus($this->orderMock, $this->notificationMock, 'underpaid'); + $this->assertEquals('underpaid', $status); + } + + public function testIsAlternativePaymentMethod() + { + // Test with alternative payment method + $this->methodMock->method('getConfigData') + ->with('group') + ->willReturn(PaymentMethods::ADYEN_GROUP_ALTERNATIVE_PAYMENT_METHODS); + $this->assertTrue($this->paymentMethodsHelper->isAlternativePaymentMethod($this->methodMock)); + + + } + + public function testIsNotAlternativePaymentMethod() + { + // Test with non-alternative payment method + $this->methodMock->method('getConfigData') + ->with('group') + ->willReturn('some_other_group'); + $this->assertFalse($this->paymentMethodsHelper->isAlternativePaymentMethod($this->methodMock)); + } + + public function testGetAlternativePaymentMethodTxVariant() + { + // Test with alternative payment method + $this->methodMock->method('getConfigData') + ->with('group') + ->willReturn(PaymentMethods::ADYEN_GROUP_ALTERNATIVE_PAYMENT_METHODS); + $this->methodMock->method('getCode') + ->willReturn('adyen_some_variant'); + $this->assertEquals('some_variant', $this->paymentMethodsHelper->getAlternativePaymentMethodTxVariant($this->methodMock)); + } + + public function testGetAlternativePaymentMethodTxVariantException() + { + // Test with non-alternative payment method + $this->methodMock->method('getConfigData') + ->with('group') + ->willReturn('some_other_group'); + $this->expectException(AdyenException::class); + $this->paymentMethodsHelper->getAlternativePaymentMethodTxVariant($this->methodMock); + } + + public function testPaymentMethodSupportsRecurring() + { + // Test with supports recurring + $this->methodMock->method('getConfigData') + ->with('supports_recurring') + ->willReturn(true); + $this->assertTrue($this->paymentMethodsHelper->paymentMethodSupportsRecurring($this->methodMock)); + } + + public function testPaymentMethodNotSupportsRecurring() + { + // Test without supports recurring + $this->methodMock->method('getConfigData') + ->with('supports_recurring') + ->willReturn(false); + $this->assertFalse($this->paymentMethodsHelper->paymentMethodSupportsRecurring($this->methodMock)); + } + + public function testCheckPaymentMethod() + { + $this->orderPaymentMock->method('getMethod') + ->willReturn('some_method'); + $this->assertTrue($this->paymentMethodsHelper->checkPaymentMethod($this->orderPaymentMock, 'some_method')); + } + + public function testCheckPaymentMethodFalse() + { + $this->orderPaymentMock->method('getMethod') + ->willReturn('some_other_method'); + $this->assertFalse($this->paymentMethodsHelper->checkPaymentMethod($this->orderPaymentMock, 'some_method')); + } + + public function testGetCcAvailableTypes() + { + // Mock adyenHelper + $adyenCcTypes = [ + 'visa' => ['name' => 'Visa'], + 'mastercard' => ['name' => 'MasterCard'], + 'amex' => ['name' => 'American Express'] + ]; + $this->adyenHelperMock->expects($this->once()) + ->method('getAdyenCcTypes') + ->willReturn($adyenCcTypes); + + $this->configHelperMock->expects($this->once()) + ->method('getAdyenCcConfigData') + ->with('cctypes') + ->willReturn('visa,mastercard'); + + // Test getCcAvailableTypes + $expectedResult = [ + 'visa' => 'Visa', + 'mastercard' => 'MasterCard' + ]; + $this->assertEquals($expectedResult, $this->paymentMethodsHelper->getCcAvailableTypes()); + } + + public function testGetCcAvailableTypesByAlt() + { + $adyenCcTypes = [ + 'visa' => ['name' => 'Visa', 'code_alt' => 'VISA'], + 'mastercard' => ['name' => 'MasterCard', 'code_alt' => 'MC'], + 'amex' => ['name' => 'American Express', 'code_alt' => 'AMEX'] + ]; + $this->adyenHelperMock->expects($this->once()) + ->method('getAdyenCcTypes') + ->willReturn($adyenCcTypes); + + $this->configHelperMock->expects($this->once()) + ->method('getAdyenCcConfigData') + ->with('cctypes') + ->willReturn('visa,mastercard'); + + // Test getCcAvailableTypesByAlt + $expectedResult = [ + 'VISA' => 'visa', + 'MC' => 'mastercard' + ]; + $this->assertEquals($expectedResult, $this->paymentMethodsHelper->getCcAvailableTypesByAlt()); + } + + /** + * @dataProvider autoCaptureDataProvider + */ + public function testIsAutoCapture( + $manualCaptureSupported, + $captureMode, + $sepaFlow, + $paymentCode, + $autoCaptureOpenInvoice, + $manualCapturePayPal, + $expectedResult + ) { + $this->configHelperMock->expects($this->any()) + ->method('getConfigData') + ->with('capture_mode', 'adyen_abstract', '1') + ->willReturn($captureMode); + + $this->configHelperMock->expects($this->any()) + ->method('getConfigData') + ->with('sepa-flow', 'adyen_abstract', '1') + ->willReturn($sepaFlow); + + $this->configHelperMock->expects($this->any()) + ->method('getAutoCaptureOpenInvoice') + ->with( '1') + ->willReturn($autoCaptureOpenInvoice); + + $this->configHelperMock->expects($this->any()) + ->method('getConfigData') + ->with( 'paypal_capture_mode','adyen_abstract','1') + ->willReturn($manualCapturePayPal); + + // Configure the mock to return the method name + $this->orderPaymentMock->method('getMethod') + ->willReturn($paymentCode); + + // Configure the order mock to return the payment mock + $this->orderMock->expects($this->once()) + ->method('getPayment') + ->willReturn($this->orderPaymentMock); + + $this->configHelperMock->expects($this->any()) + ->method('getAutoCaptureOpenInvoice') + ->willReturn($autoCaptureOpenInvoice); + + $paymentMethodsHelper = $this->objectManager->getObject(PaymentMethods::class, [ + 'configHelper' => $this->configHelperMock + ]); + + $result = $paymentMethodsHelper->isAutoCapture($this->orderMock, $paymentCode); + + $this->assertEquals($expectedResult, $result); + } + public function autoCaptureDataProvider(): array + { + return [ + // Manual capture supported, capture mode manual, sepa flow not authcap + [true, 'manual', 'notauthcap', 'paypal', true, null, true], + // Manual capture supported, capture mode auto + [true, 'auto', '', 'sepadirectdebit', true, null, true], + // Manual capture not supported + [false, '', '', 'sepadirectdebit', true, null, true] + ]; + } + + public function testBuildPaymentMethodIconWithSvg() + { + // Mock data + $paymentMethodCode = 'test_method'; + $params = [ + 'area' => 'frontend', + '_secure' => '', + 'theme' => 'Magento/blank' + ]; + $expectedSVGUrl = 'mocked_svg_url'; + $expectedPNGUrl = 'mocked_png_url'; + $svgAssetMock = $this->createMock(File::class); + $svgAssetMock->method('getUrl')->willReturn($expectedSVGUrl); + $pngAssetMock = $this->createMock(File::class); + $pngAssetMock->method('getUrl')->willReturn($expectedPNGUrl); + + $this->assetRepoMock->method('createAsset') + ->withConsecutive( + ["Adyen_Payment::images/logos/{$paymentMethodCode}.svg", $params], + ["Adyen_Payment::images/logos/{$paymentMethodCode}.png", $params] + ) + ->willReturnOnConsecutiveCalls($svgAssetMock, $pngAssetMock); + + // Set up asset source mock for SVG asset + $this->assetSourceMock->method('findSource') + ->with($svgAssetMock) + ->willReturn(true); + + // Set up asset source mock for PNG asset + $this->assetSourceMock->method('findSource') + ->with($pngAssetMock) + ->willReturn(false); + $result = $this->paymentMethodsHelper->buildPaymentMethodIcon($paymentMethodCode, $params); + $this->assertEquals(['url' => $expectedSVGUrl, 'width' => 77, 'height' => 50], $result); + } + + public function testBuildPaymentMethodIconWithPngExistsButSvgDoesNot() + { + $paymentMethodCode = 'test_method'; + $params = [ + 'area' => 'frontend', + '_secure' => '', + 'theme' => 'Magento/blank' + ]; + $expectedUrl = "https://checkoutshopper-live.adyen.com/checkoutshopper/images/logos/{$paymentMethodCode}.svg"; + $svgAssetMock = $this->createMock(File::class); + $pngAssetMock = $this->createMock(File::class); + $this->assetRepoMock->method('createAsset') + ->willReturnMap([ + ["Adyen_Payment::images/logos/{$paymentMethodCode}.svg", $params, $svgAssetMock], + ["Adyen_Payment::images/logos/{$paymentMethodCode}.png", $params, $pngAssetMock] + ]); + $this->assetSourceMock->method('findSource') + ->willReturnMap([ + [$svgAssetMock, false], + [$pngAssetMock, true] + ]); + $pngAssetMock->expects($this->once())->method('getUrl')->willReturn($expectedUrl); + $result = $this->paymentMethodsHelper->buildPaymentMethodIcon($paymentMethodCode, $params); + $this->assertEquals(['url' => $expectedUrl, 'width' => 77, 'height' => 50], $result); + } + + public function testGetPaymentMethodsRequest() + { + $merchantAccount = 'TestMerchant'; + $shopperLocale = 'en_US'; + $country = 'NL'; + $amountValue = 100; + $currencyCode = 'EUR'; + $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); + $this->amountCurrencyMock->method('getAmount')->willReturn($amountValue); + $this->chargedCurrencyMock->method('getQuoteAmountCurrency')->willReturn($this->amountCurrencyMock); + $this->adyenHelperMock->method('getCurrentLocaleCode')->willReturn($shopperLocale); + $this->adyenDataHelperMock->method('padShopperReference')->willReturn('123456'); + $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR'); + $expectedResult = [ + "channel" => "Web", + "merchantAccount" => $merchantAccount, + "countryCode" => $country, + "shopperLocale" => $shopperLocale, + "amount" => ["currency" => $currencyCode] + ]; + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + 'chargedCurrency' => $this->chargedCurrencyMock, + 'adyenHelper' => $this->adyenHelperMock, + ] + ); + + + $getPaymentMethodsRequest = $this->getPrivateMethod( + PaymentMethods::class, + 'getPaymentMethodsRequest' + ); + $result = $getPaymentMethodsRequest->invoke($paymentMethods, $merchantAccount, $this->storeMock, $this->quoteMock, $shopperLocale, $country); + + + $this->assertEquals($expectedResult, $result); + } + + public function testConnectionExceptionHandling(): void + { + $requestParams = [ + 'area' => 'frontend', + '_secure' => '', + 'theme' => 'Magento/blank' + ]; + //$storeMock = $this->createMock(Store::class); + $storeId = 123; // Provide your store ID + $this->storeMock->method('getId')->willReturn($storeId); + + $clientMock = $this->createMock(Client::class); + $checkoutServiceMock = $this->createMock(Checkout::class); + + $this->adyenHelperMock->expects($this->once()) + ->method('initializeAdyenClient') + ->with($storeId) + ->willReturn($clientMock); + + $this->adyenHelperMock + ->method('createAdyenCheckoutService') + ->with($clientMock) + ->willReturn($checkoutServiceMock); + + + $this->adyenHelperMock->expects($this->once()) + ->method('logRequest') + ->with($requestParams, Client::API_CHECKOUT_VERSION, '/paymentMethods'); + + $this->adyenHelperMock->expects($this->never())->method('logResponse'); + + $connectionException = new ConnectionException("Connection failed"); + $checkoutServiceMock->expects($this->once()) + ->method('paymentMethods') + ->willThrowException($connectionException); + + $this->adyenLoggerMock->expects($this->once()) + ->method('error') + ->with("Connection to the endpoint failed. Check the Adyen Live endpoint prefix configuration."); + + $getPaymentMethodsResponse = $this->getPrivateMethod( + PaymentMethods::class, + 'getPaymentMethodsResponse' + ); + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + 'chargedCurrency' => $this->chargedCurrencyMock, + 'adyenHelper' => $this->adyenHelperMock, + 'adyenLogger' => $this->adyenLoggerMock + ] + ); + $result = $getPaymentMethodsResponse->invoke($paymentMethods, $requestParams, $this->storeMock); + + $this->assertEquals([], $result); + } + + public function testManualCaptureAllowed(): void + { + $storeId = 123; // Provide your store ID + $this->orderMock->method('getStoreId')->willReturn($storeId); + $this->orderPaymentMock->method('getMethod')->willReturn('sepadirectdebit'); + $this->orderMock->method('getPayment')->willReturn($this->orderPaymentMock); + $manualCaptureMock = $this->getMockBuilder(ManualCapture::class) + ->disableOriginalConstructor() + ->getMock(); + $manualCaptureMock->expects($this->any())->method('isManualCaptureSupported')->willReturn(true); + + $notificationPaymentMethod = 'sepadirectdebit'; // Provide your notification payment method + + $captureMode = 'auto'; // Assuming auto capture mode is set + $sepaFlow = 'authcap'; // Assuming authcap flow for SEPA + $manualCapturePayPal = 'manual'; // Assuming manual capture for PayPal + + $this->configHelperMock->expects($this->exactly(3)) + ->method('getConfigData')// Expecting 5 calls to getConfigData method + ->withConsecutive( + ['capture_mode', 'adyen_abstract', $storeId], + ['sepa_flow', 'adyen_abstract', $storeId], + ['paypal_capture_mode', 'adyen_abstract', $storeId], + ['capture_mode_pos', 'adyen_abstract', $storeId] + ) + ->willReturnOnConsecutiveCalls($captureMode, $sepaFlow, '', 'auto', $manualCapturePayPal); + + // Mock your other dependencies as needed for your test scenario + + $paymentMethods = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'quote' => $this->quoteMock, + 'configHelper' => $this->configHelperMock, + 'chargedCurrency' => $this->chargedCurrencyMock, + 'adyenHelper' => $this->adyenHelperMock, + 'adyenLogger' => $this->adyenLoggerMock, + 'manualCapture' => $manualCaptureMock + ] + ); + + // Now, you can assert the return value of the method + $result = $paymentMethods->isAutoCapture($this->orderMock, $notificationPaymentMethod); + $this->assertFalse($result); // Assuming manual capture is allowed, so it should return false + } + + public function testShowLogosPaymentMethods() + { + $themeId = 123; // Assuming a theme ID + $this->adyenHelperMock->expects($this->any()) + ->method('showLogos') + ->willReturn(true); // Mock the method to return true for this test + $paymentMethods = [ + ['type' => 'visa', 'brand' => 'visa'] + ]; + $paymentMethodsExtraDetails = [ + 'visa' => [] + ]; + $paymentMethodCode = 'visa'; + $params = [ + 'area' => 'frontend', + '_secure' => '', + 'theme' => 'Magento/blank' + ]; + + // Set up the mock for design->getConfigurationDesignTheme + $this->designMock->expects($this->any()) + ->method('getConfigurationDesignTheme') + ->willReturn($themeId); + + // Set up the mock for themeProvider->getThemeById + $themeMock = $this->createMock(ThemeInterface::class); + + // Set up the getCode method of the theme object + $themeMock->expects($this->any()) + ->method('getCode') + ->willReturn('Magento/blank'); + + $this->themeProviderMock->expects($this->any()) + ->method('getThemeById') + ->with($themeId) + ->willReturn($themeMock); + + $expectedSVGUrl = 'mocked_svg_url'; + $expectedPNGUrl = 'mocked_png_url'; + $svgAssetMock = $this->createMock(File::class); + $svgAssetMock->method('getUrl')->willReturn($expectedSVGUrl); + $pngAssetMock = $this->createMock(File::class); + $pngAssetMock->method('getUrl')->willReturn($expectedPNGUrl); + + $this->assetRepoMock->method('createAsset') + ->withConsecutive( + ["Adyen_Payment::images/logos/{$paymentMethodCode}.svg", $params], + ["Adyen_Payment::images/logos/{$paymentMethodCode}.png", $params] + ) + ->willReturnOnConsecutiveCalls($svgAssetMock, $pngAssetMock); + + // Set up asset source mock for SVG asset + $this->assetSourceMock->method('findSource') + ->with($svgAssetMock) + ->willReturn(true); + + // Set up asset source mock for PNG asset + $this->assetSourceMock->method('findSource') + ->with($pngAssetMock) + ->willReturn(false); + + $paymentMethodsHelper = $this->objectManager->getObject( + PaymentMethods::class, + [ + 'adyenHelper' => $this->adyenHelperMock, + 'design' => $this->designMock, + 'themeProvider' => $this->themeProviderMock, + 'assetRepo' => $this->assetRepoMock, + 'assetSource' => $this->assetSourceMock + ] + ); + + $method = $this->getPrivateMethod( + PaymentMethods::class, + 'showLogosPaymentMethods' + ); + + // Call the protected method + $result = $method->invokeArgs($paymentMethodsHelper, [$paymentMethods, $paymentMethodsExtraDetails]); + + // Assert that the returned array has the expected structure + $this->assertIsArray($result); + $this->assertArrayHasKey('visa', $result); + $this->assertArrayHasKey('icon', $result['visa']); + $this->assertArrayHasKey('isOpenInvoice', $result['visa']); + } + } diff --git a/Test/Unit/Helper/WebhookTest.php b/Test/Unit/Helper/WebhookTest.php index 3d818df85..b94d27f3a 100644 --- a/Test/Unit/Helper/WebhookTest.php +++ b/Test/Unit/Helper/WebhookTest.php @@ -2,7 +2,6 @@ namespace Adyen\Payment\Test\Unit\Helper; use Adyen\Payment\Helper\Webhook; -use Adyen\Payment\Helper\Webhook\AuthorisationWebhookHandler; use Adyen\Payment\Helper\Webhook\WebhookHandlerInterface; use Adyen\Payment\Model\Notification; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; @@ -19,7 +18,6 @@ use Adyen\Payment\Helper\Webhook\WebhookHandlerFactory; use Adyen\Payment\Logger\AdyenLogger; use ReflectionMethod; -use ReflectionClass; class WebhookTest extends AbstractAdyenTestCase { @@ -190,6 +188,7 @@ public function testUpdateAdyenAttributes() $orderMock = $this->getMockBuilder(Order::class) ->disableOriginalConstructor() ->getMock(); + $orderMock->method('getData')->willReturnSelf(); $paymentMock = $this->getMockBuilder(Payment::class) ->disableOriginalConstructor() @@ -203,8 +202,21 @@ public function testUpdateAdyenAttributes() ->disableOriginalConstructor() ->getMock(); + $orderRepositoryMock = $this->createMock(OrderRepository::class); + $orderRepositoryMock->method('get')->willReturn($orderMock); + // Create an instance of your class - $webhook = $this->createWebhook(null, $serializerMock, null, null, null, $loggerMock, null, null, null); + $webhook = $this->createWebhook( + null, + $serializerMock, + null, + null, + null, + $loggerMock, + null, + null, + $orderRepositoryMock + ); // Set up expectations for the mocked objects $notificationMock->expects($this->once()) diff --git a/Test/Unit/Model/Config/Backend/PaymentMethodsStatusTest.php b/Test/Unit/Model/Config/Backend/PaymentMethodsStatusTest.php new file mode 100644 index 000000000..9035f6679 --- /dev/null +++ b/Test/Unit/Model/Config/Backend/PaymentMethodsStatusTest.php @@ -0,0 +1,41 @@ + + */ + +namespace Adyen\Payment\Test\Unit\Model\Config\Backend; + +use Adyen\Payment\Helper\PaymentMethods; +use Adyen\Payment\Model\Config\Backend\PaymentMethodsStatus; +use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class PaymentMethodsStatusTest extends AbstractAdyenTestCase +{ + const ENABLED_METHODS = [ + 'adyen_cc', + 'adyen_ideal' + ]; + + public function testAfterSave() + { + $paymentMethodsHelperMock = $this->createMock(PaymentMethods::class); + $paymentMethodsHelperMock->method('togglePaymentMethodsActivation') + ->willReturn(self::ENABLED_METHODS); + + $objectManager = new ObjectManager($this); + $paymentMethodsStatus = $objectManager->getObject(PaymentMethodsStatus::class, [ + 'paymentMethodsHelper' => $paymentMethodsHelperMock + ]); + + $result = $paymentMethodsStatus->afterSave(); + + $this->assertInstanceOf(PaymentMethodsStatus::class, $result); + } +} diff --git a/Test/Unit/Setup/RecurringTest.php b/Test/Unit/Setup/RecurringDataTest.php similarity index 76% rename from Test/Unit/Setup/RecurringTest.php rename to Test/Unit/Setup/RecurringDataTest.php index 02929115c..142f21b58 100644 --- a/Test/Unit/Setup/RecurringTest.php +++ b/Test/Unit/Setup/RecurringDataTest.php @@ -11,22 +11,22 @@ namespace Adyen\Payment\Test\Unit\Setup; -use Adyen\Payment\Setup\Recurring; +use Adyen\Payment\Setup\RecurringData; use Adyen\Payment\Test\Unit\AbstractAdyenTestCase; use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\SchemaSetupInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; use Adyen\Payment\Helper\PaymentMethodsFactory; use Adyen\Payment\Helper\PaymentMethods; class RecurringTest extends AbstractAdyenTestCase { - private Recurring $recurring; + private RecurringData $recurringData; protected function setUp(): void { parent::setUp(); $this->paymentMethodsFactoryMock = $this->createGeneratedMock(PaymentMethodsFactory::class, ['create']); - $this->recurring = new Recurring($this->paymentMethodsFactoryMock); + $this->recurringData = new RecurringData($this->paymentMethodsFactoryMock); } public function testInstall() @@ -39,9 +39,9 @@ public function testInstall() $paymentMethods ->expects($this->once()) ->method('togglePaymentMethodsActivation'); - $setup = $this->createMock(SchemaSetupInterface::class); + $setup = $this->createMock(ModuleDataSetupInterface::class); $context = $this->createMock(ModuleContextInterface::class); - $this->recurring->install($setup, $context); + $this->recurringData->install($setup, $context); } -} \ No newline at end of file +} diff --git a/composer.json b/composer.json index f787681ac..489bd0082 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "adyen/module-payment", "description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.", "type": "magento2-module", - "version": "9.2.0", + "version": "9.3.0", "license": "MIT", "repositories": [ { diff --git a/etc/config.xml b/etc/config.xml index 24b0ddf34..feca7ce4d 100755 --- a/etc/config.xml +++ b/etc/config.xml @@ -2025,8 +2025,8 @@ 1 1 adyen-alternative-payment-method - - + + 0 AdyenPaymentVippsFacade Vipps @@ -2048,6 +2048,28 @@ 1 adyen-alternative-payment-method + + 0 + AdyenPaymentBizumFacade + Bizum + 0 + 0 + authorize + 1 + 1 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + adyen-alternative-payment-method + - + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index cd6a24ad2..1ca51fe7f 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -826,7 +826,6 @@ AdyenPaymentCommandManager AdyenPaymentCommandManager AdyenPaymentCommandManager - @@ -3931,8 +3930,8 @@ AdyenPaymentMobilepayValueHandlerPool AdyenPaymentValidatorPool AdyenPaymentCommandPool - - + + adyen_vipps @@ -3977,5 +3976,31 @@ adyen_vipps - - + + + adyen_bizum + Magento\Payment\Block\Form + Adyen\Payment\Block\Info\PaymentMethodInfo + AdyenPaymentBizumValueHandlerPool + AdyenPaymentValidatorPool + AdyenPaymentCommandPool + + + + + + AdyenPaymentBizumConfigValueHandler + + + + + + AdyenPaymentBizumConfig + + + + + adyen_bizum + + + \ No newline at end of file diff --git a/etc/events.xml b/etc/events.xml index 2580f623d..2c9334265 100644 --- a/etc/events.xml +++ b/etc/events.xml @@ -281,4 +281,7 @@ - + + + + \ No newline at end of file diff --git a/etc/frontend/di.xml b/etc/frontend/di.xml index e45441148..8fd1ab7cc 100755 --- a/etc/frontend/di.xml +++ b/etc/frontend/di.xml @@ -104,6 +104,7 @@ klarna_b2b mobilepay vipps + bizum Adyen_Payment/js/view/payment/method-renderer/adyen-cc-method @@ -150,4 +151,4 @@ - + \ No newline at end of file diff --git a/etc/graphql/di.xml b/etc/graphql/di.xml index 13bd54d79..72618ab23 100644 --- a/etc/graphql/di.xml +++ b/etc/graphql/di.xml @@ -84,6 +84,7 @@ Adyen\Payment\Model\Cart\Payment\AdditionalDataProvider\AdyenPm Adyen\Payment\Model\Cart\Payment\AdditionalDataProvider\AdyenPm Adyen\Payment\Model\Cart\Payment\AdditionalDataProvider\AdyenPm + Adyen\Payment\Model\Cart\Payment\AdditionalDataProvider\AdyenPm diff --git a/etc/module.xml b/etc/module.xml index 867f5452b..830961a77 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -12,11 +12,12 @@ --> - + + diff --git a/etc/payment.xml b/etc/payment.xml index 3dd06ebd5..b362a32a3 100755 --- a/etc/payment.xml +++ b/etc/payment.xml @@ -237,10 +237,13 @@ 1 - 1 + 1 1 + + 1 + \ No newline at end of file diff --git a/view/base/web/images/logos/bizum.svg b/view/base/web/images/logos/bizum.svg new file mode 100644 index 000000000..0b474c3da --- /dev/null +++ b/view/base/web/images/logos/bizum.svg @@ -0,0 +1,15 @@ + + + + Fill 7 + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index e634d30d2..5e7b6a06e 100755 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -293,6 +293,9 @@ true + + true + @@ -310,4 +313,4 @@ - + \ No newline at end of file diff --git a/view/frontend/layout/multishipping_checkout_billing.xml b/view/frontend/layout/multishipping_checkout_billing.xml index 629e7db0e..0ae147f9f 100644 --- a/view/frontend/layout/multishipping_checkout_billing.xml +++ b/view/frontend/layout/multishipping_checkout_billing.xml @@ -94,6 +94,7 @@ Adyen_Payment::form/multishipping/abstract-form.phtml Adyen_Payment::form/multishipping/abstract-form.phtml Adyen_Payment::form/multishipping/abstract-form.phtml + Adyen_Payment::form/multishipping/abstract-form.phtml false diff --git a/view/frontend/web/template/payment/pm-form.html b/view/frontend/web/template/payment/pm-form.html index fbe8d6dd4..bd6be127a 100755 --- a/view/frontend/web/template/payment/pm-form.html +++ b/view/frontend/web/template/payment/pm-form.html @@ -19,77 +19,75 @@
-
- - -
+ +
- - +
+ + +
-
+
-
- + + + + + +
+
+ - +
+
+
- + +
+ +
+ - -
- - - -
- - -
-
-
- - -
- - - -
- - -
-
- -
+
+
+
- -
+
+