diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a24a177..13227fd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -20,18 +20,11 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: [ "8.0", "8.1", "8.2", "8.3" ]
- symfony: [ "^5.4", "^6.4" ]
- sylius: [ "^1.12", "^1.13" ]
- node: [ "18.x", "20.x" ]
- mysql: [ "8.0" ]
-
- exclude:
- - sylius: ^1.13
- php: 8.0
- - sylius: ^1.12
- php: 8.0
- symfony: ^6.4
+ php: [ "8.2", "8.3" ]
+ symfony: [ "^6.4", "^7.1" ]
+ sylius: [ "^2.0.4" ]
+ node: [ "20.x", "22.x" ]
+ mysql: [ "5.7", "8.0" ]
env:
APP_ENV: test
@@ -75,14 +68,6 @@ jobs:
name: Install certificates
run: symfony server:ca:install
- -
- name: Run Chrome Headless
- run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1 > /dev/null 2>&1 &
-
- -
- name: Run webserver
- run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon)
-
-
name: Get Composer cache directory
id: composer-cache
@@ -157,17 +142,9 @@ jobs:
name: Validate database schema
run: (cd tests/Application && bin/console doctrine:schema:validate)
- -
- name: Run PHPSpec
- run: vendor/bin/phpspec run --ansi -f progress --no-interaction
-
-
name: Run PHPUnit
run: vendor/bin/phpunit --colors=always
-
- -
- name: Load fixtures in test application
- run: (cd tests/Application && bin/console sylius:fixtures:load -n)
-
name: Failed build Slack notification
diff --git a/.github/workflows/coding_standard.yml b/.github/workflows/coding_standard.yml
index 97e34a4..6866c60 100644
--- a/.github/workflows/coding_standard.yml
+++ b/.github/workflows/coding_standard.yml
@@ -18,17 +18,10 @@ jobs:
strategy:
fail-fast: false
matrix:
- php: [ "8.0", "8.1", "8.2", "8.3" ]
- symfony: [ "^5.4", "^6.4" ]
- sylius: [ "^1.12", "^1.13" ]
- node: [ "18.x", "20.x" ]
-
- exclude:
- - sylius: ^1.13
- php: 8.0
- - sylius: ^1.12
- php: 8.0
- symfony: ^6.4
+ php: [ "8.2", "8.3" ]
+ symfony: [ "^6.4", "^7.1" ]
+ sylius: [ "^2.0.4" ]
+ node: [ "20.x", "22.x" ]
steps:
- uses: actions/checkout@v3
@@ -70,10 +63,10 @@ jobs:
SYMFONY_REQUIRE: ${{ matrix.symfony }}
- name: Run PHPStan
- run: vendor/bin/phpstan analyse -c phpstan.neon -l 8 src/
+ run: vendor/bin/phpstan analyse -c phpstan.neon -l 7 src/
- name: Run ECS
- run: vendor/bin/ecs check src
+ run: vendor/bin/ecs check src --debug
- name: Failed build Slack notification
uses: rtCamp/action-slack-notify@v2
diff --git a/CONFLICTS.md b/CONFLICTS.md
deleted file mode 100644
index dab299f..0000000
--- a/CONFLICTS.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# CONFLICTS
-
-This document explains why certain conflicts were added to `composer.json` and
-references related issues.
-
-- `symfony/framework-bundle:6.2.8`:
-
- This version is missing the service alias `validator.expression`
- which causes ValidatorException exception to be thrown when using `Expression` constraint.
diff --git a/README.md b/README.md
index a34ecee..37c7cee 100644
--- a/README.md
+++ b/README.md
@@ -4,11 +4,11 @@
We want to impact many unique eCommerce projects and build our brand recognition worldwide, so we are heavily involved in creating open-source solutions, especially for Sylius. We have already created over **35 extensions, which have been downloaded almost 2 million times.**
-You can find more information about our eCommerce services and technologies on our website: https://bitbag.io/. We have also created a unique service dedicated to creating plugins: https://bitbag.io/services/sylius-plugin-development.
+You can find more information about our eCommerce services and technologies on our website: https://bitbag.io/. We have also created a unique service dedicated to creating plugins: https://bitbag.io/services/sylius-plugin-development.
-Do you like our work? Would you like to join us? Check out the **“Career” tab:** https://bitbag.io/pl/kariera.
+Do you like our work? Would you like to join us? Check out the **“Career” tab:** https://bitbag.io/pl/kariera.
-# About Us
+# About Us
---
BitBag is a software house that implements tailor-made eCommerce platforms with the entire infrastructure—from creating eCommerce platforms to implementing PIM and CMS systems to developing custom eCommerce applications, specialist B2B solutions, and migrations from other platforms.
@@ -27,14 +27,14 @@ We have a 70-person team of experts: business analysts and consultants, eCommerc
* PIM and CMS implementations
**Some numbers from BitBag regarding Sylius:**
-* 70 experts on board
+* 70 experts on board
* +150 projects delivered on top of Sylius
* 30 countries of BitBag’s customers
* 7 years in the Sylius ecosystem
* +35 plugins created for Sylius
---
-[](https://bitbag.io/contact-us/?utm_source=github&utm_medium=referral&utm_campaign=plugins_elasticsearch)
+[](https://bitbag.io/contact-us/?utm_source=github&utm_medium=referral&utm_campaign=plugins_elasticsearch)
---
@@ -56,46 +56,28 @@ We have a 70-person team of experts: business analysts and consultants, eCommerc
* [Community](#community)
# Installation
-----
+
The installation process for the Imoje Paywall Plugin can be found [here](doc/installation.md).
-## Requirements
----
+
+## Requirements:
We work on stable, supported and up-to-date versions of packages. We recommend you to do the same.
-| Package | Version |
-|---------------|---------------------|
-| PHP | \>=8.1 |
-| sylius/sylius | \>=1.12.13 - 1.13.x |
-| MySQL | \>= 5.7 |
-| NodeJS | \>= 14.x |
+| Package | Version |
+|---------------|----------|
+| PHP | \>=8.1 |
+| sylius/sylius | \>=2.0.4 |
+| MySQL | \>= 5.7 |
+| NodeJS | \>= 20.x |
+| Symfony | \>= 6.4 |
-## Usage
+# Usage
This plugin allows you to use the payment solution delivered by Imoje.
+# Configuration
-## Configuration
-
-To create an ING-based payment method, go to Payment methods in the Sylius admin panel.
-After that, you need to add an ING payment:
-
-
-
-And now, you can configure your payment method in the admin panel:
-
-
-
-
-To configure the imoje gateway, log in to ING the admin panel.
-
-From "Settings" -> "Data for integration" you can acquire all the needed keys:
-
-merchantId, serviceId, shopKey
-
-Also, here in the integration data page you need to configure the path to your webhook, just type in your shop URL followed by /payment/imoje/notify
-
-You also need an authorization token, so you need to go to: "Settings" -> "API Keys". And click on your "API key". This will be your authorization token.
+The configuration process for the Imoje Paywall Plugin can be found [here](doc/configuration.md).
# Functionalities
@@ -106,7 +88,7 @@ All main functionalities of the plugin are described **[here.](doc/functionaliti
**If you need some help with Sylius development, don't be hesitated to contact us directly. You can fill the form on [this site](https://bitbag.io/contact-us/?utm_source=github&utm_medium=referral&utm_campaign=plugins_mollie) or send us an e-mail to hello@bitbag.io!**
---
-# Demo
+# Demo
---
We created a demo app with some useful use-cases of plugins! Visit http://demo.sylius.com/ to take a look at it.
@@ -129,7 +111,7 @@ This plugin's source code is completely free and released under the terms of the
[//]: # (These are reference links used in the body of this note and get stripped out when the markdown processor does its job. There is no need to format nicely because it shouldn't be seen.)
-# Contact and support
+# Contact and support
---
This open-source plugin was developed to help the Sylius community. If you have any additional questions, would like help with installing or configuring the plugin, or need any assistance with your Sylius project - let us know! **Contact us** or send us an **e-mail to hello@bitbag.io** with your question(s).
diff --git a/tests/Application/assets/admin/entry.js b/assets/admin/entrypoint.js
similarity index 100%
rename from tests/Application/assets/admin/entry.js
rename to assets/admin/entrypoint.js
diff --git a/tests/Application/assets/shop/entry.js b/assets/shop/entrypoint.js
similarity index 100%
rename from tests/Application/assets/shop/entry.js
rename to assets/shop/entrypoint.js
diff --git a/composer.json b/composer.json
index 18a58a7..9d57651 100644
--- a/composer.json
+++ b/composer.json
@@ -8,27 +8,23 @@
],
"license": "MIT",
"require": {
- "php": "^8.0",
- "doctrine/annotations": "^1.14",
- "sylius/sylius": "~1.12.0 || ~1.13.0",
- "sylius/mailer-bundle": "^1.8 || ^2.0@beta",
- "symfony/webpack-encore-bundle": "^1.15"
+ "sylius/sylius": "^2.0.4",
+ "symfony/webpack-encore-bundle": "^2.1"
},
"require-dev": {
- "behat/behat": "^3.6.1",
- "behat/mink-selenium2-driver": "^1.4",
+ "behat/behat": "^3.14",
+ "behat/mink-selenium2-driver": "^1.6",
"bitbag/coding-standard": "^3.0",
- "dmore/behat-chrome-extension": "^1.3",
- "dmore/chrome-mink-driver": "^2.7",
- "friends-of-behat/mink": "^1.8",
- "friends-of-behat/mink-browserkit-driver": "^1.4",
- "friends-of-behat/mink-debug-extension": "^2.0.0",
- "friends-of-behat/mink-extension": "^2.4",
+ "dmore/behat-chrome-extension": "^1.4",
+ "dmore/chrome-mink-driver": "^2.9",
+ "friends-of-behat/mink": "^1.11",
+ "friends-of-behat/mink-browserkit-driver": "^1.6",
+ "friends-of-behat/mink-debug-extension": "^2.1",
+ "friends-of-behat/mink-extension": "^2.7",
"friends-of-behat/page-object-extension": "^0.3",
"friends-of-behat/suite-settings-extension": "^1.0",
- "friends-of-behat/symfony-extension": "^2.1",
- "friends-of-behat/variadic-extension": "^1.3",
- "phpspec/phpspec": "^7.5",
+ "friends-of-behat/symfony-extension": "^2.6",
+ "friends-of-behat/variadic-extension": "^1.6",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.10",
"phpstan/phpstan-doctrine": "1.3.40",
@@ -36,46 +32,43 @@
"phpstan/phpstan-webmozart-assert": "^1.2.0",
"phpunit/phpunit": "^9.5",
"polishsymfonycommunity/symfony-mocker-container": "^1.0",
- "sylius-labs/coding-standard": "^4.2",
- "symfony/browser-kit": "^5.4 || ^6.0",
- "symfony/debug-bundle": "^5.4 || ^6.0",
- "symfony/dotenv": "^5.4 || ^6.0",
- "symfony/flex": "^2.2.2",
- "symfony/intl": "^5.4 || ^6.0",
- "symfony/web-profiler-bundle": "^5.4 || ^6.0",
- "vimeo/psalm": "4.27.0"
- },
- "conflict": {
- "behat/mink-selenium2-driver": ">=1.7.0",
- "symfony/framework-bundle": "6.2.8",
- "symfony/validator": "6.4.7"
+ "sylius/mailer-bundle": "^1.8 || ^2.0@beta",
+ "sylius-labs/coding-standard": "^4.4",
+ "symfony/browser-kit": "^6.4 || ^7.1",
+ "symfony/debug-bundle": "^6.4 || ^7.1",
+ "symfony/dotenv": "^6.4 || ^7.1",
+ "symfony/flex": "^2.4",
+ "symfony/intl": "^6.4 || ^7.1",
+ "symfony/web-profiler-bundle": "^6.4 || ^7.1",
+ "nyholm/psr7": "^1.8"
},
"config": {
"sort-packages": true,
"allow-plugins": {
- "dealerdirect/phpcodesniffer-composer-installer": false,
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "php-http/discovery": true,
"phpstan/extension-installer": true,
"symfony/flex": true
}
},
"extra": {
- "branch-alias": {
- "dev-master": "1.12-dev"
- },
"symfony": {
- "require": "^5.4 || ^6.0"
+ "require": "^6.4 || ^7.1"
}
},
"autoload": {
"psr-4": {
- "BitBag\\SyliusImojePlugin\\": "src/",
- "Tests\\BitBag\\SyliusImojePlugin\\": "tests/"
+ "BitBag\\SyliusImojePlugin\\": "src/"
}
},
"autoload-dev": {
- "classmap": [
- "tests/Application/Kernel.php"
- ]
+ "psr-4": {
+ "Tests\\BitBag\\SyliusImojePlugin\\": [
+ "tests/",
+ "tests/Application/src"
+ ]
+ },
+ "classmap": ["tests/Application/Kernel.php"]
},
"scripts": {
"post-install-cmd": [
diff --git a/config/config.yaml b/config/config.yaml
new file mode 100644
index 0000000..593215b
--- /dev/null
+++ b/config/config.yaml
@@ -0,0 +1,3 @@
+imports:
+ - { resource: services.yaml }
+ - { resource: twig_hooks.yaml }
diff --git a/config/routing.yml b/config/routes.yaml
similarity index 100%
rename from config/routing.yml
rename to config/routes.yaml
diff --git a/config/services.xml b/config/services.xml
deleted file mode 100644
index f1ac82b..0000000
--- a/config/services.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/config/services.yaml b/config/services.yaml
new file mode 100644
index 0000000..98761ca
--- /dev/null
+++ b/config/services.yaml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: services/*.yaml }
diff --git a/config/services/action.xml b/config/services/action.xml
deleted file mode 100644
index 1f1b2fc..0000000
--- a/config/services/action.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/services/command_handlers.yaml b/config/services/command_handlers.yaml
new file mode 100644
index 0000000..98c5d92
--- /dev/null
+++ b/config/services/command_handlers.yaml
@@ -0,0 +1,32 @@
+services:
+ bitbag.sylius.command_handlers.imoje_paywall.capture:
+ class: BitBag\SyliusImojePlugin\CommandHandler\CapturePaymentRequestHandler
+ arguments:
+ - '@sylius.provider.payment_request'
+ - '@sylius_abstraction.state_machine'
+ - '@bitbag.imoje_plugin.resolver.signature_resolver'
+ - '@sylius_shop.provider.order_pay.payment_request_pay_url'
+ tags:
+ - name: messenger.message_handler
+ bus: sylius.payment_request.command_bus
+
+ bitbag.sylius.command_handlers.imoje_paywall.capture_end:
+ class: BitBag\SyliusImojePlugin\CommandHandler\CaptureEndPaymentRequestHandler
+ arguments:
+ - '@sylius.provider.payment_request'
+ - '@sylius_abstraction.state_machine'
+ - '@bitbag.sylius_imoje_plugin.processor.payment_transition'
+ tags:
+ - name: messenger.message_handler
+ bus: sylius.payment_request.command_bus
+
+ bitbag.sylius.command_handlers.imoje_paywall.status:
+ class: BitBag\SyliusImojePlugin\CommandHandler\StatusPaymentRequestHandler
+ arguments:
+ - '@sylius.provider.payment_request'
+ - '@sylius_abstraction.state_machine'
+ - '@bitbag.sylius_imoje_plugin.processor.payment_transition'
+ tags:
+ - name: messenger.message_handler
+ bus: sylius.payment_request.command_bus
+ handles: BitBag\SyliusImojePlugin\Command\StatusPaymentRequest
diff --git a/config/services/command_providers.yaml b/config/services/command_providers.yaml
new file mode 100644
index 0000000..abc198f
--- /dev/null
+++ b/config/services/command_providers.yaml
@@ -0,0 +1,22 @@
+services:
+ bitbag.sylius.command_provider.imoje_paywall:
+ class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider
+ arguments:
+ - !tagged_locator
+ tag: bitbag.sylius.command_provider.imoje_paywall
+ index_by: 'action'
+ tags:
+ - name: sylius.payment_request.command_provider
+ gateway_factory: 'imoje_paywall'
+
+ bitbag.sylius.command_provider.imoje_paywall.capture:
+ class: BitBag\SyliusImojePlugin\CommandProvider\CapturePaymentRequestCommandProvider
+ tags:
+ - name: bitbag.sylius.command_provider.imoje_paywall
+ action: !php/const Sylius\Component\Payment\Model\PaymentRequestInterface::ACTION_CAPTURE
+
+ bitbag.sylius.command_provider.imoje_paywall.status:
+ class: BitBag\SyliusImojePlugin\CommandProvider\StatusPaymentRequestCommandProvider
+ tags:
+ - name: bitbag.sylius.command_provider.imoje_paywall
+ action: !php/const Sylius\Component\Payment\Model\PaymentRequestInterface::ACTION_STATUS
diff --git a/config/services/controller.xml b/config/services/controller.xml
deleted file mode 100644
index 87250a8..0000000
--- a/config/services/controller.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/services/controller.yaml b/config/services/controller.yaml
new file mode 100644
index 0000000..784d538
--- /dev/null
+++ b/config/services/controller.yaml
@@ -0,0 +1,11 @@
+services:
+ _defaults:
+ public: true
+
+ bitbag.sylius_imoje_plugin.controller.notify_controller:
+ class: BitBag\SyliusImojePlugin\Controller\NotifyController
+ arguments:
+ - '@sylius.repository.order'
+ - '@sylius.repository.payment'
+ - '@doctrine.orm.entity_manager'
+ - '@bitbag.imoje_plugin.resolver.signature_resolver'
diff --git a/config/services/form.xml b/config/services/form.xml
deleted file mode 100644
index 8fe17bc..0000000
--- a/config/services/form.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/config/services/form.yaml b/config/services/form.yaml
new file mode 100644
index 0000000..1d77e25
--- /dev/null
+++ b/config/services/form.yaml
@@ -0,0 +1,8 @@
+services:
+ bitbag.imoje_plugin.form.type.gateway_configuration.imoje_paywall:
+ class: BitBag\SyliusImojePlugin\Form\Type\ImojeGatewayConfigurationType
+ tags:
+ - name: sylius.gateway_configuration_type
+ type: imoje_paywall
+ label: 'bitbag.imoje_plugin.paywall'
+ - name: form.type
diff --git a/config/services/gateway_factory.xml b/config/services/gateway_factory.xml
deleted file mode 100644
index 6d57172..0000000
--- a/config/services/gateway_factory.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
- BitBag\SyliusImojePlugin\ImojeGatewayFactory
-
-
-
-
diff --git a/config/services/http_response_provider.yaml b/config/services/http_response_provider.yaml
new file mode 100644
index 0000000..60de9cf
--- /dev/null
+++ b/config/services/http_response_provider.yaml
@@ -0,0 +1,16 @@
+services:
+ bitbag.sylius.provider.order_pay.http_response.imoje_paywall:
+ class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider
+ arguments:
+ - !tagged_locator
+ tag: bitbag.sylius.provider.order_pay.http_response.imoje_paywall
+ index_by: action
+ tags:
+ - name: sylius.payment_request.provider.http_response
+ gateway_factory: 'imoje_paywall'
+
+ bitbag.sylius.provider.order_pay.http_response.imoje_paywall.capture:
+ class: BitBag\SyliusImojePlugin\OrderPay\Provider\CaptureHttpResponseProvider
+ tags:
+ - name: bitbag.sylius.provider.order_pay.http_response.imoje_paywall
+ action: !php/const Sylius\Component\Payment\Model\PaymentRequestInterface::ACTION_CAPTURE
diff --git a/config/services/processor.yaml b/config/services/processor.yaml
new file mode 100644
index 0000000..05e2412
--- /dev/null
+++ b/config/services/processor.yaml
@@ -0,0 +1,5 @@
+services:
+ bitbag.sylius_imoje_plugin.processor.payment_transition:
+ class: BitBag\SyliusImojePlugin\Processor\PaymentTransitionProcessor
+ arguments:
+ - '@sylius_abstraction.state_machine'
diff --git a/config/services/provider.xml b/config/services/provider.xml
deleted file mode 100644
index a8f7304..0000000
--- a/config/services/provider.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/config/services/resolver.xml b/config/services/resolver.xml
deleted file mode 100644
index 8880f9d..0000000
--- a/config/services/resolver.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
diff --git a/config/services/resolver.yaml b/config/services/resolver.yaml
new file mode 100644
index 0000000..3a9f043
--- /dev/null
+++ b/config/services/resolver.yaml
@@ -0,0 +1,3 @@
+services:
+ bitbag.imoje_plugin.resolver.signature_resolver:
+ class: BitBag\SyliusImojePlugin\Resolver\SignatureResolver
diff --git a/config/twig_hooks.yaml b/config/twig_hooks.yaml
new file mode 100644
index 0000000..88c395f
--- /dev/null
+++ b/config/twig_hooks.yaml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: twig_hooks/payment_method/**/*.yaml }
diff --git a/config/twig_hooks/payment_method/admin/create.yaml b/config/twig_hooks/payment_method/admin/create.yaml
new file mode 100644
index 0000000..755ed64
--- /dev/null
+++ b/config/twig_hooks/payment_method/admin/create.yaml
@@ -0,0 +1,18 @@
+sylius_twig_hooks:
+ hooks:
+ 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.imoje_paywall':
+ environment:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/environment.html.twig'
+ priority: 400
+ merchant_id:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/merchant_id.html.twig'
+ priority: 300
+ service_id:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/service_id.html.twig'
+ priority: 200
+ service_key:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/service_key.html.twig'
+ priority: 100
+ authorization_token:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/authorization_token.html.twig'
+ priority: 0
diff --git a/config/twig_hooks/payment_method/admin/update.yaml b/config/twig_hooks/payment_method/admin/update.yaml
new file mode 100644
index 0000000..db9cbd6
--- /dev/null
+++ b/config/twig_hooks/payment_method/admin/update.yaml
@@ -0,0 +1,18 @@
+sylius_twig_hooks:
+ hooks:
+ 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.imoje_paywall':
+ environment:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/environment.html.twig'
+ priority: 400
+ merchant_id:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/merchant_id.html.twig'
+ priority: 300
+ service_id:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/service_id.html.twig'
+ priority: 200
+ service_key:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/service_key.html.twig'
+ priority: 100
+ authorization_token:
+ template: '@BitBagSyliusImojePlugin/admin/payment_method/form/authorization_token.html.twig'
+ priority: 0
diff --git a/doc/configuration.md b/doc/configuration.md
new file mode 100644
index 0000000..d1c556c
--- /dev/null
+++ b/doc/configuration.md
@@ -0,0 +1,36 @@
+# Configuration
+
+---
+
+## Shop admin panel:
+To create an ING-based payment method, go to Payment methods in the Sylius admin panel.
+After that, you need to add an ING payment:
+
+
+
+And now, you can configure your payment method in the admin panel:
+
+
+
+## ING admin panel:
+To configure the imoje gateway, log in to ING the admin panel.
+
+- [Sandbox ING admin panel](https://sandbox.imoje.ing.pl)
+- [Production ING admin panel](https://imoje.ing.pl)
+
+From `Shops` -> `Your shop` -> `Details` -> `Integration data` you can acquire needed keys:
+
+- Merchant ID,
+- Service ID,
+- Service key,
+
+Also, here in the integration data page you need to configure the path to your webhook,
+just type in your shop URL followed by: `/payment/imoje/notify`
+
+In sandbox mode, you can use Ngrok or another tunneling program to expose your localhost.
+
+
+
+The authorization token can be obtained from `Your profile` → `API keys` → `Details`
+
+
diff --git a/doc/create_imoje_payment_method.png b/doc/create_imoje_payment_method.png
new file mode 100644
index 0000000..effe942
Binary files /dev/null and b/doc/create_imoje_payment_method.png differ
diff --git a/doc/create_ing_method.png b/doc/create_ing_method.png
deleted file mode 100644
index 92e0779..0000000
Binary files a/doc/create_ing_method.png and /dev/null differ
diff --git a/doc/functionalities.md b/doc/functionalities.md
index 790be45..3795a02 100644
--- a/doc/functionalities.md
+++ b/doc/functionalities.md
@@ -11,14 +11,12 @@ It is a comprehensive payment gateway service, offering various payment methods
- After an installation, user should be able to create new `Imoje gateway` payment method in the `Payment methods` section in the admin panel.
-
-

-
+
- And now, you can configure your payment method in the admin panel:
-
-

-
+
- After this, created payment method should be visible in the checkout.
+
+
diff --git a/doc/imoje_api_key.png b/doc/imoje_api_key.png
new file mode 100644
index 0000000..b9f14ba
Binary files /dev/null and b/doc/imoje_api_key.png differ
diff --git a/doc/imoje_integration_data.png b/doc/imoje_integration_data.png
new file mode 100644
index 0000000..b70d505
Binary files /dev/null and b/doc/imoje_integration_data.png differ
diff --git a/doc/installation.md b/doc/installation.md
index 77b3a29..f704b1e 100644
--- a/doc/installation.md
+++ b/doc/installation.md
@@ -10,16 +10,6 @@ ADDITIONAL
- [Known Issues](#known-issues)
---
-## Requirements:
-We work on stable, supported and up-to-date versions of packages. We recommend you to do the same.
-
-| Package | Version |
-|---------------|---------------------|
-| PHP | \>=8.1 |
-| sylius/sylius | \>=1.12.13 - 1.13.x |
-| MySQL | \>= 5.7 |
-| NodeJS | \>= 14.x |
-
## Composer:
```bash
composer require bitbag/imoje-paywall-plugin --with-all-dependencies
@@ -39,10 +29,15 @@ return [
Add routing to your `config/routes.yaml` file:
```yaml
-# config/routes.yaml
-
bitbag_sylius_imoje_plugin:
- resource: "@BitBagSyliusImojePlugin/config/routing.yml"
+ resource: "@BitBagSyliusImojePlugin/config/routes.yaml"
+```
+
+Import plugin configuration in `config/packages/_sylius.yaml` file:
+```yaml
+ imports:
+ # ...
+ - { resource: "@BitBagSyliusImojePlugin/config/config.yaml" }
```
## Known issues
@@ -51,3 +46,10 @@ For incorrectly displayed translations, execute the command:
```bash
bin/console cache:clear
```
+
+### Can't create payment method (Invalid encryption key)
+
+To create a new payment configuration, you need a valid encryption key. If you don’t have one, generate it by running:
+```bash
+bin/console sylius:payment:generate-key
+```
diff --git a/doc/payment_method_config.png b/doc/payment_method_config.png
index 9afb12c..abfd71b 100644
Binary files a/doc/payment_method_config.png and b/doc/payment_method_config.png differ
diff --git a/doc/shop_checkout.png b/doc/shop_checkout.png
new file mode 100644
index 0000000..15a3230
Binary files /dev/null and b/doc/shop_checkout.png differ
diff --git a/ecs.php b/ecs.php
index 3cf43de..21a4b41 100644
--- a/ecs.php
+++ b/ecs.php
@@ -1,21 +1,10 @@
paths([
- __DIR__ . '/src',
- __DIR__ . '/tests/Behat',
- __DIR__ . '/ecs.php',
- ]);
-
- $ecsConfig->import('vendor/sylius-labs/coding-standard/ecs.php');
+return static function (ECSConfig $config): void {
+ putenv('ALLOW_BITBAG_OS_HEADER=1');
- $ecsConfig->skip([
- VisibilityRequiredFixer::class => ['*Spec.php'],
- ]);
+ $config->import('vendor/bitbag/coding-standard/ecs.php');
+ $config->paths(['src', 'tests']);
};
-
diff --git a/phpspec.yml.dist b/phpspec.yml.dist
deleted file mode 100644
index 2dc73c0..0000000
--- a/phpspec.yml.dist
+++ /dev/null
@@ -1,4 +0,0 @@
-suites:
- main:
- namespace: BitBag\SyliusImojePlugin
- psr4_prefix: BitBag\SyliusImojePlugin
diff --git a/phpstan.neon b/phpstan.neon
index 3256831..8133864 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,5 +1,5 @@
parameters:
- level: max
+ level: 7
reportUnmatchedIgnoredErrors: false
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
@@ -7,14 +7,8 @@ parameters:
- src
- tests/Behat
- excludes_analyse:
- # Makes PHPStan crash
- - 'src/DependencyInjection/Configuration.php'
-
# Test dependencies
- 'tests/Application/app/**.php'
- 'tests/Application/src/**.php'
ignoreErrors:
- - '/Parameter #1 \$configuration of method Symfony\\Component\\DependencyInjection\\Extension\\Extension::processConfiguration\(\) expects Symfony\\Component\\Config\\Definition\\ConfigurationInterface, Symfony\\Component\\Config\\Definition\\ConfigurationInterface\|null given\./'
- - '#Property .+::\$requestStack is never read, only written\.#'
diff --git a/psalm.xml b/psalm.xml
deleted file mode 100644
index 3240886..0000000
--- a/psalm.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/spec/Action/CaptureActionSpec.php b/spec/Action/CaptureActionSpec.php
deleted file mode 100644
index b33bf3e..0000000
--- a/spec/Action/CaptureActionSpec.php
+++ /dev/null
@@ -1,117 +0,0 @@
-beConstructedWith($signatureResolver);
- }
-
- public function it_should_return_true_when_request_and_model_is_valid(
- Capture $request,
- ArrayObject $arrayObject,
- ): void {
- $request->getModel()->willReturn($arrayObject);
-
- $this->supports($request)->shouldReturn(true);
- }
-
- public function it_should_return_false_when_model_is_invalid(
- Capture $request,
- ): void {
- $request->getModel()->willReturn(null);
-
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_request_is_not_a_capture_instance(
- Request $request,
- ): void {
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_executes_correctly_with_valid_request(
- Capture $request,
- OrderInterface $order,
- PaymentInterface $payment,
- PaymentSecurityTokenInterface $token,
- AddressInterface $address,
- CustomerInterface $customer,
- ImojeApi $apiClass,
- SignatureResolverInterface $signatureResolver,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::NEW_STATUS, 'paymentId' => 123, 'tokenHash' => '1234sdcsdfxz'];
- $request->getModel()->willReturn(new ArrayObject($data));
-
- $request->getToken()->willReturn('1234sdcsdfxz');
- $request->getFirstModel()->willReturn($payment);
- $request->getToken()->willReturn($token);
-
- $payment->getOrder()->willReturn($order);
- $payment->getId()->willReturn(123);
-
- $token->getHash()->willReturn('1234sdcsdfxz');
-
- $apiClass->getServiceKey()->willReturn('1234sdcsdfxz');
- $order->getBillingAddress()->willReturn($address);
- $order->getCustomer()->willReturn($customer);
-
- $apiClass->getApiUrl()->willReturn('http://example.com/');
-
- $apiClass->getServiceId()->willReturn('1');
- $apiClass->getMerchantId()->willReturn('1');
- $order->getTotal()->willReturn(1000);
- $order->getCurrencyCode()->willReturn('EUR');
- $order->getNumber()->willReturn('123');
- $address->getFirstName()->willReturn('John Doe');
- $address->getLastName()->willReturn('Smith');
- $token->getAfterUrl()->willReturn('http://example.com/');
- $customer->getEmail()->willReturn('john@doe.com');
-
- $orderData = [
- 'serviceId' => '1',
- 'merchantId' => '1',
- 'amount' => 1000,
- 'currency' => 'EUR',
- 'orderId' => '123',
- 'customerFirstName' => 'John Doe',
- 'customerLastName' => 'Smith',
- 'urlReturn' => 'http://example.com/',
- 'customerEmail' => 'john@doe.com',
- ];
-
- $signatureResolver->createSignature($orderData, '1234sdcsdfxz')
- ->willReturn('signature');
-
- $request->setModel(new ArrayObject($data))->shouldBeCalled();
-
- $this->setApi($apiClass);
- $this->shouldThrow(HttpPostRedirect::class)
- ->during('execute', [$request]);
- }
-}
diff --git a/spec/Action/ConvertPaymentActionSpec.php b/spec/Action/ConvertPaymentActionSpec.php
deleted file mode 100644
index 1883e8b..0000000
--- a/spec/Action/ConvertPaymentActionSpec.php
+++ /dev/null
@@ -1,108 +0,0 @@
-shouldHaveType(ConvertPaymentAction::class);
- }
-
- function it_implements_imoje_gateway_factory_interface(): void
- {
- $this->shouldHaveType(ActionInterface::class);
- }
-
- public function it_sets_result_from_payment_details_with_non_empty_details(
- Convert $request,
- PaymentInterface $payment,
- ): void {
- $request->getSource()->willReturn($payment);
- $payment->getDetails()->willReturn(['field' => '123']);
- $request->setResult(['field' => '123'])->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_sets_empty_result_when_payment_details_are_empty(
- Convert $request,
- PaymentInterface $payment,
- ): void {
- $payment->getDetails()->willReturn([]);
- $request->getSource()->willReturn($payment);
- $request->setResult([])->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_sets_result_when_payment_details_contain_null(
- Convert $request,
- PaymentInterface $payment,
- ): void {
- $payment->getDetails()->willReturn(['key' => null]);
- $request->getSource()->willReturn($payment);
- $request->setResult(['key' => null])->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_true_when_getTo_and_source_is_valid(
- Convert $request,
- PaymentInterface $payment,
- ): void {
- $request->getSource()->willReturn($payment);
- $request->getTo()->willReturn('array');
-
- $this->supports($request)->shouldReturn(true);
- }
-
- public function it_should_return_false_when_source_is_invalid(
- Convert $request,
- ): void {
- $request->getSource()->willReturn(null);
- $request->getTo()->willReturn('array');
-
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_getTo_is_invalid(
- Convert $request,
- PaymentInterface $payment,
- ): void {
- $request->getSource()->willReturn($payment);
- $request->getTo()->willReturn('object');
-
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_getTo_and_source_is_invalid(
- Convert $request,
- ): void {
- $request->getSource()->willReturn(null);
- $request->getTo()->willReturn('object');
-
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_request_invalid(
- Request $request,
- ): void {
- $this->supports($request)->shouldReturn(false);
- }
-}
diff --git a/spec/Action/NotifyActionSpec.php b/spec/Action/NotifyActionSpec.php
deleted file mode 100644
index 246c315..0000000
--- a/spec/Action/NotifyActionSpec.php
+++ /dev/null
@@ -1,124 +0,0 @@
-beConstructedWith(
- $requestStack,
- $signatureResolver,
- );
- }
-
- public function it_should_return_true_when_request_and_request_data_is_valid(
- Notify $request,
- ArrayObject $arrayObject,
- SignatureResolverInterface $signatureResolver,
- ImojeApi $api,
- Request $httpRequest,
- RequestStack $requestStack,
- ): void {
- $request->getModel()->willReturn($arrayObject);
- $requestStack->getCurrentRequest()
- ->willReturn($httpRequest);
- $api->getServiceKey()->willReturn('1234sdcsdfxz');
- $signatureResolver->verifySignature($httpRequest, '1234sdcsdfxz')
- ->willReturn(true);
-
- $this->setApi($api);
- $this->supports($request)->shouldReturn(true);
- }
-
- public function it_should_return_false_when_request_and_signature_are_invalid(
- Notify $request,
- ArrayObject $arrayObject,
- SignatureResolverInterface $signatureResolver,
- ImojeApi $api,
- Request $httpRequest,
- RequestStack $requestStack,
- ): void {
- $request->getModel()->willReturn($arrayObject);
- $requestStack->getCurrentRequest()->willReturn($httpRequest);
- $api->getServiceKey()->willReturn('1234sdcsdfxz');
- $signatureResolver->verifySignature($httpRequest, '1234sdcsdfxz')
- ->willReturn(false);
-
- $this->setApi($api);
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_request_is_empty(
- Notify $request,
- ImojeApi $api,
- RequestStack $requestStack,
- Request $httpRequest,
- ): void {
- $request->getModel()->willReturn(null);
- $requestStack->getCurrentRequest()->willReturn($httpRequest);
- $api->getServiceKey()->willReturn(null);
-
- $this->supports($request)->shouldReturn(false);
- }
-
- public function it_should_return_false_when_request_is_invalid_and(
- Notify $request,
- RequestStack $requestStack,
- Request $httpRequest,
- ): void {
- $request->getModel()->willReturn(null);
- $requestStack->getCurrentRequest()->willReturn($httpRequest);
-
- $this->supports($httpRequest)->shouldReturn(false);
- }
-
- public function it_sets_model_status_from_notification_data(
- Notify $request,
- ArrayObject $arrayObject,
- SignatureResolverInterface $signatureResolver,
- ImojeApi $api,
- Request $httpRequest,
- RequestStack $requestStack,
- ): void {
- $requestStack->getCurrentRequest()->willReturn($httpRequest);
- $api->getServiceKey()->willReturn('1234sdcsdfxz');
- $signatureResolver->verifySignature($httpRequest, '1234sdcsdfxz')
- ->willReturn(true);
- $notificationData = ['transaction' => ['status' => 'new', 'paymentId' => 1, 'tokenHash' => '1234sdcsdfxz']];
- $jsonNotificationData = json_encode($notificationData);
- $httpRequest->getContent()->willReturn($jsonNotificationData);
- $request->getModel()->willReturn(new ArrayObject([
- 'status' => 'new',
- 'paymentId' => 1,
- 'tokenHash' => '1234sdcsdfxz',
- ]));
- $request->setModel(new ArrayObject([
- 'status' => 'new',
- 'paymentId' => 1,
- 'tokenHash' => '1234sdcsdfxz',
- 'statusImoje' => 'new',
- ]))->willReturn($arrayObject);
-
- $this->setApi($api);
- $this->execute($request);
- }
-}
diff --git a/spec/Action/StatusActionSpec.php b/spec/Action/StatusActionSpec.php
deleted file mode 100644
index 0cf0f2d..0000000
--- a/spec/Action/StatusActionSpec.php
+++ /dev/null
@@ -1,135 +0,0 @@
-shouldHaveType(StatusAction::class);
- }
-
- public function it_should_implement_interface(): void
- {
- $this->shouldImplement(ActionInterface::class);
- }
-
- public function it_should_return_new_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::NEW_STATUS, 'paymentId' => 1];
-
- $request->getModel()->willReturn(new ArrayCollection($data));
-
- $request->markNew()->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_pending_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::PENDING_STATUS, 'paymentId' => 1];
-
- $request->getModel()->willReturn(new ArrayCollection($data));
- $request->markPending()->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_cancelled_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::CANCELLED_STATUS, 'paymentId' => 1, 'tokenHash' => 'dfgdsgxcvxcerf234'];
-
- $request->getModel()->willReturn(new ArrayCollection($data));
- $request->markCanceled()->shouldBeCalled();
- $data['tokenHash'] = '';
-
- $request->setModel(new ArrayCollection($data))->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_rejected_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::REJECTED_STATUS, 'paymentId' => 1, 'tokenHash' => 'dfgdsgxcvxcerf234'];
- $request->getModel()->willReturn(new ArrayCollection($data));
- $request->markFailed()->shouldBeCalled();
- $data['tokenHash'] = '';
-
- $request->setModel(new ArrayCollection($data))->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_settled_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => ImojeApiInterface::SETTLED_STATUS, 'paymentId' => 1, 'tokenHash' => 'dfgdsgxcvxcerf234'];
- $request->getModel()->willReturn(new ArrayCollection($data));
-
- $request->markCaptured()->shouldBeCalled();
-
- $this->execute($request);
- }
-
- public function it_should_return_unknown_status(
- GetStatusInterface $request,
- ): void {
- $data = ['statusImoje' => 'test', 'paymentId' => 1, 'tokenHash' => 'dfgdsgxcvxcerf234'];
- $request->getModel()->willReturn(new ArrayCollection($data));
-
- $request->markUnknown()->shouldBeCalled();
-
- $this->execute($request);
- }
-
- function it_throws_exception_if_request_not_supported(
- GetStatusInterface $request,
- ): void {
- $this->shouldThrow(RequestNotSupportedException::class)->during('execute', [$request]);
- }
-
- function it_returns_true_if_request_is_valid(
- GetStatusInterface $request,
- ArrayAccess $model,
- ): void {
- $request->getModel()->willReturn($model);
-
- $this->supports($request)->shouldBe(true);
- }
-
- function it_returns_false_if_request_model_is_empty(
- GetStatusInterface $request,
- ): void {
- $request->getModel()->willReturn(null);
-
- $this->supports($request)->shouldBe(false);
- }
-
- function it_returns_false_if_request_class_not_instanceof_GetStatusInterface(
- Request $request,
- ): void {
- $this->supports($request)->shouldBe(false);
- }
-}
diff --git a/spec/ImojeGatewayFactorySpec.php b/spec/ImojeGatewayFactorySpec.php
deleted file mode 100644
index 0a1c73d..0000000
--- a/spec/ImojeGatewayFactorySpec.php
+++ /dev/null
@@ -1,28 +0,0 @@
-shouldHaveType(ImojeGatewayFactory::class);
- }
-
- function it_implements_imoje_gateway_factory_interface(): void
- {
- $this->shouldHaveType(GatewayFactoryInterface::class);
- }
-}
diff --git a/spec/Provider/PaymentTokenProviderSpec.php b/spec/Provider/PaymentTokenProviderSpec.php
deleted file mode 100644
index f8b2dd7..0000000
--- a/spec/Provider/PaymentTokenProviderSpec.php
+++ /dev/null
@@ -1,93 +0,0 @@
-beConstructedWith($orderRepository, $paymentTokenRepository);
- }
-
- public function it_is_initializable(): void
- {
- $this->shouldHaveType(PaymentTokenProvider::class);
- }
-
- public function it_should_return_token_correctly(
- Request $request,
- OrderInterface $order,
- PaymentSecurityTokenInterface $token,
- PaymentInterface $payment,
- RepositoryInterface $orderRepository,
- RepositoryInterface $paymentTokenRepository,
- ): void {
- $orderNumber = 500;
- $tokenHash = '3423423453fsxzc';
-
- $transactionData = [
- 'transaction' => [
- 'orderId' => $orderNumber,
- 'tokenHash' => $tokenHash,
- ],
- ];
-
- $request->getContent()->willReturn(json_encode($transactionData));
- $orderRepository->findOneBy(['number' => $orderNumber])->willReturn($order);
- $order->getPayments()
- ->willReturn(new ArrayCollection([
- $payment->getWrappedObject(),
- ]));
- $payment->getState()->willReturn(PaymentInterface::STATE_NEW);
- $payment->getDetails()->willReturn(['tokenHash' => $tokenHash]);
- $paymentTokenRepository->findOneBy(['hash' => $tokenHash])->willReturn($token);
-
- $this->provideToken($request)->shouldReturn($token);
- }
-
- public function it_should_return_null_if_paymentTokenRepository_is_not_called(
- Request $request,
- OrderInterface $order,
- PaymentInterface $payment,
- RepositoryInterface $orderRepository,
- ): void {
- $orderNumber = 500;
- $tokenHash = '3423423453fsxzc';
- $transactionData = [
- 'transaction' => [
- 'orderId' => $orderNumber,
- 'tokenHash' => $tokenHash,
- ],
- ];
- $request->getContent()->willReturn(json_encode($transactionData));
- $orderRepository->findOneBy(['number' => $orderNumber])
- ->willReturn($order);
- $order->getPayments()
- ->willReturn(new ArrayCollection([
- $payment->getWrappedObject(),
- ]));
- $payment->getState()->willReturn(PaymentInterface::STATE_CANCELLED);
- $payment->getDetails()->willReturn(['tokenHash' => $tokenHash]);
-
- $this->provideToken($request)->shouldReturn(null);
- }
-}
diff --git a/spec/Resolver/SignatureResolverSpec.php b/spec/Resolver/SignatureResolverSpec.php
deleted file mode 100644
index 02ad24c..0000000
--- a/spec/Resolver/SignatureResolverSpec.php
+++ /dev/null
@@ -1,95 +0,0 @@
-shouldHaveType(SignatureResolver::class);
- }
-
- public function it_should_sort_fields_and_build_data_string(): void
- {
- $fields = [
- 'field1' => 'value1',
- 'field2' => 'value2',
- ];
- $serviceKey = 'adasvcx3412';
- $expectedDataString = 'field1=value1&field2=value2';
- $expectedHash = hash(ImojeApiInterface::HASHING_ALGORITHM, $expectedDataString . $serviceKey) . ';' . ImojeApiInterface::HASHING_ALGORITHM;
-
- $this->createSignature($fields, $serviceKey)->shouldReturn($expectedHash);
- }
-
- public function it_should_return_hash_with_service_key_only_when_fields_are_empty(): void
- {
- $fields = [];
- $serviceKey = 'adasvcx3412';
- $expectedHash = hash(ImojeApiInterface::HASHING_ALGORITHM, $serviceKey) . ';' . ImojeApiInterface::HASHING_ALGORITHM;
-
- $this->createSignature($fields, $serviceKey)->shouldReturn($expectedHash);
- }
-
- public function it_should_return_hash_without_service_key_when_service_key_is_empty(): void
- {
- $fields = [
- 'field1' => 'value1',
- 'field2' => 'value2',
- ];
- $serviceKey = '';
- $expectedDataString = 'field1=value1&field2=value2';
- $expectedHash = hash(ImojeApiInterface::HASHING_ALGORITHM, $expectedDataString) . ';' . ImojeApiInterface::HASHING_ALGORITHM;
-
- $this->createSignature($fields, $serviceKey)->shouldReturn($expectedHash);
- }
-
- public function it_should_return_true_if_signatures_match(
- Request $request,
- ): void {
- $serviceKey = 'adasvcx3412';
- $body = 'test.jpg';
- $exampleHash = hash('sha256', sprintf('test.jpg%s', $serviceKey));
- $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
- $request->getContent()->willReturn($body);
-
- $request->headers = new \Symfony\Component\HttpFoundation\HeaderBag(['X-Imoje-Signature' => $headerSignature]);
-
- $this->verifySignature($request, $serviceKey)->shouldBe(true);
- }
-
- public function it_should_return_false_if_signatures_not_match(
- Request $request,
- ): void {
- $serviceKey = 'adasvcx3412';
- $body = 'test2.jpg';
- $exampleHash = hash('sha256', sprintf('test.jpg%s', $serviceKey));
- $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
- $request->getContent()->willReturn($body);
-
- $request->headers = new \Symfony\Component\HttpFoundation\HeaderBag(['X-Imoje-Signature' => $headerSignature]);
-
- $this->verifySignature($request, $serviceKey)->shouldBe(false);
- }
-
- public function it_should_return_false_if_content_is_empty(
- Request $request,
- ): void {
- $serviceKey = '';
- $body = '';
- $exampleHash = '';
- $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
- $request->getContent()->willReturn($body);
-
- $request->headers = new \Symfony\Component\HttpFoundation\HeaderBag(['X-Imoje-Signature' => $headerSignature]);
-
- $this->verifySignature($request, $serviceKey)->shouldBe(false);
- }
-}
diff --git a/src/Action/CaptureAction.php b/src/Action/CaptureAction.php
deleted file mode 100644
index 0022a53..0000000
--- a/src/Action/CaptureAction.php
+++ /dev/null
@@ -1,90 +0,0 @@
-apiClass = ImojeApi::class;
- }
-
- public function execute($request): void
- {
- RequestNotSupportedException::assertSupports($this, $request);
- $model = $request->getModel();
-
- /** @var PaymentInterface $payment */
- $payment = $request->getFirstModel();
-
- /** @var OrderInterface $order */
- $order = $payment->getOrder();
-
- /** @var PaymentSecurityTokenInterface $token */
- $token = $request->getToken();
-
- $orderData = $this->prepareOrderData($order, $token);
-
- $model['tokenHash'] = $token->getHash();
- $model['statusImoje'] = ImojeApiInterface::NEW_STATUS;
- $model['paymentId'] = $payment->getId();
- $request->setModel($model);
-
- throw new HttpPostRedirect(
- $this->api->getApiUrl(),
- $orderData,
- );
- }
-
- public function supports($request): bool
- {
- return
- $request instanceof Capture &&
- $request->getModel() instanceof ArrayObject;
- }
-
- private function prepareOrderData(OrderInterface $order, PaymentSecurityTokenInterface $token): array
- {
- $orderData = [];
-
- $billingAddress = $order->getBillingAddress();
- $customer = $order->getCustomer();
-
- $orderData['serviceId'] = $this->api->getServiceId();
- $orderData['merchantId'] = $this->api->getMerchantId();
- $orderData['amount'] = $order->getTotal();
- $orderData['currency'] = $order->getCurrencyCode();
- $orderData['orderId'] = $order->getNumber();
- $orderData['customerFirstName'] = $billingAddress?->getFirstName();
- $orderData['customerLastName'] = $billingAddress?->getLastName();
- $orderData['urlReturn'] = $token->getAfterUrl();
- $orderData['customerEmail'] = $customer?->getEmail();
- $orderData['signature'] = $this->signatureResolver->createSignature($orderData, $this->api->getServiceKey());
-
- return $orderData;
- }
-}
diff --git a/src/Action/ConvertPaymentAction.php b/src/Action/ConvertPaymentAction.php
deleted file mode 100644
index be187f2..0000000
--- a/src/Action/ConvertPaymentAction.php
+++ /dev/null
@@ -1,35 +0,0 @@
-getSource();
- $details = ArrayObject::ensureArrayObject($payment->getDetails());
-
- $request->setResult((array) $details);
- }
-
- public function supports($request): bool
- {
- return
- $request instanceof Convert &&
- $request->getSource() instanceof PaymentInterface &&
- $request->getTo() === 'array';
- }
-}
diff --git a/src/Action/NotifyAction.php b/src/Action/NotifyAction.php
deleted file mode 100644
index 7a1be8b..0000000
--- a/src/Action/NotifyAction.php
+++ /dev/null
@@ -1,68 +0,0 @@
-request = $requestStack->getCurrentRequest();
- $this->apiClass = ImojeApi::class;
- }
-
- public function execute($request): void
- {
- RequestNotSupportedException::assertSupports($this, $request);
-
- if (null == $this->request) {
- throw new \Exception('Request is empty');
- }
-
- /** @var string $content */
- $content = $this->request->getContent();
- $notificationData = json_decode($content, true);
- $transactionData = $notificationData['transaction'];
-
- $model = $request->getModel();
- $model['statusImoje'] = $transactionData['status'];
-
- $request->setModel($model);
- }
-
- public function supports($request): bool
- {
- if (null == $this->request) {
- return false;
- }
-
- return
- $request instanceof Notify &&
- $request->getModel() instanceof ArrayObject &&
- $this->signatureResolver->verifySignature($this->request, $this->api->getServiceKey());
- }
-}
diff --git a/src/Action/StatusAction.php b/src/Action/StatusAction.php
deleted file mode 100644
index d088982..0000000
--- a/src/Action/StatusAction.php
+++ /dev/null
@@ -1,74 +0,0 @@
-getModel();
- $status = $model['statusImoje'] ?? null;
- $paymentId = $model['paymentId'] ?? null;
-
- if (($status === null || ImojeApiInterface::NEW_STATUS === $status) && null !== $paymentId) {
- $request->markNew();
-
- return;
- }
-
- if (ImojeApiInterface::PENDING_STATUS === $status) {
- $request->markPending();
-
- return;
- }
-
- if (ImojeApiInterface::CANCELLED_STATUS === $status) {
- $request->markCanceled();
-
- $model['tokenHash'] = '';
- $request->setModel($model);
-
- return;
- }
-
- if (ImojeApiInterface::REJECTED_STATUS === $status) {
- $request->markFailed();
-
- $model['tokenHash'] = '';
- $request->setModel($model);
-
- return;
- }
-
- if (ImojeApiInterface::SETTLED_STATUS === $status) {
- $request->markCaptured();
-
- return;
- }
-
- $request->markUnknown();
- }
-
- public function supports($request): bool
- {
- return $request instanceof GetStatusInterface &&
- $request->getModel() instanceof ArrayAccess
- ;
- }
-}
diff --git a/src/Api/ImojeApi.php b/src/Api/ImojeApi.php
deleted file mode 100644
index 49d96d7..0000000
--- a/src/Api/ImojeApi.php
+++ /dev/null
@@ -1,48 +0,0 @@
-environment === 'production' ? self::PRODUCTION_PAYWALL_URL : self::SANDBOX_PAYWALL_URL;
- }
-
- public function getMerchantId(): string
- {
- return $this->merchantId;
- }
-
- public function getServiceId(): string
- {
- return $this->serviceId;
- }
-
- public function getServiceKey(): string
- {
- return $this->serviceKey;
- }
-
- public function getAuthorizationToken(): string
- {
- return $this->authorizationToken;
- }
-}
diff --git a/src/Api/ImojeApiInterface.php b/src/Api/ImojeApiInterface.php
deleted file mode 100644
index 6f4e716..0000000
--- a/src/Api/ImojeApiInterface.php
+++ /dev/null
@@ -1,44 +0,0 @@
-paymentRequestProvider->provide($captureEndPaymentRequest);
+
+ if (PaymentRequestInterface::STATE_PROCESSING !== $paymentRequest->getState()) {
+ return;
+ }
+
+ $this->paymentTransitionProcessor->process($paymentRequest);
+
+ $this->stateMachine->apply(
+ $paymentRequest,
+ PaymentRequestTransitions::GRAPH,
+ PaymentRequestTransitions::TRANSITION_COMPLETE,
+ );
+ }
+}
diff --git a/src/CommandHandler/CapturePaymentRequestHandler.php b/src/CommandHandler/CapturePaymentRequestHandler.php
new file mode 100644
index 0000000..f2b6b36
--- /dev/null
+++ b/src/CommandHandler/CapturePaymentRequestHandler.php
@@ -0,0 +1,104 @@
+paymentRequestProvider->provide($capturePaymentRequest);
+
+ $paymentMethod = $paymentRequest->getMethod();
+ $gatewayConfig = $paymentMethod->getGatewayConfig();
+ Assert::notNull($gatewayConfig, sprintf(
+ 'The payment method (code: %s) has not been configured.',
+ $paymentMethod->getCode(),
+ ));
+ /** @var PaymentInterface $payment */
+ $payment = $paymentRequest->getPayment();
+ /** @var OrderInterface $order */
+ $order = $payment->getOrder();
+
+ /** @var string $environment */
+ $environment = $gatewayConfig->getConfig()['environment']->value;
+ $returnUrl = $this->afterPayUrlProvider->getUrl($paymentRequest, UrlGeneratorInterface::ABSOLUTE_URL);
+
+ $paymentRequest->setResponseData([
+ 'url' => $this->getPaymentUrl($environment),
+ 'orderData' => $this->prepareOrderData($order, $gatewayConfig, $returnUrl),
+ ]);
+
+ $this->stateMachine->apply(
+ $paymentRequest,
+ PaymentRequestTransitions::GRAPH,
+ PaymentRequestTransitions::TRANSITION_PROCESS,
+ );
+ }
+
+ private function prepareOrderData(
+ OrderInterface $order,
+ GatewayConfigInterface $gatewayConfig,
+ string $returnUrl,
+ ): array {
+ $orderData = [];
+
+ $billingAddress = $order->getBillingAddress();
+ $customer = $order->getCustomer();
+ /** @var string $serviceKey */
+ $serviceKey = $gatewayConfig->getConfig()['service_key'];
+ /** @var string $serviceId */
+ $serviceId = $gatewayConfig->getConfig()['service_id'];
+ /** @var string $merchantId */
+ $merchantId = $gatewayConfig->getConfig()['merchant_id'];
+
+ $orderData['serviceId'] = $serviceId;
+ $orderData['merchantId'] = $merchantId;
+ $orderData['amount'] = $order->getTotal();
+ $orderData['currency'] = $order->getCurrencyCode();
+ $orderData['orderId'] = $order->getNumber();
+ $orderData['customerFirstName'] = $billingAddress?->getFirstName();
+ $orderData['customerLastName'] = $billingAddress?->getLastName();
+ $orderData['urlReturn'] = $returnUrl;
+ $orderData['customerEmail'] = $customer?->getEmail();
+ $orderData['signature'] = $this->signatureResolver->createSignature($orderData, $serviceKey);
+
+ return $orderData;
+ }
+
+ private function getPaymentUrl(string $environment): string
+ {
+ return $environment === ImojeEnvironment::PRODUCTION_ENVIRONMENT->value ? ImojeEnvironment::PRODUCTION_URL->value : ImojeEnvironment::SANDBOX_URL->value;
+ }
+}
diff --git a/src/CommandHandler/StatusPaymentRequestHandler.php b/src/CommandHandler/StatusPaymentRequestHandler.php
new file mode 100644
index 0000000..70406d9
--- /dev/null
+++ b/src/CommandHandler/StatusPaymentRequestHandler.php
@@ -0,0 +1,43 @@
+paymentRequestProvider->provide($statusPaymentRequest);
+
+ $this->paymentTransitionProcessor->process($paymentRequest);
+
+ $this->stateMachine->apply(
+ $paymentRequest,
+ PaymentRequestTransitions::GRAPH,
+ PaymentRequestTransitions::TRANSITION_COMPLETE,
+ );
+ }
+}
diff --git a/src/CommandProvider/CapturePaymentRequestCommandProvider.php b/src/CommandProvider/CapturePaymentRequestCommandProvider.php
new file mode 100644
index 0000000..fedd684
--- /dev/null
+++ b/src/CommandProvider/CapturePaymentRequestCommandProvider.php
@@ -0,0 +1,34 @@
+getState()) {
+ return new CaptureEndPaymentRequest($paymentRequest->getId());
+ }
+
+ return new CapturePaymentRequest($paymentRequest->getId());
+ }
+}
diff --git a/src/CommandProvider/StatusPaymentRequestCommandProvider.php b/src/CommandProvider/StatusPaymentRequestCommandProvider.php
new file mode 100644
index 0000000..f1547e8
--- /dev/null
+++ b/src/CommandProvider/StatusPaymentRequestCommandProvider.php
@@ -0,0 +1,29 @@
+getId());
+ }
+}
diff --git a/src/Controller/NotifyController.php b/src/Controller/NotifyController.php
index 59650cc..e6e55ed 100644
--- a/src/Controller/NotifyController.php
+++ b/src/Controller/NotifyController.php
@@ -1,70 +1,93 @@
getContent()) {
- return new Response('', Response::HTTP_NO_CONTENT);
+ $content = $request->getContent();
+ if ('' === $content) {
+ return new Response('There is no content in request.', Response::HTTP_NO_CONTENT);
}
- $paymentToken = $this->paymentTokenProvider->provideToken($request);
+ $data = json_decode($content, true, 512, \JSON_THROW_ON_ERROR);
+ if (!is_array($data)) {
+ return new Response('Invalid JSON structure', Response::HTTP_BAD_REQUEST);
+ }
- if (null === $paymentToken) {
- throw new NotFoundHttpException('Payment token not found');
+ $orderNumber = (string) $data['payment']['orderId'];
+ if ('' === $orderNumber) {
+ return new Response('There is no order number in request data.', Response::HTTP_NO_CONTENT);
}
- $notifyToken = $this->payum->getHttpRequestVerifier()->verify($this->createRequestWithToken($request, $paymentToken));
- $gateway = $this->payum->getGateway($notifyToken->getGatewayName());
+ $order = $this->orderRepository->findOneByNumber($orderNumber);
+ Assert::notNull($order, sprintf(
+ 'There is no order for number: %s.',
+ $orderNumber,
+ ));
- $gateway->execute(new Notify($notifyToken));
+ $orderId = (string) $order->getId();
+ /** @var PaymentInterface|null $payment */
+ $payment = $this->paymentRepository->findOneBy(['order' => $orderId]);
+ Assert::notNull($payment, sprintf(
+ 'There is no payment registered for order: %s.',
+ $orderId,
+ ));
- return new JsonResponse(['status' => 'ok']);
- }
+ $paymentMethod = $payment->getMethod();
+ Assert::notNull($paymentMethod, sprintf(
+ 'There is no payment method in payment: %s.',
+ $payment->getId(),
+ ));
- private function createRequestWithToken(
- Request $request,
- PaymentSecurityTokenInterface $token,
- ): Request {
- $request = Request::create(
- $token->getTargetUrl(),
- $request->getMethod(),
- $request->query->all(),
- $request->cookies->all(),
- $request->files->all(),
- $request->server->all(),
- $request->getContent(),
- );
-
- $request->attributes->add([
- 'payum_token' => $token->getHash(),
- ]);
+ $gatewayConfig = $paymentMethod->getGatewayConfig();
+ Assert::notNull($gatewayConfig, sprintf(
+ 'The payment method (code: %s) has not been configured.',
+ $paymentMethod->getCode(),
+ ));
+
+ /** @var string $serviceKey */
+ $serviceKey = $gatewayConfig->getConfig()['service_key'];
- return $request;
+ if (false === $this->signatureResolver->verifySignature($request, $serviceKey)) {
+ return new Response('Signature verification failed', Response::HTTP_FORBIDDEN);
+ }
+
+ $imojePaymentStatus = (string) $data['payment']['status'];
+ $payment->setDetails(['status' => $imojePaymentStatus]);
+ $this->entityManager->persist($payment);
+ $this->entityManager->flush();
+
+ return new JsonResponse([
+ 'status' => $imojePaymentStatus,
+ ]);
}
}
diff --git a/src/DependencyInjection/BitBagSyliusImojeExtension.php b/src/DependencyInjection/BitBagSyliusImojeExtension.php
index 684b70e..934c419 100644
--- a/src/DependencyInjection/BitBagSyliusImojeExtension.php
+++ b/src/DependencyInjection/BitBagSyliusImojeExtension.php
@@ -1,10 +1,11 @@
load('services.xml');
+ $loader->load('services.yaml');
}
public function prepend(ContainerBuilder $container): void
diff --git a/src/Enum/ImojeEnvironment.php b/src/Enum/ImojeEnvironment.php
new file mode 100644
index 0000000..02f9213
--- /dev/null
+++ b/src/Enum/ImojeEnvironment.php
@@ -0,0 +1,21 @@
+ [
- 'bitbag.imoje_plugin.configuration.production' => ImojeApiInterface::PRODUCTION_ENVIRONMENT,
- 'bitbag.imoje_plugin.configuration.sandbox' => ImojeApiInterface::SANDBOX_ENVIRONMENT,
- ],
- 'label' => 'bitbag.imoje_plugin.configuration.environment',
+ 'choices' => [
+ 'bitbag.imoje_plugin.configuration.production' => ImojeEnvironment::PRODUCTION_ENVIRONMENT,
+ 'bitbag.imoje_plugin.configuration.sandbox' => ImojeEnvironment::SANDBOX_ENVIRONMENT,
+ ],
+ 'label' => 'bitbag.imoje_plugin.configuration.environment',
],
)
->add('merchant_id', TextType::class, [
@@ -76,6 +77,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
],
),
],
- ]);
+ ])
+ ;
}
}
diff --git a/src/ImojeGatewayFactory.php b/src/ImojeGatewayFactory.php
deleted file mode 100644
index b83a070..0000000
--- a/src/ImojeGatewayFactory.php
+++ /dev/null
@@ -1,54 +0,0 @@
-defaults(
- [
- 'payum.factory_name' => 'imoje',
- 'payum.factory_title' => 'Imoje',
- ],
- );
-
- if (false === (bool) $config['payum.api']) {
- $config['payum.default_options'] = [
- 'environment' => ImojeApiInterface::SANDBOX_ENVIRONMENT,
- 'merchant_id' => '',
- 'service_id' => '',
- 'service_key' => '',
- 'authorization_token' => '',
- ];
- $config->defaults($config['payum.default_options']);
-
- $config['payum.required_options'] = ['environment', 'merchant_id', 'service_id', 'service_key', 'authorization_token'];
-
- $config['payum.api'] = function (ArrayObject $config) {
- $config->validateNotEmpty($config['payum.required_options']);
-
- return new ImojeApi(
- $config['environment'],
- $config['merchant_id'],
- $config['service_id'],
- $config['service_key'],
- $config['authorization_token'],
- );
- };
- }
- }
-}
diff --git a/src/OrderPay/Provider/CaptureHttpResponseProvider.php b/src/OrderPay/Provider/CaptureHttpResponseProvider.php
new file mode 100644
index 0000000..0028962
--- /dev/null
+++ b/src/OrderPay/Provider/CaptureHttpResponseProvider.php
@@ -0,0 +1,38 @@
+getState();
+ }
+
+ public function getResponse(RequestConfiguration $requestConfiguration, PaymentRequestInterface $paymentRequest): Response
+ {
+ $data = $paymentRequest->getResponseData();
+ /** @var string $url */
+ $url = $data['url'];
+ $params = $data['orderData'];
+ $parsedParams = http_build_query($params);
+ $finalUrl = sprintf('%s?%s', $url, $parsedParams);
+
+ return new RedirectResponse($finalUrl, Response::HTTP_SEE_OTHER);
+ }
+}
diff --git a/src/Processor/PaymentTransitionProcessor.php b/src/Processor/PaymentTransitionProcessor.php
new file mode 100644
index 0000000..796337c
--- /dev/null
+++ b/src/Processor/PaymentTransitionProcessor.php
@@ -0,0 +1,55 @@
+getPayment();
+
+ $transition = $this->getTransition($payment);
+
+ if (null === $transition) {
+ return;
+ }
+
+ if ($this->stateMachine->can($payment, PaymentTransitions::GRAPH, $transition)) {
+ $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $transition);
+ }
+ }
+
+ private function getTransition(PaymentInterface $payment): ?string
+ {
+ $details = $payment->getDetails();
+ /** @var ?string $status */
+ $status = $details['status'] ?? null;
+
+ return match ($status) {
+ PaymentTransitionProcessorInterface::STATE_PENDING => PaymentTransitions::TRANSITION_PROCESS,
+ PaymentTransitionProcessorInterface::STATE_SETTLED => PaymentTransitions::TRANSITION_COMPLETE,
+ PaymentTransitionProcessorInterface::STATE_CANCELLED => PaymentTransitions::TRANSITION_CANCEL,
+ PaymentTransitionProcessorInterface::STATE_REJECTED => PaymentTransitions::TRANSITION_FAIL,
+ default => null
+ };
+ }
+}
diff --git a/src/Processor/PaymentTransitionProcessorInterface.php b/src/Processor/PaymentTransitionProcessorInterface.php
new file mode 100644
index 0000000..7af7b17
--- /dev/null
+++ b/src/Processor/PaymentTransitionProcessorInterface.php
@@ -0,0 +1,27 @@
+getContent();
- $content = json_decode($content, true);
-
- $transactionData = $content['transaction'];
-
- /** @var OrderInterface $order */
- $order = $this->getOrder($transactionData);
-
- /** @var Collection $payments */
- $payments = $order->getPayments();
-
- foreach ($payments as $payment) {
- $model = $payment->getDetails();
-
- $tokenHash = $model['tokenHash'] ?? null;
-
- if (
- null !== $tokenHash &&
- $payment->getState() !== PaymentInterface::STATE_CANCELLED &&
- $payment->getState() !== PaymentInterface::STATE_FAILED
- ) {
- return $this->getToken($tokenHash);
- }
- }
-
- return null;
- }
-
- private function getOrder(array $transactionData): ?OrderInterface
- {
- /** @var OrderInterface|null $order */
- $order = $this->orderRepository->findOneBy(['number' => $transactionData['orderId']]);
-
- return $order;
- }
-
- private function getToken(string $hash): ?PaymentSecurityTokenInterface
- {
- /** @var PaymentSecurityTokenInterface|null $token */
- $token = $this->paymentTokenRepository->findOneBy(['hash' => $hash]);
-
- return $token;
- }
-}
diff --git a/src/Provider/PaymentTokenProviderInterface.php b/src/Provider/PaymentTokenProviderInterface.php
deleted file mode 100644
index 8ba4481..0000000
--- a/src/Provider/PaymentTokenProviderInterface.php
+++ /dev/null
@@ -1,19 +0,0 @@
-value, $dataString . $serviceKey) . ';' . ImojeEnvironment::HASHING_ALGORITHM->value;
}
public function verifySignature(Request $request, string $serviceKey): bool
diff --git a/src/Resolver/SignatureResolverInterface.php b/src/Resolver/SignatureResolverInterface.php
index 1722aee..3b2249d 100644
--- a/src/Resolver/SignatureResolverInterface.php
+++ b/src/Resolver/SignatureResolverInterface.php
@@ -1,10 +1,11 @@
+ {{ form_row(form, sylius_test_form_attribute('config-authorization-token')) }}
+
diff --git a/templates/admin/payment_method/form/environment.html.twig b/templates/admin/payment_method/form/environment.html.twig
new file mode 100644
index 0000000..45a96c8
--- /dev/null
+++ b/templates/admin/payment_method/form/environment.html.twig
@@ -0,0 +1,5 @@
+{% set form = hookable_metadata.context.form.gatewayConfig.config.environment %}
+
+
+ {{ form_row(form, sylius_test_form_attribute('config-environment')) }}
+
diff --git a/templates/admin/payment_method/form/merchant_id.html.twig b/templates/admin/payment_method/form/merchant_id.html.twig
new file mode 100644
index 0000000..1fe71df
--- /dev/null
+++ b/templates/admin/payment_method/form/merchant_id.html.twig
@@ -0,0 +1,5 @@
+{% set form = hookable_metadata.context.form.gatewayConfig.config.merchant_id %}
+
+
+ {{ form_row(form, sylius_test_form_attribute('config-merchant-id')) }}
+
diff --git a/templates/admin/payment_method/form/service_id.html.twig b/templates/admin/payment_method/form/service_id.html.twig
new file mode 100644
index 0000000..ab9942a
--- /dev/null
+++ b/templates/admin/payment_method/form/service_id.html.twig
@@ -0,0 +1,5 @@
+{% set form = hookable_metadata.context.form.gatewayConfig.config.service_id %}
+
+
+ {{ form_row(form, sylius_test_form_attribute('config-service-id')) }}
+
diff --git a/templates/admin/payment_method/form/service_key.html.twig b/templates/admin/payment_method/form/service_key.html.twig
new file mode 100644
index 0000000..051d0ba
--- /dev/null
+++ b/templates/admin/payment_method/form/service_key.html.twig
@@ -0,0 +1,5 @@
+{% set form = hookable_metadata.context.form.gatewayConfig.config.service_key %}
+
+
+ {{ form_row(form, sylius_test_form_attribute('config-service-key')) }}
+
diff --git a/tests/Application/Kernel.php b/tests/Application/Kernel.php
index a893f71..6f2cfa2 100644
--- a/tests/Application/Kernel.php
+++ b/tests/Application/Kernel.php
@@ -5,8 +5,10 @@
namespace Tests\BitBag\SyliusImojePlugin\Application;
use PSS\SymfonyMockerContainer\DependencyInjection\MockerContainer;
-use Sylius\Bundle\CoreBundle\Application\Kernel as SyliusKernel;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
+use Symfony\Component\Config\Loader\LoaderInterface;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
@@ -38,6 +40,23 @@ public function registerBundles(): iterable
}
}
+ protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void
+ {
+ foreach ($this->getConfigurationDirectories() as $confDir) {
+ $bundlesFile = $confDir . '/bundles.php';
+ if (false === is_file($bundlesFile)) {
+ continue;
+ }
+ $container->addResource(new FileResource($bundlesFile));
+ }
+
+ $container->setParameter('container.dumper.inline_class_loader', true);
+
+ foreach ($this->getConfigurationDirectories() as $confDir) {
+ $this->loadContainerConfiguration($loader, $confDir);
+ }
+ }
+
protected function configureRoutes(RoutingConfigurator $routes): void
{
foreach ($this->getConfigurationDirectories() as $confDir) {
@@ -45,6 +64,13 @@ protected function configureRoutes(RoutingConfigurator $routes): void
}
}
+ private function loadRoutesConfiguration(RoutingConfigurator $routes, string $confDir): void
+ {
+ $routes->import($confDir . '/{routes}/*' . self::CONFIG_EXTS);
+ $routes->import($confDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS);
+ $routes->import($confDir . '/{routes}' . self::CONFIG_EXTS);
+ }
+
protected function getContainerBaseClass(): string
{
if ($this->isTestEnvironment() && class_exists(MockerContainer::class)) {
@@ -59,11 +85,12 @@ private function isTestEnvironment(): bool
return 0 === strpos($this->getEnvironment(), 'test');
}
- private function loadRoutesConfiguration(RoutingConfigurator $routes, string $confDir): void
+ private function loadContainerConfiguration(LoaderInterface $loader, string $confDir): void
{
- $routes->import($confDir . '/{routes}/*' . self::CONFIG_EXTS);
- $routes->import($confDir . '/{routes}/' . $this->environment . '/**/*' . self::CONFIG_EXTS);
- $routes->import($confDir . '/{routes}' . self::CONFIG_EXTS);
+ $loader->load($confDir . '/{packages}/*' . self::CONFIG_EXTS, 'glob');
+ $loader->load($confDir . '/{packages}/' . $this->environment . '/**/*' . self::CONFIG_EXTS, 'glob');
+ $loader->load($confDir . '/{services}' . self::CONFIG_EXTS, 'glob');
+ $loader->load($confDir . '/{services}_' . $this->environment . self::CONFIG_EXTS, 'glob');
}
/**
@@ -85,13 +112,5 @@ private function registerBundlesFromFile(string $bundlesFile): iterable
private function getConfigurationDirectories(): iterable
{
yield $this->getProjectDir() . '/config';
- $syliusConfigDir = $this->getProjectDir() . '/config/sylius/' . SyliusKernel::MAJOR_VERSION . '.' . SyliusKernel::MINOR_VERSION;
- if (is_dir($syliusConfigDir)) {
- yield $syliusConfigDir;
- }
- $symfonyConfigDir = $this->getProjectDir() . '/config/symfony/' . BaseKernel::MAJOR_VERSION . '.' . BaseKernel::MINOR_VERSION;
- if (is_dir($symfonyConfigDir)) {
- yield $symfonyConfigDir;
- }
}
}
diff --git a/tests/Application/assets/admin/entrypoint.js b/tests/Application/assets/admin/entrypoint.js
new file mode 100644
index 0000000..b5c678e
--- /dev/null
+++ b/tests/Application/assets/admin/entrypoint.js
@@ -0,0 +1 @@
+import '../../../../assets/admin/entrypoint';
diff --git a/tests/Application/assets/shop/entrypoint.js b/tests/Application/assets/shop/entrypoint.js
new file mode 100644
index 0000000..61b4353
--- /dev/null
+++ b/tests/Application/assets/shop/entrypoint.js
@@ -0,0 +1 @@
+import '../../../../assets/shop/entrypoint';
diff --git a/tests/Application/config/bundles.php b/tests/Application/config/bundles.php
index 94bd806..9285a9a 100644
--- a/tests/Application/config/bundles.php
+++ b/tests/Application/config/bundles.php
@@ -1,13 +1,21 @@
['all' => true],
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
+ Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class => ['all' => true],
Sylius\Bundle\OrderBundle\SyliusOrderBundle::class => ['all' => true],
Sylius\Bundle\MoneyBundle\SyliusMoneyBundle::class => ['all' => true],
Sylius\Bundle\CurrencyBundle\SyliusCurrencyBundle::class => ['all' => true],
@@ -30,40 +38,34 @@
Sylius\Bundle\CoreBundle\SyliusCoreBundle::class => ['all' => true],
Sylius\Bundle\ResourceBundle\SyliusResourceBundle::class => ['all' => true],
Sylius\Bundle\GridBundle\SyliusGridBundle::class => ['all' => true],
- winzou\Bundle\StateMachineBundle\winzouStateMachineBundle::class => ['all' => true],
- Sonata\BlockBundle\SonataBlockBundle::class => ['all' => true],
- Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle::class => ['all' => true],
- JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
- FOS\RestBundle\FOSRestBundle::class => ['all' => true],
Knp\Bundle\GaufretteBundle\KnpGaufretteBundle::class => ['all' => true],
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
Liip\ImagineBundle\LiipImagineBundle::class => ['all' => true],
Payum\Bundle\PayumBundle\PayumBundle::class => ['all' => true],
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
+ BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true],
Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
Sylius\Bundle\FixturesBundle\SyliusFixturesBundle::class => ['all' => true],
Sylius\Bundle\PayumBundle\SyliusPayumBundle::class => ['all' => true],
Sylius\Bundle\ThemeBundle\SyliusThemeBundle::class => ['all' => true],
Sylius\Bundle\AdminBundle\SyliusAdminBundle::class => ['all' => true],
Sylius\Bundle\ShopBundle\SyliusShopBundle::class => ['all' => true],
- BitBag\SyliusImojePlugin\BitBagSyliusImojePlugin::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true, 'test_cached' => true],
FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle::class => ['test' => true, 'test_cached' => true],
Sylius\Behat\Application\SyliusTestPlugin\SyliusTestPlugin::class => ['test' => true, 'test_cached' => true],
- ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
+ ApiPlatform\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true],
- BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true],
- SyliusLabs\Polyfill\Symfony\Security\Bundle\SyliusLabsPolyfillSymfonySecurityBundle::class => ['all' => true],
- Sylius\Calendar\SyliusCalendarBundle::class => ['all' => true],
- Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
League\FlysystemBundle\FlysystemBundle::class => ['all' => true],
+ Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
+ Sylius\TwigHooks\SyliusTwigHooksBundle::class => ['all' => true],
+ Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
+ Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true],
+ Symfony\UX\Autocomplete\AutocompleteBundle::class => ['all' => true],
+ Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true],
+ Sylius\TwigExtra\Symfony\SyliusTwigExtraBundle::class => ['all' => true],
+ Symfony\UX\Icons\UXIconsBundle::class => ['all' => true],
+ BitBag\SyliusImojePlugin\BitBagSyliusImojePlugin::class => ['all' => true],
];
-
-if ( defined(SyliusCoreBundle::class.'::VERSION_ID') && SyliusCoreBundle::VERSION_ID >= '11300') {
- $bundles[Sylius\Abstraction\StateMachine\SyliusStateMachineAbstractionBundle::class] = ['all' => true];
-}
-
-return $bundles;
diff --git a/tests/Application/config/packages/_sylius.yaml b/tests/Application/config/packages/_sylius.yaml
index 18acdd4..b2ba98f 100644
--- a/tests/Application/config/packages/_sylius.yaml
+++ b/tests/Application/config/packages/_sylius.yaml
@@ -1,10 +1,8 @@
imports:
- { resource: "@SyliusCoreBundle/Resources/config/app/config.yml" }
-
+ - { resource: "@SyliusPayumBundle/Resources/config/app/config.yaml" }
- { resource: "@SyliusAdminBundle/Resources/config/app/config.yml" }
-
- { resource: "@SyliusShopBundle/Resources/config/app/config.yml" }
-
- { resource: "@SyliusApiBundle/Resources/config/app/config.yaml" }
parameters:
diff --git a/tests/Application/config/packages/api_platform.yaml b/tests/Application/config/packages/api_platform.yaml
index b428304..b0351e5 100644
--- a/tests/Application/config/packages/api_platform.yaml
+++ b/tests/Application/config/packages/api_platform.yaml
@@ -1,10 +1,9 @@
api_platform:
- mapping:
- paths:
- - '%kernel.project_dir%/../../vendor/sylius/sylius/src/Sylius/Bundle/ApiBundle/Resources/config/api_resources'
- - '%kernel.project_dir%/config/api_platform'
- - '%kernel.project_dir%/src/Entity'
- patch_formats:
- json: ['application/merge-patch+json']
- swagger:
- versions: [3]
+ mapping:
+ paths:
+ - '%kernel.project_dir%/config/api_platform'
+ - '%kernel.project_dir%/src/Entity'
+ patch_formats:
+ json: ['application/merge-patch+json']
+ swagger:
+ versions: [3]
diff --git a/tests/Application/config/packages/bitbag_sylius_imoje_plugin.yaml b/tests/Application/config/packages/bitbag_sylius_imoje_plugin.yaml
new file mode 100644
index 0000000..394d4fd
--- /dev/null
+++ b/tests/Application/config/packages/bitbag_sylius_imoje_plugin.yaml
@@ -0,0 +1,2 @@
+imports:
+ - { resource: "@BitBagSyliusImojePlugin/config/config.yaml" }
diff --git a/tests/Application/config/packages/dev/jms_serializer.yaml b/tests/Application/config/packages/dev/jms_serializer.yaml
deleted file mode 100644
index 2f32a9b..0000000
--- a/tests/Application/config/packages/dev/jms_serializer.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-jms_serializer:
- visitors:
- json_serialization:
- options:
- - JSON_PRETTY_PRINT
- - JSON_UNESCAPED_SLASHES
- - JSON_PRESERVE_ZERO_FRACTION
- json_deserialization:
- options:
- - JSON_PRETTY_PRINT
- - JSON_UNESCAPED_SLASHES
- - JSON_PRESERVE_ZERO_FRACTION
diff --git a/tests/Application/config/packages/fos_rest.yaml b/tests/Application/config/packages/fos_rest.yaml
deleted file mode 100644
index eaebb27..0000000
--- a/tests/Application/config/packages/fos_rest.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-fos_rest:
- exception: true
- view:
- formats:
- json: true
- xml: true
- empty_content: 204
- format_listener:
- rules:
- - { path: '^/api/v1/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
- - { path: '^/', stop: true }
diff --git a/tests/Application/config/packages/http_discovery.yaml b/tests/Application/config/packages/http_discovery.yaml
new file mode 100644
index 0000000..2a789e7
--- /dev/null
+++ b/tests/Application/config/packages/http_discovery.yaml
@@ -0,0 +1,10 @@
+services:
+ Psr\Http\Message\RequestFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\ResponseFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\ServerRequestFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\StreamFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\UploadedFileFactoryInterface: '@http_discovery.psr17_factory'
+ Psr\Http\Message\UriFactoryInterface: '@http_discovery.psr17_factory'
+
+ http_discovery.psr17_factory:
+ class: Http\Discovery\Psr17Factory
diff --git a/tests/Application/config/packages/jms_serializer.yaml b/tests/Application/config/packages/jms_serializer.yaml
deleted file mode 100644
index ed7bc61..0000000
--- a/tests/Application/config/packages/jms_serializer.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-jms_serializer:
- visitors:
- xml_serialization:
- format_output: '%kernel.debug%'
diff --git a/tests/Application/config/packages/prod/jms_serializer.yaml b/tests/Application/config/packages/prod/jms_serializer.yaml
deleted file mode 100644
index c288182..0000000
--- a/tests/Application/config/packages/prod/jms_serializer.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-jms_serializer:
- visitors:
- json_serialization:
- options:
- - JSON_UNESCAPED_SLASHES
- - JSON_PRESERVE_ZERO_FRACTION
- json_deserialization:
- options:
- - JSON_UNESCAPED_SLASHES
- - JSON_PRESERVE_ZERO_FRACTION
diff --git a/tests/Application/config/packages/security.yaml b/tests/Application/config/packages/security.yaml
index 4ed342f..58d3628 100644
--- a/tests/Application/config/packages/security.yaml
+++ b/tests/Application/config/packages/security.yaml
@@ -1,5 +1,4 @@
security:
- enable_authenticator_manager: true
providers:
sylius_admin_user_provider:
id: sylius.admin_user_provider.email_or_name_based
@@ -9,7 +8,7 @@ security:
id: sylius.shop_user_provider.email_or_name_based
sylius_api_shop_user_provider:
id: sylius.shop_user_provider.email_or_name_based
-
+
password_hashers:
Sylius\Component\User\Model\UserInterface: argon2i
firewalls:
@@ -18,6 +17,7 @@ security:
context: admin
pattern: "%sylius.security.admin_regex%"
provider: sylius_admin_user_provider
+ user_checker: security.user_checker.chain.admin
form_login:
provider: sylius_admin_user_provider
login_path: sylius_admin_login
@@ -38,38 +38,41 @@ security:
logout:
path: sylius_admin_logout
target: sylius_admin_login
-
- new_api_admin_user:
- pattern: "%sylius.security.new_api_admin_regex%/.*"
+
+ api_admin:
+ pattern: "%sylius.security.api_admin_regex%/.*"
provider: sylius_api_admin_user_provider
+ user_checker: security.user_checker.chain.api_admin
stateless: true
entry_point: jwt
json_login:
- check_path: "%sylius.security.new_api_admin_route%/authentication-token"
+ check_path: "%sylius.security.api_admin_route%/administrators/token"
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
jwt: true
-
- new_api_shop_user:
- pattern: "%sylius.security.new_api_shop_regex%/.*"
+
+ api_shop:
+ pattern: "%sylius.security.api_shop_regex%/.*"
provider: sylius_api_shop_user_provider
+ user_checker: security.user_checker.chain.api_shop
stateless: true
entry_point: jwt
json_login:
- check_path: "%sylius.security.new_api_shop_route%/authentication-token"
+ check_path: "%sylius.security.api_shop_route%/customers/token"
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
jwt: true
-
+
shop:
switch_user: { role: ROLE_ALLOWED_TO_SWITCH }
context: shop
pattern: "%sylius.security.shop_regex%"
provider: sylius_shop_user_provider
+ user_checker: security.user_checker.chain.shop
form_login:
success_handler: sylius.authentication.success_handler
failure_handler: sylius.authentication.failure_handler
@@ -83,6 +86,12 @@ security:
enable_csrf: true
csrf_parameter: _csrf_shop_security_token
csrf_token_id: shop_authenticate
+ json_login:
+ check_path: sylius_shop_json_login_check
+ username_path: _username
+ password_path: _password
+ success_handler: sylius.authentication.success_handler
+ failure_handler: sylius.authentication.failure_handler
remember_me:
secret: "%env(APP_SECRET)%"
name: APP_SHOP_REMEMBER_ME
@@ -92,20 +101,17 @@ security:
path: sylius_shop_logout
target: sylius_shop_homepage
invalidate_session: false
-
- dev:
- pattern: ^/(_(profiler|wdt)|css|images|js)/
- security: false
-
+
image_resolver:
pattern: ^/media/cache/resolve
security: false
-
+
+ dev:
+ pattern: ^/(_(profiler|wdt)|css|images|js)/
+ security: false
+
access_control:
- - { path: "%sylius.security.admin_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] }
- - { path: "%sylius.security.admin_regex%/_partial", role: ROLE_NO_ACCESS }
- - { path: "%sylius.security.shop_regex%/_partial", role: PUBLIC_ACCESS, ips: [127.0.0.1, ::1] }
- - { path: "%sylius.security.shop_regex%/_partial", role: ROLE_NO_ACCESS }
+ - { path: "%sylius.security.admin_regex%/forgotten-password", role: PUBLIC_ACCESS }
- { path: "%sylius.security.admin_regex%/login", role: PUBLIC_ACCESS }
- { path: "%sylius.security.shop_regex%/login", role: PUBLIC_ACCESS }
@@ -116,9 +122,9 @@ security:
- { path: "%sylius.security.admin_regex%", role: ROLE_ADMINISTRATION_ACCESS }
- { path: "%sylius.security.shop_regex%/account", role: ROLE_USER }
- - { path: "%sylius.security.new_api_admin_route%/reset-password-requests", role: PUBLIC_ACCESS }
- - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
- - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: PUBLIC_ACCESS }
- - { path: "%sylius.security.new_api_user_account_regex%/.*", role: ROLE_USER }
- - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: PUBLIC_ACCESS }
- - { path: "%sylius.security.new_api_shop_regex%/.*", role: PUBLIC_ACCESS }
+ - { path: "%sylius.security.api_admin_route%/administrators/reset-password", role: PUBLIC_ACCESS }
+ - { path: "%sylius.security.api_admin_regex%/.*", role: ROLE_API_ACCESS }
+ - { path: "%sylius.security.api_admin_route%/administrators/token", role: PUBLIC_ACCESS }
+ - { path: "%sylius.security.api_shop_account_regex%/.*", role: ROLE_USER }
+ - { path: "%sylius.security.api_shop_route%/customers/token", role: PUBLIC_ACCESS }
+ - { path: "%sylius.security.api_shop_regex%/.*", role: PUBLIC_ACCESS }
diff --git a/tests/Application/config/packages/test_cached/fos_rest.yaml b/tests/Application/config/packages/test_cached/fos_rest.yaml
deleted file mode 100644
index 2b4189d..0000000
--- a/tests/Application/config/packages/test_cached/fos_rest.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-fos_rest:
- exception:
- debug: true
diff --git a/tests/Application/config/packages/validator.yaml b/tests/Application/config/packages/validator.yaml
index 61807db..8ff7da1 100644
--- a/tests/Application/config/packages/validator.yaml
+++ b/tests/Application/config/packages/validator.yaml
@@ -1,3 +1,3 @@
framework:
validation:
- enable_annotations: true
+ enable_attributes: true
diff --git a/tests/Application/config/routes.yaml b/tests/Application/config/routes.yaml
index 7e80a7a..cb7b696 100644
--- a/tests/Application/config/routes.yaml
+++ b/tests/Application/config/routes.yaml
@@ -1,2 +1,2 @@
bitbag_sylius_imoje_plugin:
- resource: "@BitBagSyliusImojePlugin/config/routing.yml"
+ resource: "@BitBagSyliusImojePlugin/config/routes.yaml"
diff --git a/tests/Application/config/routes/sylius_admin.yaml b/tests/Application/config/routes/sylius_admin.yaml
index 1ba48d6..c76c433 100644
--- a/tests/Application/config/routes/sylius_admin.yaml
+++ b/tests/Application/config/routes/sylius_admin.yaml
@@ -1,3 +1,7 @@
sylius_admin:
resource: "@SyliusAdminBundle/Resources/config/routing.yml"
prefix: /admin
+
+live_component:
+ resource: "@LiveComponentBundle/config/routes.php"
+ prefix: /_components
diff --git a/tests/Application/config/routes/sylius_api.yaml b/tests/Application/config/routes/sylius_api.yaml
index ae01ffc..a7504e8 100644
--- a/tests/Application/config/routes/sylius_api.yaml
+++ b/tests/Application/config/routes/sylius_api.yaml
@@ -1,3 +1,3 @@
sylius_api:
resource: "@SyliusApiBundle/Resources/config/routing.yml"
- prefix: "%sylius.security.new_api_route%"
+ prefix: "%sylius.security.api_route%"
diff --git a/tests/Application/config/routes/sylius_shop.yaml b/tests/Application/config/routes/sylius_shop.yaml
index fae46cb..8e3dd42 100644
--- a/tests/Application/config/routes/sylius_shop.yaml
+++ b/tests/Application/config/routes/sylius_shop.yaml
@@ -5,10 +5,22 @@ sylius_shop:
_locale: ^[A-Za-z]{2,4}(_([A-Za-z]{4}|[0-9]{3}))?(_([A-Za-z]{2}|[0-9]{3}))?$
sylius_shop_payum:
- resource: "@SyliusShopBundle/Resources/config/routing/payum.yml"
+ resource: "@SyliusPayumBundle/Resources/config/routing/integrations/sylius_shop.yaml"
+
+sylius_payment_notify:
+ resource: "@SyliusPaymentBundle/Resources/config/routing/integrations/sylius.yaml"
sylius_shop_default_locale:
path: /
methods: [GET]
defaults:
- _controller: sylius.controller.shop.locale_switch::switchAction
+ _controller: sylius_shop.controller.locale_switch::switchAction
+
+# see https://web.dev/change-password-url/
+sylius_shop_request_password_reset_token_redirect:
+ path: /.well-known/change-password
+ methods: [GET]
+ controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
+ defaults:
+ route: sylius_shop_request_password_reset_token
+ permanent: false
diff --git a/tests/Application/config/routes/ux.yaml b/tests/Application/config/routes/ux.yaml
new file mode 100644
index 0000000..b0fed23
--- /dev/null
+++ b/tests/Application/config/routes/ux.yaml
@@ -0,0 +1,3 @@
+live_component:
+ resource: "@LiveComponentBundle/config/routes.php"
+ prefix: /_components
diff --git a/tests/Application/package.json b/tests/Application/package.json
index b428c24..4711908 100644
--- a/tests/Application/package.json
+++ b/tests/Application/package.json
@@ -3,11 +3,18 @@
"scripts": {
"build": "encore dev",
"build:prod": "encore production",
- "postinstall": "semantic-ui-css-patch",
"lint": "yarn lint:js",
"watch": "encore dev --watch"
},
+ "dependencies": {
+ "@sylius-ui/admin": "file:../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle",
+ "@sylius-ui/shop": "file:../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle",
+ "@symfony/ux-autocomplete": "file:../../vendor/symfony/ux-autocomplete/assets",
+ "@symfony/ux-live-component": "file:../../vendor/symfony/ux-live-component/assets"
+ },
"devDependencies": {
- "@sylius-ui/frontend": "^1.0"
+ "@hotwired/stimulus": "^3.2.2",
+ "@symfony/stimulus-bridge": "^3.2.2",
+ "tom-select": "^2.2.2"
}
}
diff --git a/tests/Application/webpack.config.js b/tests/Application/webpack.config.js
index 0d3d978..1a4130c 100644
--- a/tests/Application/webpack.config.js
+++ b/tests/Application/webpack.config.js
@@ -1,49 +1,48 @@
const path = require('path');
const Encore = require('@symfony/webpack-encore');
-const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/');
-const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/');
-const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/private/');
+const SyliusAdmin = require('@sylius-ui/admin');
+const SyliusShop = require('@sylius-ui/shop');
+
+// Admin config
+const adminConfig = SyliusAdmin.getWebpackConfig(path.resolve(__dirname));
// Shop config
+const shopConfig = SyliusShop.getWebpackConfig(path.resolve(__dirname));
+
+// App shop config
Encore
- .setOutputPath('public/build/shop/')
- .setPublicPath('/build/shop')
- .addEntry('shop-entry', '../../vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/private/entry.js')
+ .setOutputPath('public/build/app/shop')
+ .setPublicPath('/build/app/shop')
+ .addEntry('app-shop-entry', './assets/shop/entrypoint.js')
.disableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
- .enableSassLoader();
+ .enableSassLoader()
+;
-const shopConfig = Encore.getWebpackConfig();
+const appShopConfig = Encore.getWebpackConfig();
-shopConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
-shopConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
-shopConfig.resolve.alias['sylius/bundle'] = syliusBundles;
-shopConfig.resolve.alias['chart.js/dist/Chart.min'] = path.resolve(__dirname, 'node_modules/chart.js/dist/chart.min.js');
-shopConfig.name = 'shop';
+appShopConfig.externals = Object.assign({}, appShopConfig.externals, { window: 'window', document: 'document' });
+appShopConfig.name = 'app.shop';
Encore.reset();
-// Admin config
+// App admin config
Encore
- .setOutputPath('public/build/admin/')
- .setPublicPath('/build/admin')
- .addEntry('admin-entry', '../../vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/private/entry.js')
+ .setOutputPath('public/build/app/admin')
+ .setPublicPath('/build/app/admin')
+ .addEntry('app-admin-entry', './assets/admin/entrypoint.js')
.disableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.enableSassLoader();
-const adminConfig = Encore.getWebpackConfig();
+const appAdminConfig = Encore.getWebpackConfig();
-adminConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
-adminConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
-adminConfig.resolve.alias['sylius/bundle'] = syliusBundles;
-adminConfig.resolve.alias['chart.js/dist/Chart.min'] = path.resolve(__dirname, 'node_modules/chart.js/dist/chart.min.js');
-adminConfig.externals = Object.assign({}, adminConfig.externals, { window: 'window', document: 'document' });
-adminConfig.name = 'admin';
+appAdminConfig.externals = Object.assign({}, appAdminConfig.externals, { window: 'window', document: 'document' });
+appAdminConfig.name = 'app.admin';
-module.exports = [shopConfig, adminConfig];
+module.exports = [shopConfig, adminConfig, appShopConfig, appAdminConfig];
diff --git a/tests/Behat/Resources/suites.yml b/tests/Behat/Resources/suites.yml
index 527734a..e47c39e 100644
--- a/tests/Behat/Resources/suites.yml
+++ b/tests/Behat/Resources/suites.yml
@@ -1,3 +1,2 @@
default:
suites:
-
diff --git a/tests/Unit/CommandHandler/CapturePaymentRequestHandlerTest.php b/tests/Unit/CommandHandler/CapturePaymentRequestHandlerTest.php
new file mode 100644
index 0000000..9b41164
--- /dev/null
+++ b/tests/Unit/CommandHandler/CapturePaymentRequestHandlerTest.php
@@ -0,0 +1,126 @@
+paymentRequestProvider = $this->createMock(PaymentRequestProviderInterface::class);
+ $this->stateMachine = $this->createMock(StateMachineInterface::class);
+ $this->signatureResolver = $this->createMock(SignatureResolverInterface::class);
+ $this->afterPayUrlProvider = $this->createMock(UrlProviderInterface::class);
+
+ $this->handler = new CapturePaymentRequestHandler(
+ $this->paymentRequestProvider,
+ $this->stateMachine,
+ $this->signatureResolver,
+ $this->afterPayUrlProvider
+ );
+ }
+
+ public function testItProcessesCapturePaymentRequest(): void
+ {
+ $capturePaymentRequest = new CapturePaymentRequest('payment-request-id');
+
+ $paymentRequest = $this->createMock(PaymentRequestInterface::class);
+ $paymentMethod = $this->createMock(PaymentMethodInterface::class);
+ $gatewayConfig = $this->createMock(GatewayConfigInterface::class);
+ $payment = $this->createMock(PaymentInterface::class);
+ $order = $this->createMock(OrderInterface::class);
+ $billingAddress = $this->createMock(AddressInterface::class);
+ $customer = $this->createMock(CustomerInterface::class);
+
+ $paymentRequest->method('getMethod')->willReturn($paymentMethod);
+ $paymentRequest->method('getPayment')->willReturn($payment);
+ $payment->method('getOrder')->willReturn($order);
+
+ $paymentMethod->method('getGatewayConfig')->willReturn($gatewayConfig);
+ $gatewayConfig->method('getConfig')->willReturn([
+ 'environment' => ImojeEnvironment::SANDBOX_ENVIRONMENT,
+ 'service_key' => 'test_key',
+ 'service_id' => 'test_service',
+ 'merchant_id' => 'test_merchant',
+ ]);
+
+ $order->method('getBillingAddress')->willReturn($billingAddress);
+ $order->method('getCustomer')->willReturn($customer);
+ $order->method('getTotal')->willReturn(1000);
+ $order->method('getCurrencyCode')->willReturn('USD');
+ $order->method('getNumber')->willReturn('ORDER123');
+
+ $this->afterPayUrlProvider->method('getUrl')
+ ->with($paymentRequest, UrlGeneratorInterface::ABSOLUTE_URL)
+ ->willReturn('https://return.url');
+
+ $this->signatureResolver->method('createSignature')
+ ->with([
+ 'serviceId' => 'test_service',
+ 'merchantId' => 'test_merchant',
+ 'amount' => 1000,
+ 'currency' => 'USD',
+ 'orderId' => 'ORDER123',
+ 'customerFirstName' => null,
+ 'customerLastName' => null,
+ 'urlReturn' => 'https://return.url',
+ 'customerEmail' => null,
+ ], 'test_key')
+ ->willReturn('test_signature');
+
+ $paymentRequest->expects(self::once())
+ ->method('setResponseData')
+ ->with([
+ 'url' => ImojeEnvironment::SANDBOX_URL->value,
+ 'orderData' => [
+ 'serviceId' => 'test_service',
+ 'merchantId' => 'test_merchant',
+ 'amount' => 1000,
+ 'currency' => 'USD',
+ 'orderId' => 'ORDER123',
+ 'customerFirstName' => null,
+ 'customerLastName' => null,
+ 'urlReturn' => 'https://return.url',
+ 'customerEmail' => null,
+ 'signature' => 'test_signature',
+ ],
+ ]);
+
+ $this->stateMachine->expects(self::once())
+ ->method('apply')
+ ->with($paymentRequest, PaymentRequestTransitions::GRAPH, PaymentRequestTransitions::TRANSITION_PROCESS);
+
+ $this->paymentRequestProvider->method('provide')
+ ->with($capturePaymentRequest)
+ ->willReturn($paymentRequest);
+
+ ($this->handler)($capturePaymentRequest);
+
+ $this->addToAssertionCount(1);
+ }
+}
diff --git a/tests/Unit/Processor/PaymentTransitionProcessorTest.php b/tests/Unit/Processor/PaymentTransitionProcessorTest.php
new file mode 100644
index 0000000..9a2f5c5
--- /dev/null
+++ b/tests/Unit/Processor/PaymentTransitionProcessorTest.php
@@ -0,0 +1,116 @@
+stateMachine = $this->createMock(StateMachineInterface::class);
+ $this->processor = new PaymentTransitionProcessor($this->stateMachine);
+ }
+
+ /**
+ * @dataProvider paymentStatusProvider
+ */
+ public function testItProcessesPaymentWithDifferentStatuses(
+ string $status,
+ ?string $expectedTransition
+ ): void {
+ $paymentRequest = $this->createMock(PaymentRequestInterface::class);
+ $payment = $this->createMock(PaymentInterface::class);
+
+ $payment->method('getDetails')->willReturn(['status' => $status]);
+ $paymentRequest->method('getPayment')->willReturn($payment);
+
+ if ($expectedTransition) {
+ $this->stateMachine
+ ->expects(self::once())
+ ->method('can')
+ ->with($payment, PaymentTransitions::GRAPH, $expectedTransition)
+ ->willReturn(true);
+
+ $this->stateMachine
+ ->expects(self::once())
+ ->method('apply')
+ ->with($payment, PaymentTransitions::GRAPH, $expectedTransition);
+ } else {
+ $this->stateMachine
+ ->expects(self::never())
+ ->method('apply');
+ }
+
+ $this->processor->process($paymentRequest);
+
+ $this->addToAssertionCount(1);
+ }
+
+ public function testItDoesNotApplyTransitionIfCannotTransition(): void
+ {
+ $paymentRequest = $this->createMock(PaymentRequestInterface::class);
+ $payment = $this->createMock(PaymentInterface::class);
+
+ $payment->method('getDetails')->willReturn(['status' => PaymentTransitionProcessorInterface::STATE_PENDING]);
+ $paymentRequest->method('getPayment')->willReturn($payment);
+
+ $this->stateMachine
+ ->expects(self::once())
+ ->method('can')
+ ->with($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_PROCESS)
+ ->willReturn(false);
+
+ $this->stateMachine
+ ->expects(self::never())
+ ->method('apply');
+
+ $this->processor->process($paymentRequest);
+
+ $this->addToAssertionCount(1);
+ }
+
+ public static function paymentStatusProvider(): array
+ {
+ return [
+ 'Pending status' => [
+ PaymentTransitionProcessorInterface::STATE_PENDING,
+ PaymentTransitions::TRANSITION_PROCESS,
+ ],
+ 'Settled status' => [
+ PaymentTransitionProcessorInterface::STATE_SETTLED,
+ PaymentTransitions::TRANSITION_COMPLETE,
+ ],
+ 'Cancelled status' => [
+ PaymentTransitionProcessorInterface::STATE_CANCELLED,
+ PaymentTransitions::TRANSITION_CANCEL,
+ ],
+ 'Rejected status' => [
+ PaymentTransitionProcessorInterface::STATE_REJECTED,
+ PaymentTransitions::TRANSITION_FAIL,
+ ],
+ 'Unknown status (no transition)' => [
+ 'unknown_status',
+ null,
+ ],
+ ];
+ }
+}
diff --git a/tests/Unit/Resolver/SignatureResolverTest.php b/tests/Unit/Resolver/SignatureResolverTest.php
new file mode 100644
index 0000000..c76eef5
--- /dev/null
+++ b/tests/Unit/Resolver/SignatureResolverTest.php
@@ -0,0 +1,110 @@
+signatureResolver = new SignatureResolver();
+ }
+
+ public function testItIsInitializable(): void
+ {
+ $this->assertInstanceOf(SignatureResolver::class, $this->signatureResolver);
+ }
+
+ public function testItShouldSortFieldsAndBuildDataString(): void
+ {
+ $fields = [
+ 'field1' => 'value1',
+ 'field2' => 'value2',
+ ];
+ $serviceKey = 'adasvcx3412';
+ $expectedDataString = 'field1=value1&field2=value2';
+ $expectedHash = hash(ImojeEnvironment::HASHING_ALGORITHM->value, $expectedDataString . $serviceKey) . ';' . ImojeEnvironment::HASHING_ALGORITHM->value;
+
+ $this->assertSame($expectedHash, $this->signatureResolver->createSignature($fields, $serviceKey));
+ }
+
+ public function testItShouldReturnHashWithServiceKeyOnlyWhenFieldsAreEmpty(): void
+ {
+ $fields = [];
+ $serviceKey = 'adasvcx3412';
+ $expectedHash = hash(ImojeEnvironment::HASHING_ALGORITHM->value, $serviceKey) . ';' . ImojeEnvironment::HASHING_ALGORITHM->value;
+
+ $this->assertSame($expectedHash, $this->signatureResolver->createSignature($fields, $serviceKey));
+ }
+
+ public function testItShouldReturnHashWithoutServiceKeyWhenServiceKeyIsEmpty(): void
+ {
+ $fields = [
+ 'field1' => 'value1',
+ 'field2' => 'value2',
+ ];
+ $serviceKey = '';
+ $expectedDataString = 'field1=value1&field2=value2';
+ $expectedHash = hash(ImojeEnvironment::HASHING_ALGORITHM->value, $expectedDataString) . ';' . ImojeEnvironment::HASHING_ALGORITHM->value;
+
+ $this->assertSame($expectedHash, $this->signatureResolver->createSignature($fields, $serviceKey));
+ }
+
+ public function testItShouldReturnTrueIfSignaturesMatch(): void
+ {
+ $serviceKey = 'adasvcx3412';
+ $body = 'test.jpg';
+ $exampleHash = hash('sha256', sprintf('test.jpg%s', $serviceKey));
+ $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
+
+ $request = $this->createMock(Request::class);
+ $request->method('getContent')->willReturn($body);
+ $request->headers = new HeaderBag(['X-Imoje-Signature' => $headerSignature]);
+
+ $this->assertTrue($this->signatureResolver->verifySignature($request, $serviceKey));
+ }
+
+ public function testItShouldReturnFalseIfSignaturesDoNotMatch(): void
+ {
+ $serviceKey = 'adasvcx3412';
+ $body = 'test2.jpg';
+ $exampleHash = hash('sha256', sprintf('test.jpg%s', $serviceKey));
+ $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
+
+ $request = $this->createMock(Request::class);
+ $request->method('getContent')->willReturn($body);
+ $request->headers = new HeaderBag(['X-Imoje-Signature' => $headerSignature]);
+
+ $this->assertFalse($this->signatureResolver->verifySignature($request, $serviceKey));
+ }
+
+ public function testItShouldReturnFalseIfContentIsEmpty(): void
+ {
+ $serviceKey = '';
+ $body = '';
+ $exampleHash = '';
+ $headerSignature = sprintf('alg=sha256;signature=%s', $exampleHash);
+
+ $request = $this->createMock(Request::class);
+ $request->method('getContent')->willReturn($body);
+ $request->headers = new HeaderBag(['X-Imoje-Signature' => $headerSignature]);
+
+ $this->assertFalse($this->signatureResolver->verifySignature($request, $serviceKey));
+ }
+}
diff --git a/translations/messages.en.yml b/translations/messages.en.yml
index 21ba3cd..eed3d24 100644
--- a/translations/messages.en.yml
+++ b/translations/messages.en.yml
@@ -8,4 +8,4 @@ bitbag:
service_key: Service key
authorization_token: Authorization token
environment: Envrionment
- gateway_label: Imoje gateway
+ paywall: Imoje (Paywall)
diff --git a/translations/validators.en.yaml b/translations/validators.en.yaml
new file mode 100644
index 0000000..6659cdf
--- /dev/null
+++ b/translations/validators.en.yaml
@@ -0,0 +1,11 @@
+bitbag:
+ imoje_plugin:
+ configuration:
+ merchant_id:
+ not_blank: Please enter a merchant ID.
+ service_id:
+ not_blank: Please enter a service ID.
+ service_key:
+ not_blank: Please enter a service key.
+ authorization_token:
+ not_blank: Please enter an authorization token.