diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 53edcabf3..5d87b0920 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,7 @@ jobs:
with:
php-version: ${{ matrix.php-versions }}
coverage: none
- tools: composer:v1
+ tools: composer:v2
- name: Validate composer.json and composer.lock
run: composer validate
@@ -28,14 +28,14 @@ jobs:
run: composer update --prefer-dist --no-progress
- name: dump autoload
- run: composer dump-autoload
+ run: composer dump-autoload --dev --optimize --strict-psr
- name: check syntax
run: find src -name '*.php' | xargs -n 1 -P4 php -l
- name: Run PHPUnit
run: ./vendor/bin/phpunit
-
+
- name: Run Psalm
run: ./vendor/bin/psalm --show-info=false --threads=2
diff --git a/.idea/WooCommerce.iml b/.idea/WooCommerce.iml
index 6828e16ed..692525fb1 100644
--- a/.idea/WooCommerce.iml
+++ b/.idea/WooCommerce.iml
@@ -72,6 +72,7 @@
+
diff --git a/.idea/php.xml b/.idea/php.xml
index f41096f56..813e16952 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -132,6 +132,10 @@
+
+
+
+
@@ -241,7 +245,7 @@
-
+
diff --git a/composer.json b/composer.json
index 4100eb24d..89100fc0f 100644
--- a/composer.json
+++ b/composer.json
@@ -23,7 +23,8 @@
"inpsyde/modularity": "^1.7.4",
"psr/container": "1.1.0",
"psr/log":"^1.1.4",
- "sniccowp/php-scoper-wordpress-excludes": "^6.6"
+ "sniccowp/php-scoper-wordpress-excludes": "^6.6",
+ "dhii/services": "^0.1.0"
},
"require-dev": {
"phpunit/phpunit": "^8",
@@ -40,7 +41,8 @@
"autoload": {
"psr-4": {
"Mollie\\WooCommerce\\": "src/",
- "Inpsyde\\EnvironmentChecker\\": "pluginEnvironmentChecker"
+ "Inpsyde\\EnvironmentChecker\\": "pluginEnvironmentChecker",
+ "Inpsyde\\PaymentGateway\\": "lib/payment-gateway/src/"
}
},
"autoload-dev": {
diff --git a/composer.lock b/composer.lock
index 2243f5e96..ecefdabfb 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "afd1fef3a31e6c8742cf9df94a0ca170",
+ "content-hash": "4e52aea3a7eaecc473990bcc5f42517a",
"packages": [
{
"name": "composer/ca-bundle",
- "version": "1.5.2",
+ "version": "1.5.4",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
- "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137"
+ "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/48a792895a2b7a6ee65dd5442c299d7b835b6137",
- "reference": "48a792895a2b7a6ee65dd5442c299d7b835b6137",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/bc0593537a463e55cadf45fd938d23b75095b7e1",
+ "reference": "bc0593537a463e55cadf45fd938d23b75095b7e1",
"shasum": ""
},
"require": {
@@ -64,7 +64,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
- "source": "https://github.com/composer/ca-bundle/tree/1.5.2"
+ "source": "https://github.com/composer/ca-bundle/tree/1.5.4"
},
"funding": [
{
@@ -80,20 +80,67 @@
"type": "tidelift"
}
],
- "time": "2024-09-25T07:49:53+00:00"
+ "time": "2024-11-27T15:35:25+00:00"
+ },
+ {
+ "name": "dhii/services",
+ "version": "v0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Dhii/services.git",
+ "reference": "09cad8199a59d2003ad19126213075aefecaf17b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Dhii/services/zipball/09cad8199a59d2003ad19126213075aefecaf17b",
+ "reference": "09cad8199a59d2003ad19126213075aefecaf17b",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 | ^8.0",
+ "psr/container": "^1.0"
+ },
+ "require-dev": {
+ "codeclimate/php-test-reporter": "<=0.3.2",
+ "phpunit/phpunit": "^7.0 | ^8.0 | ^9.0",
+ "slevomat/coding-standard": "^6.0",
+ "vimeo/psalm": "^4.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Dhii\\Services\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Dhii Team",
+ "email": "development@dhii.co"
+ }
+ ],
+ "description": "A collection of useful DI service implementations.",
+ "support": {
+ "issues": "https://github.com/Dhii/services/issues",
+ "source": "https://github.com/Dhii/services/tree/v0.1.0"
+ },
+ "time": "2022-01-06T14:57:20+00:00"
},
{
"name": "inpsyde/modularity",
- "version": "1.10.0",
+ "version": "1.11.0",
"source": {
"type": "git",
"url": "https://github.com/inpsyde/modularity.git",
- "reference": "2119d0e32706741a3c6dc0a85d908ec19ebf142e"
+ "reference": "c79bb3682f55e1a2ece67f36e70d04fa2ab8c65d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/inpsyde/modularity/zipball/2119d0e32706741a3c6dc0a85d908ec19ebf142e",
- "reference": "2119d0e32706741a3c6dc0a85d908ec19ebf142e",
+ "url": "https://api.github.com/repos/inpsyde/modularity/zipball/c79bb3682f55e1a2ece67f36e70d04fa2ab8c65d",
+ "reference": "c79bb3682f55e1a2ece67f36e70d04fa2ab8c65d",
"shasum": ""
},
"require": {
@@ -127,31 +174,31 @@
],
"authors": [
{
- "name": "Inpsyde GmbH",
- "email": "hello@inpsyde.com",
- "homepage": "https://inpsyde.com/",
+ "name": "Syde GmbH",
+ "email": "hello@syde.com",
+ "homepage": "https://syde.com/",
"role": "Company"
}
],
"description": "Modular PSR-11 implementation for WordPress plugins, themes or libraries.",
"support": {
"issues": "https://github.com/inpsyde/modularity/issues",
- "source": "https://github.com/inpsyde/modularity/tree/1.10.0"
+ "source": "https://github.com/inpsyde/modularity/tree/1.11.0"
},
- "time": "2024-09-03T10:42:50+00:00"
+ "time": "2024-11-28T09:34:00+00:00"
},
{
"name": "mollie/mollie-api-php",
- "version": "v2.73.0",
+ "version": "v2.76.0",
"source": {
"type": "git",
"url": "https://github.com/mollie/mollie-api-php.git",
- "reference": "0a26175492d4c55bb461e44fe3e63546539b81c1"
+ "reference": "b6e9848e4893d1d306fba54da3ac6f4a31a40368"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/0a26175492d4c55bb461e44fe3e63546539b81c1",
- "reference": "0a26175492d4c55bb461e44fe3e63546539b81c1",
+ "url": "https://api.github.com/repos/mollie/mollie-api-php/zipball/b6e9848e4893d1d306fba54da3ac6f4a31a40368",
+ "reference": "b6e9848e4893d1d306fba54da3ac6f4a31a40368",
"shasum": ""
},
"require": {
@@ -228,9 +275,9 @@
],
"support": {
"issues": "https://github.com/mollie/mollie-api-php/issues",
- "source": "https://github.com/mollie/mollie-api-php/tree/v2.73.0"
+ "source": "https://github.com/mollie/mollie-api-php/tree/v2.76.0"
},
- "time": "2024-09-30T13:16:57+00:00"
+ "time": "2024-12-18T12:26:03+00:00"
},
{
"name": "psr/container",
@@ -337,22 +384,22 @@
},
{
"name": "sniccowp/php-scoper-wordpress-excludes",
- "version": "6.6.2",
+ "version": "6.7.1",
"source": {
"type": "git",
"url": "https://github.com/snicco/php-scoper-wordpress-excludes.git",
- "reference": "b87d7455bdf05c25f9a688fc3862bb3f2b7c8b15"
+ "reference": "d8e6b5fdc9e42300a8ab18b44b775836a7b52363"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/snicco/php-scoper-wordpress-excludes/zipball/b87d7455bdf05c25f9a688fc3862bb3f2b7c8b15",
- "reference": "b87d7455bdf05c25f9a688fc3862bb3f2b7c8b15",
+ "url": "https://api.github.com/repos/snicco/php-scoper-wordpress-excludes/zipball/d8e6b5fdc9e42300a8ab18b44b775836a7b52363",
+ "reference": "d8e6b5fdc9e42300a8ab18b44b775836a7b52363",
"shasum": ""
},
"require-dev": {
"php": "^7.4",
"php-stubs/wordpress-globals": "0.2.0",
- "php-stubs/wordpress-stubs": "6.6.2",
+ "php-stubs/wordpress-stubs": "6.7.1",
"sniccowp/php-scoper-excludes": "dev-master"
},
"type": "library",
@@ -378,9 +425,9 @@
],
"support": {
"issues": "https://github.com/snicco/php-scoper-wordpress-excludes/issues",
- "source": "https://github.com/snicco/php-scoper-wordpress-excludes/tree/6.6.2"
+ "source": "https://github.com/snicco/php-scoper-wordpress-excludes/tree/6.7.1"
},
- "time": "2024-10-01T00:32:14+00:00"
+ "time": "2024-11-25T00:31:50+00:00"
}
],
"packages-dev": [
@@ -546,16 +593,16 @@
},
{
"name": "antecedent/patchwork",
- "version": "2.2.0",
+ "version": "2.2.1",
"source": {
"type": "git",
"url": "https://github.com/antecedent/patchwork.git",
- "reference": "b07d4fb37c3c723c8755122160c089e077d5de65"
+ "reference": "1bf183a3e1bd094f231a2128b9ecc5363c269245"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/antecedent/patchwork/zipball/b07d4fb37c3c723c8755122160c089e077d5de65",
- "reference": "b07d4fb37c3c723c8755122160c089e077d5de65",
+ "url": "https://api.github.com/repos/antecedent/patchwork/zipball/1bf183a3e1bd094f231a2128b9ecc5363c269245",
+ "reference": "1bf183a3e1bd094f231a2128b9ecc5363c269245",
"shasum": ""
},
"require": {
@@ -588,9 +635,9 @@
],
"support": {
"issues": "https://github.com/antecedent/patchwork/issues",
- "source": "https://github.com/antecedent/patchwork/tree/2.2.0"
+ "source": "https://github.com/antecedent/patchwork/tree/2.2.1"
},
- "time": "2024-09-27T16:59:55+00:00"
+ "time": "2024-12-11T10:19:54+00:00"
},
{
"name": "automattic/phpcs-neutron-standard",
@@ -693,16 +740,16 @@
},
{
"name": "brain/monkey",
- "version": "2.6.1",
+ "version": "2.6.2",
"source": {
"type": "git",
"url": "https://github.com/Brain-WP/BrainMonkey.git",
- "reference": "a31c84515bb0d49be9310f52ef1733980ea8ffbb"
+ "reference": "d95a9d895352c30f47604ad1b825ab8fa9d1a373"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/a31c84515bb0d49be9310f52ef1733980ea8ffbb",
- "reference": "a31c84515bb0d49be9310f52ef1733980ea8ffbb",
+ "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/d95a9d895352c30f47604ad1b825ab8fa9d1a373",
+ "reference": "d95a9d895352c30f47604ad1b825ab8fa9d1a373",
"shasum": ""
},
"require": {
@@ -718,8 +765,8 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-version/1": "1.x-dev",
- "dev-master": "2.0.x-dev"
+ "dev-master": "2.x-dev",
+ "dev-version/1": "1.x-dev"
}
},
"autoload": {
@@ -759,7 +806,7 @@
"issues": "https://github.com/Brain-WP/BrainMonkey/issues",
"source": "https://github.com/Brain-WP/BrainMonkey"
},
- "time": "2021-11-11T15:53:55+00:00"
+ "time": "2024-08-29T20:15:04+00:00"
},
{
"name": "composer/package-versions-deprecated",
@@ -836,16 +883,16 @@
},
{
"name": "composer/pcre",
- "version": "3.3.1",
+ "version": "3.3.2",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
- "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4"
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/pcre/zipball/63aaeac21d7e775ff9bc9d45021e1745c97521c4",
- "reference": "63aaeac21d7e775ff9bc9d45021e1745c97521c4",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
"shasum": ""
},
"require": {
@@ -855,19 +902,19 @@
"phpstan/phpstan": "<1.11.10"
},
"require-dev": {
- "phpstan/phpstan": "^1.11.10",
- "phpstan/phpstan-strict-rules": "^1.1",
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
"phpunit/phpunit": "^8 || ^9"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "3.x-dev"
- },
"phpstan": {
"includes": [
"extension.neon"
]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
}
},
"autoload": {
@@ -895,7 +942,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
- "source": "https://github.com/composer/pcre/tree/3.3.1"
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
},
"funding": [
{
@@ -911,7 +958,7 @@
"type": "tidelift"
}
],
- "time": "2024-08-27T18:44:43+00:00"
+ "time": "2024-11-12T16:29:46+00:00"
},
{
"name": "composer/semver",
@@ -1174,29 +1221,27 @@
},
{
"name": "doctrine/deprecations",
- "version": "1.1.3",
+ "version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
- "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
+ "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
- "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
+ "url": "https://api.github.com/repos/doctrine/deprecations/zipball/31610dbb31faa98e6b5447b62340826f54fbc4e9",
+ "reference": "31610dbb31faa98e6b5447b62340826f54fbc4e9",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"require-dev": {
- "doctrine/coding-standard": "^9",
- "phpstan/phpstan": "1.4.10 || 1.10.15",
- "phpstan/phpstan-phpunit": "^1.0",
+ "doctrine/coding-standard": "^9 || ^12",
+ "phpstan/phpstan": "1.4.10 || 2.0.3",
+ "phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "psalm/plugin-phpunit": "0.18.4",
- "psr/log": "^1 || ^2 || ^3",
- "vimeo/psalm": "4.30.0 || 5.12.0"
+ "psr/log": "^1 || ^2 || ^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
@@ -1204,7 +1249,7 @@
"type": "library",
"autoload": {
"psr-4": {
- "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
+ "Doctrine\\Deprecations\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -1215,9 +1260,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
- "source": "https://github.com/doctrine/deprecations/tree/1.1.3"
+ "source": "https://github.com/doctrine/deprecations/tree/1.1.4"
},
- "time": "2024-01-30T19:34:25+00:00"
+ "time": "2024-12-07T21:18:45+00:00"
},
{
"name": "doctrine/instantiator",
@@ -1527,10 +1572,10 @@
"extra": {
"class": "Inpsyde\\AssetsCompiler\\Composer\\Plugin",
"branch-alias": {
- "dev-master": "2.x-dev",
"dev-v1.x": "1.x-dev",
"dev-v2.x": "2.x-dev",
- "dev-v3.x": "3.x-dev"
+ "dev-v3.x": "3.x-dev",
+ "dev-master": "2.x-dev"
}
},
"autoload": {
@@ -1761,16 +1806,16 @@
},
{
"name": "myclabs/deep-copy",
- "version": "1.12.0",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": ""
},
"require": {
@@ -1809,7 +1854,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
},
"funding": [
{
@@ -1817,7 +1862,7 @@
"type": "tidelift"
}
],
- "time": "2024-06-12T14:39:25+00:00"
+ "time": "2024-11-08T17:47:46+00:00"
},
{
"name": "netresearch/jsonmapper",
@@ -2305,16 +2350,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "5.4.1",
+ "version": "5.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c"
+ "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
- "reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
+ "reference": "e5e784149a09bd69d9a5e3b01c5cbd2e2bd653d8",
"shasum": ""
},
"require": {
@@ -2323,17 +2368,17 @@
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.2",
"phpdocumentor/type-resolver": "^1.7",
- "phpstan/phpdoc-parser": "^1.7",
+ "phpstan/phpdoc-parser": "^1.7|^2.0",
"webmozart/assert": "^1.9.1"
},
"require-dev": {
- "mockery/mockery": "~1.3.5",
+ "mockery/mockery": "~1.3.5 || ~1.6.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpunit/phpunit": "^9.5",
- "vimeo/psalm": "^5.13"
+ "psalm/phar": "^5.26"
},
"type": "library",
"extra": {
@@ -2363,29 +2408,29 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1"
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.1"
},
- "time": "2024-05-21T05:55:05+00:00"
+ "time": "2024-12-07T09:39:29+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.8.2",
+ "version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "153ae662783729388a584b4361f2545e4d841e3c"
+ "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/153ae662783729388a584b4361f2545e4d841e3c",
- "reference": "153ae662783729388a584b4361f2545e4d841e3c",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.3 || ^8.0",
"phpdocumentor/reflection-common": "^2.0",
- "phpstan/phpdoc-parser": "^1.13"
+ "phpstan/phpdoc-parser": "^1.18|^2.0"
},
"require-dev": {
"ext-tokenizer": "*",
@@ -2421,36 +2466,36 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.8.2"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
},
- "time": "2024-02-23T11:10:43+00:00"
+ "time": "2024-11-09T15:12:26+00:00"
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.33.0",
+ "version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140"
+ "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140",
- "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/c00d78fb6b29658347f9d37ebe104bffadf36299",
+ "reference": "c00d78fb6b29658347f9d37ebe104bffadf36299",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0"
+ "php": "^7.4 || ^8.0"
},
"require-dev": {
"doctrine/annotations": "^2.0",
- "nikic/php-parser": "^4.15",
+ "nikic/php-parser": "^5.3.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^1.5",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpstan/phpstan-strict-rules": "^1.0",
- "phpunit/phpunit": "^9.5",
+ "phpstan/phpstan": "^2.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpstan/phpstan-strict-rules": "^2.0",
+ "phpunit/phpunit": "^9.6",
"symfony/process": "^5.2"
},
"type": "library",
@@ -2468,9 +2513,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/2.0.0"
},
- "time": "2024-10-13T11:25:22+00:00"
+ "time": "2024-10-13T11:29:49+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -2771,16 +2816,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "8.5.40",
+ "version": "8.5.41",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "48ed828b72c35b38cdddcd9059339734cb06b3a7"
+ "reference": "d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/48ed828b72c35b38cdddcd9059339734cb06b3a7",
- "reference": "48ed828b72c35b38cdddcd9059339734cb06b3a7",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa",
+ "reference": "d843cb5bcf0bf9ae3484016444fe0c5b6ec7e4fa",
"shasum": ""
},
"require": {
@@ -2791,7 +2836,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.12.0",
+ "myclabs/deep-copy": "^1.12.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=7.2",
@@ -2849,7 +2894,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.40"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.41"
},
"funding": [
{
@@ -2865,7 +2910,7 @@
"type": "tidelift"
}
],
- "time": "2024-09-19T10:47:04+00:00"
+ "time": "2024-12-05T13:44:26+00:00"
},
{
"name": "ptrofimov/xpmock",
@@ -3634,16 +3679,16 @@
},
{
"name": "sirbrillig/phpcs-variable-analysis",
- "version": "v2.11.19",
+ "version": "v2.11.22",
"source": {
"type": "git",
"url": "https://github.com/sirbrillig/phpcs-variable-analysis.git",
- "reference": "bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1"
+ "reference": "ffb6f16c6033ec61ed84446b479a31d6529f0eb7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1",
- "reference": "bc8d7e30e2005bce5c59018b7cdb08e9fb45c0d1",
+ "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/ffb6f16c6033ec61ed84446b479a31d6529f0eb7",
+ "reference": "ffb6f16c6033ec61ed84446b479a31d6529f0eb7",
"shasum": ""
},
"require": {
@@ -3654,9 +3699,8 @@
"dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0",
"phpcsstandards/phpcsdevcs": "^1.1",
"phpstan/phpstan": "^1.7",
- "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0",
- "sirbrillig/phpcs-import-detection": "^1.1",
- "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta"
+ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0 || ^10.5.32 || ^11.3.3",
+ "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0"
},
"type": "phpcodesniffer-standard",
"autoload": {
@@ -3688,7 +3732,7 @@
"source": "https://github.com/sirbrillig/phpcs-variable-analysis",
"wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki"
},
- "time": "2024-06-26T20:08:34+00:00"
+ "time": "2025-01-06T17:54:24+00:00"
},
{
"name": "squizlabs/php_codesniffer",
@@ -3762,16 +3806,16 @@
},
{
"name": "symfony/console",
- "version": "v5.4.44",
+ "version": "v5.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "5b5a0aa66e3296e303e22490f90f521551835a83"
+ "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/5b5a0aa66e3296e303e22490f90f521551835a83",
- "reference": "5b5a0aa66e3296e303e22490f90f521551835a83",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed",
+ "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed",
"shasum": ""
},
"require": {
@@ -3841,7 +3885,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v5.4.44"
+ "source": "https://github.com/symfony/console/tree/v5.4.47"
},
"funding": [
{
@@ -3857,20 +3901,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-20T07:56:40+00:00"
+ "time": "2024-11-06T11:30:55+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v2.5.3",
+ "version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d"
+ "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918",
+ "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918",
"shasum": ""
},
"require": {
@@ -3878,12 +3922,12 @@
},
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
"dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -3908,7 +3952,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4"
},
"funding": [
{
@@ -3924,7 +3968,7 @@
"type": "tidelift"
}
],
- "time": "2023-01-24T14:02:46+00:00"
+ "time": "2024-09-25T14:11:13+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -3952,8 +3996,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4028,8 +4072,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4106,8 +4150,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4190,8 +4234,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4264,8 +4308,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4340,8 +4384,8 @@
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
@@ -4402,16 +4446,16 @@
},
{
"name": "symfony/service-contracts",
- "version": "v2.5.3",
+ "version": "v2.5.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3"
+ "reference": "f37b419f7aea2e9abf10abd261832cace12e3300"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3",
- "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300",
+ "reference": "f37b419f7aea2e9abf10abd261832cace12e3300",
"shasum": ""
},
"require": {
@@ -4427,12 +4471,12 @@
},
"type": "library",
"extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
"branch-alias": {
"dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -4465,7 +4509,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v2.5.3"
+ "source": "https://github.com/symfony/service-contracts/tree/v2.5.4"
},
"funding": [
{
@@ -4481,20 +4525,20 @@
"type": "tidelift"
}
],
- "time": "2023-04-21T15:04:16+00:00"
+ "time": "2024-09-25T14:11:13+00:00"
},
{
"name": "symfony/string",
- "version": "v5.4.44",
+ "version": "v5.4.47",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "832caa16b6d9aac6bf11747315225f5aba384c24"
+ "reference": "136ca7d72f72b599f2631aca474a4f8e26719799"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/832caa16b6d9aac6bf11747315225f5aba384c24",
- "reference": "832caa16b6d9aac6bf11747315225f5aba384c24",
+ "url": "https://api.github.com/repos/symfony/string/zipball/136ca7d72f72b599f2631aca474a4f8e26719799",
+ "reference": "136ca7d72f72b599f2631aca474a4f8e26719799",
"shasum": ""
},
"require": {
@@ -4551,7 +4595,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.4.44"
+ "source": "https://github.com/symfony/string/tree/v5.4.47"
},
"funding": [
{
@@ -4567,7 +4611,7 @@
"type": "tidelift"
}
],
- "time": "2024-09-20T07:56:40+00:00"
+ "time": "2024-11-10T20:33:58+00:00"
},
{
"name": "theseer/tokenizer",
@@ -4691,10 +4735,10 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.x-dev",
- "dev-3.x": "3.x-dev",
+ "dev-1.x": "1.x-dev",
"dev-2.x": "2.x-dev",
- "dev-1.x": "1.x-dev"
+ "dev-3.x": "3.x-dev",
+ "dev-master": "4.x-dev"
}
},
"autoload": {
@@ -4901,6 +4945,6 @@
"ext-intl": "*",
"ext-json": "*"
},
- "platform-dev": [],
+ "platform-dev": {},
"plugin-api-version": "2.6.0"
}
diff --git a/inc/modules.php b/inc/modules.php
new file mode 100644
index 000000000..0924257c0
--- /dev/null
+++ b/inc/modules.php
@@ -0,0 +1,41 @@
+
+ */
+ static function (): iterable {
+ return [
+ new ActivationModule(),
+ new NoticeModule(),
+ new SharedModule(),
+ new PaymentGatewayModule(),
+ new SDKModule(),
+ new SettingsModule(),
+ new LogModule('mollie-payments-for-woocommerce-'),
+ new AssetsModule(),
+ new GatewayModule(),
+ new VoucherModule(),
+ new PaymentModule(),
+ new SubscriptionModule(),
+ new MerchantCaptureModule(),
+ new UninstallModule(),
+ ];
+ };
diff --git a/inc/settings/mollie_applepay_settings.php b/inc/settings/mollie_applepay_settings.php
deleted file mode 100644
index e69de29bb..000000000
diff --git a/inc/utils.php b/inc/utils.php
index 2acee663a..b5a544b3e 100644
--- a/inc/utils.php
+++ b/inc/utils.php
@@ -165,7 +165,10 @@ function mollieWooCommerceIsVoucherEnabled()
*/
function mollieWooCommerceIsMollieGateway($gateway)
{
- if (strpos($gateway, 'mollie_wc_gateway_') !== false) {
+ if (
+ (is_string($gateway) && strpos($gateway, 'mollie_wc_gateway_') !== false)
+ || (is_object($gateway) && strpos($gateway->id, 'mollie_wc_gateway_') !== false)
+ ) {
return true;
}
return false;
diff --git a/lib/payment-gateway/.distignore b/lib/payment-gateway/.distignore
new file mode 100644
index 000000000..185a70f64
--- /dev/null
+++ b/lib/payment-gateway/.distignore
@@ -0,0 +1,8 @@
+.distignore
+.ddev
+.git*
+tests/
+vendor/**/test*
+*.lock
+package-lock.json
+*.xml.*
diff --git a/lib/payment-gateway/CHANGELOG.md b/lib/payment-gateway/CHANGELOG.md
new file mode 100644
index 000000000..f32ab37a9
--- /dev/null
+++ b/lib/payment-gateway/CHANGELOG.md
@@ -0,0 +1,97 @@
+# [1.6.0](https://github.com/inpsyde/payment-gateway/compare/1.5.2...1.6.0) (2024-11-19)
+
+
+### Features
+
+* Filterable checkout components ([#34](https://github.com/inpsyde/payment-gateway/issues/34)) ([76f8c16](https://github.com/inpsyde/payment-gateway/commit/76f8c1626f3360b9763c6210393a6f7a40a0ccd7)), closes [#35](https://github.com/inpsyde/payment-gateway/issues/35)
+
+## [1.5.2](https://github.com/inpsyde/payment-gateway/compare/1.5.1...1.5.2) (2024-11-13)
+
+
+### Bug Fixes
+
+* allow node 22 ([1a28fdd](https://github.com/inpsyde/payment-gateway/commit/1a28fdd38be46459d1c63cd99192d9f2bc22e25d))
+* allow node 22 ([93a85e6](https://github.com/inpsyde/payment-gateway/commit/93a85e69eb329620dc636180298253ac18742a66))
+
+## [1.5.1](https://github.com/inpsyde/payment-gateway/compare/1.5.0...1.5.1) (2024-09-23)
+
+
+### Bug Fixes
+
+* Fix PaymentGatewayBlocks::$gateway type. ([#31](https://github.com/inpsyde/payment-gateway/issues/31)) ([58cd64c](https://github.com/inpsyde/payment-gateway/commit/58cd64cb64bc11fcd1a89d9aa0690d90738162a4))
+
+# [1.5.0](https://github.com/inpsyde/payment-gateway/compare/1.4.1...1.5.0) (2024-09-20)
+
+
+### Bug Fixes
+
+* code style, remove PaymentGatewayBlocks::$name type ([32ed490](https://github.com/inpsyde/payment-gateway/commit/32ed490e73414383c6f6eb34529a483468afb56c))
+
+
+### Features
+
+* Allow to interrupt refund with a message ([e5c6e10](https://github.com/inpsyde/payment-gateway/commit/e5c6e10d06b228483b8725cfbd41686fb0c5b776))
+
+## [1.4.1](https://github.com/inpsyde/payment-gateway/compare/1.4.0...1.4.1) (2024-09-18)
+
+
+### Bug Fixes
+
+* use variable in process_refund() ([afabd5c](https://github.com/inpsyde/payment-gateway/commit/afabd5cc6e08a830238af5067500df3fb462644f))
+
+# [1.4.0](https://github.com/inpsyde/payment-gateway/compare/1.3.2...1.4.0) (2024-09-13)
+
+
+### Features
+
+* [PROD-169] Implement l10n for errors & order notes ([#26](https://github.com/inpsyde/payment-gateway/issues/26)) ([7806c79](https://github.com/inpsyde/payment-gateway/commit/7806c798bc1a6e450f91d703fc94f7c07e8aea96)), closes [#1](https://github.com/inpsyde/payment-gateway/issues/1) [#2](https://github.com/inpsyde/payment-gateway/issues/2)
+
+## [1.3.2](https://github.com/inpsyde/payment-gateway/compare/1.3.1...1.3.2) (2024-07-12)
+
+
+### Bug Fixes
+
+* Keep frontend source and composer.json in releases ([ee1f8a3](https://github.com/inpsyde/payment-gateway/commit/ee1f8a3642d9240927b8df39b70e8022b000ad4f))
+
+## [1.3.1](https://github.com/inpsyde/payment-gateway/compare/1.3.0...1.3.1) (2024-07-01)
+
+
+### Bug Fixes
+
+* Do not use PHP_INT_MIN for hooks ([8e5e15d](https://github.com/inpsyde/payment-gateway/commit/8e5e15d4f09364333b5937a2d09b44210fe0c2f4))
+* Move comment outside of expression ([c80b6cd](https://github.com/inpsyde/payment-gateway/commit/c80b6cde33661b53fe0ac73824f5eaae3fda9db7))
+
+# [1.3.0](https://github.com/inpsyde/payment-gateway/compare/1.2.0...1.3.0) (2024-06-05)
+
+
+### Features
+
+* Add locators for method title & description ([#24](https://github.com/inpsyde/payment-gateway/issues/24)) ([27a73a9](https://github.com/inpsyde/payment-gateway/commit/27a73a90965af918da92185526315a97ab8b8c48))
+
+# [1.2.0](https://github.com/inpsyde/payment-gateway/compare/1.1.1...1.2.0) (2024-06-05)
+
+
+### Features
+
+* Check required services during init ([79ae2b9](https://github.com/inpsyde/payment-gateway/commit/79ae2b9bb178376419c91b418bdfa2b593b99346)), closes [#15](https://github.com/inpsyde/payment-gateway/issues/15)
+
+## [1.1.1](https://github.com/inpsyde/payment-gateway/compare/1.1.0...1.1.1) (2024-06-04)
+
+
+### Bug Fixes
+
+* don't register gateway for blocks if disabled ([e577b52](https://github.com/inpsyde/payment-gateway/commit/e577b522ef0452104a2e54c499f39e9953876a38))
+
+# [1.1.0](https://github.com/inpsyde/payment-gateway/compare/1.0.1...1.1.0) (2024-06-04)
+
+
+### Features
+
+* Add a new service to allow skipping blocks registration ([#21](https://github.com/inpsyde/payment-gateway/issues/21)) ([e1978d1](https://github.com/inpsyde/payment-gateway/commit/e1978d19654a2c685265a9d32fa12ff49c7b6249))
+
+# 1.0.0 (2024-05-21)
+
+
+### Bug Fixes
+
+* specify playwright dependency ([1060e5c](https://github.com/inpsyde/payment-gateway/commit/1060e5cafece37c465e6e78077d2c7378f723b46))
diff --git a/lib/payment-gateway/composer.json b/lib/payment-gateway/composer.json
new file mode 100644
index 000000000..b13040dd9
--- /dev/null
+++ b/lib/payment-gateway/composer.json
@@ -0,0 +1,112 @@
+{
+ "name": "inpsyde/payment-gateway",
+ "type": "inpsyde-module",
+ "description": "",
+ "license": "GPL-2.0",
+ "authors": [
+ {
+ "name": "Inpsyde GmbH",
+ "homepage": "https://inpsyde.com/",
+ "email": "hello@inpsyde.com",
+ "role": "Company"
+ }
+ ],
+ "repositories": [
+ {
+ "type": "composer",
+ "url": "https://repo.packagist.com/inpsyde/"
+ }
+ ],
+ "require": {
+ "php": "^7.4 | ^8.0",
+ "inpsyde/modularity": "^1.5"
+ },
+ "require-dev": {
+ "brain/monkey": "^2.0",
+ "brainmaestro/composer-git-hooks": "^2.8",
+ "inpsyde/composer-assets-compiler": "^2.5",
+ "inpsyde/ddev-tools": "dev-main",
+ "inpsyde/php-coding-standards": "^2.0",
+ "inpsyde/wp-translation-downloader": "^2.4",
+ "mockery/mockery": "^1.3",
+ "phpunit/phpunit": "^8.0 | ^9.0",
+ "php-stubs/wordpress-stubs": "^5.0@stable",
+ "php-stubs/woocommerce-stubs": "^5.0@stable",
+ "vimeo/psalm": "^4.3"
+ },
+ "autoload": {
+ "psr-4": {
+ "Inpsyde\\PaymentGateway\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Inpsyde\\PaymentGateway\\Test\\": "tests/PHPUnit/Helper"
+ }
+ },
+ "minimum-stability": "dev",
+ "prefer-stable": true,
+ "scripts": {
+ "phpcs": "@php ./vendor/bin/phpcs -n -s --parallel=24",
+ "phpcs:phpcbf": "@php ./vendor/bin/phpcbf --parallel=24;exit 0",
+ "phpcs:interactive": "@php ./vendor/bin/phpcs -a",
+ "phpcs:dev": [
+ "@cs:phpcbf",
+ "@cs:interactive"
+ ],
+ "phpunit": "vendor/bin/phpunit",
+ "test": [
+ "@phpunit"
+ ],
+ "cghooks": "vendor/bin/cghooks",
+ "post-install-cmd": [
+ "@cghooks add --ignore-lock"
+ ],
+ "post-update-cmd": [
+ "@cghooks update"
+ ]
+ },
+ "config": {
+ "sort-packages": true,
+ "optimize-autoloader": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true,
+ "inpsyde/composer-assets-compiler": true,
+ "composer/installers": true,
+ "inpsyde/wp-translation-downloader": true
+ }
+ },
+ "extra": {
+ "hooks": {
+ "pre-commit": [
+ "vendor/bin/phpcbf -q --parallel=24; exit 0"
+ ]
+ },
+ "wp-translation-downloader": {
+ "auto-run": false,
+ "languageRootDir": "./",
+ "languages": [
+ "de_DE",
+ "en_US"
+ ],
+ "api": {
+ "names": {
+ "inpsyde/*": "https://translate.inpsyde.com/products/api/translations/%projectName%"
+ }
+ },
+ "directories": {
+ "names": {
+ "inpsyde/*": "languages/"
+ }
+ }
+ },
+ "composer-asset-compiler": {
+ "auto-run": false,
+ "dependencies": "install",
+ "script": "build",
+ "default-env": {
+ "WEBPACK_ENV": "production"
+ }
+ }
+ }
+}
diff --git a/lib/payment-gateway/index.php b/lib/payment-gateway/index.php
new file mode 100644
index 000000000..4d2383de6
--- /dev/null
+++ b/lib/payment-gateway/index.php
@@ -0,0 +1,31 @@
+ 'GET',
+ 'callback' => function () {
+ return ['hello' => __('world', 'ddev-wordpress-plugin-example')];
+ },
+ 'permission_callback' => '__return_true',
+ ]);
+});
+
+
diff --git a/lib/payment-gateway/languages/ddev-wordpress-plugin-example.pot b/lib/payment-gateway/languages/ddev-wordpress-plugin-example.pot
new file mode 100644
index 000000000..2ac5537ac
--- /dev/null
+++ b/lib/payment-gateway/languages/ddev-wordpress-plugin-example.pot
@@ -0,0 +1,36 @@
+# Copyright (C) 2023 Inpsyde
+# This file is distributed under the GPL-2.0.
+msgid ""
+msgstr ""
+"Project-Id-Version: ddev-wordpress-plugin-example {VERSION}\n"
+"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/ddev-wordpress-plugin-example\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"POT-Creation-Date: 2023-02-01T14:03:42+00:00\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"X-Generator: WP-CLI 2.7.1\n"
+"X-Domain: ddev-wordpress-plugin-example\n"
+
+#. Plugin Name of the plugin
+msgid "ddev-wordpress-plugin-example"
+msgstr ""
+
+#. Plugin URI of the plugin
+#. Author URI of the plugin
+msgid "https://inpsyde.com"
+msgstr ""
+
+#. Description of the plugin
+msgid "{DESCRIPTION}"
+msgstr ""
+
+#. Author of the plugin
+msgid "Inpsyde"
+msgstr ""
+
+#: ddev-wordpress-plugin-example.php:25
+msgid "world"
+msgstr ""
diff --git a/lib/payment-gateway/package.json b/lib/payment-gateway/package.json
new file mode 100644
index 000000000..ba7a33030
--- /dev/null
+++ b/lib/payment-gateway/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@inpsyde/generic-payment-gateway",
+ "version": "0.1.0",
+ "engines": {
+ "node": "^16 || ^18 || ^20 || ^22"
+ },
+ "devDependencies": {
+ "@semantic-release/changelog": "^6.0.3",
+ "@semantic-release/commit-analyzer": "^12.0.0",
+ "@semantic-release/exec": "^6.0.3",
+ "@semantic-release/git": "^10.0.1",
+ "@semantic-release/github": "^10.0.3",
+ "@semantic-release/npm": "^12.0.0",
+ "@semantic-release/release-notes-generator": "^13.0.0",
+ "@woocommerce/dependency-extraction-webpack-plugin": "3.0.0",
+ "@woocommerce/settings": "^1.0.0",
+ "@wordpress/hooks": "^4.11.0",
+ "@wordpress/html-entities": "^3.39.0",
+ "@wordpress/i18n": "^4.39.0",
+ "@wordpress/scripts": "^26.10.0",
+ "semantic-release": "^23.0.8",
+ "ts-loader": "^9.0.0",
+ "typescript": "^5.1.6"
+ },
+ "scripts": {
+ "build": "wp-scripts build",
+ "build:dev": "wp-scripts build --mode development",
+ "dev": "wp-scripts build --mode development --watch",
+ "start": "wp-scripts start",
+ "lint:md": "wp-scripts lint-md-docs docs/**/*.md",
+ "lint:js": "wp-scripts lint-js resources/js/**/*",
+ "lint:style": "wp-scripts lint-style resources/scss/**/*.scss"
+ }
+}
diff --git a/lib/payment-gateway/psalm.xml.dist b/lib/payment-gateway/psalm.xml.dist
new file mode 100644
index 000000000..8cf3d7066
--- /dev/null
+++ b/lib/payment-gateway/psalm.xml.dist
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/payment-gateway/release.config.js b/lib/payment-gateway/release.config.js
new file mode 100644
index 000000000..0ca2a55e9
--- /dev/null
+++ b/lib/payment-gateway/release.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ "branches": ["main"],
+ "plugins": [
+ "@semantic-release/commit-analyzer",
+ "@semantic-release/release-notes-generator",
+ "@semantic-release/changelog",
+ "@semantic-release/github",
+ ["@semantic-release/git", {
+ "assets": ["CHANGELOG.md"],
+ "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
+ }]
+ ],
+ "preset": "angular",
+ "tagFormat": "${version}"
+}
\ No newline at end of file
diff --git a/lib/payment-gateway/resources/js/backend.js b/lib/payment-gateway/resources/js/backend.js
new file mode 100644
index 000000000..f5f3a3c64
--- /dev/null
+++ b/lib/payment-gateway/resources/js/backend.js
@@ -0,0 +1 @@
+alert('hi!');
diff --git a/lib/payment-gateway/resources/js/blocks/index.js b/lib/payment-gateway/resources/js/blocks/index.js
new file mode 100644
index 000000000..17c66c7ed
--- /dev/null
+++ b/lib/payment-gateway/resources/js/blocks/index.js
@@ -0,0 +1,67 @@
+import {__} from '@wordpress/i18n';
+import {registerPaymentMethod} from '@woocommerce/blocks-registry';
+import {decodeEntities} from '@wordpress/html-entities';
+import {getSetting} from '@woocommerce/settings';
+import {defaultHooks} from '@wordpress/hooks';
+
+
+inpsydeGateways.forEach((name) => {
+ const settings = getSetting(`${name}_data`, {});
+ const hookName = `${name}_checkout_fields`;
+ const defaultLabel = __(
+ 'Syde Payment Gateway',
+ 'syde-payment-gateway'
+ );
+
+ const label = decodeEntities(settings.title) || defaultLabel;
+
+ const Content = () => {
+ const components = defaultHooks.applyFilters(hookName, [])
+ console.log(hookName)
+
+ /**
+ * If no external plugins/slot-fills are configured,
+ * we default to displaying the method description
+ */
+ if (!Array.isArray(components) || !components.length) {
+ const DefaultPlugin = () => decodeEntities(settings.description || '');
+ return
+ }
+
+ return (
+ <>{components.map((Component) => )}>
+ );
+ };
+ /**
+ * Label component
+ *
+ * @param {*} props Props from payment API.
+ */
+ const Label = (props) => {
+ const {PaymentMethodLabel} = props.components;
+ return ;
+ };
+
+ /**
+ * Payment method config object.
+ */
+ const PaymentMethod = {
+ name: name,
+ label: ,
+ content: ,
+ edit: ,
+ canMakePayment: () => true,
+ ariaLabel: label,
+ supports: {
+ features: settings.supports,
+ },
+ };
+
+ if (settings.placeOrderButtonLabel) {
+ PaymentMethod.placeOrderButtonLabel = settings.placeOrderButtonLabel;
+ }
+
+ registerPaymentMethod(PaymentMethod);
+
+})
+
diff --git a/lib/payment-gateway/src/Fields/ContentField.php b/lib/payment-gateway/src/Fields/ContentField.php
new file mode 100644
index 000000000..1c74d3238
--- /dev/null
+++ b/lib/payment-gateway/src/Fields/ContentField.php
@@ -0,0 +1,56 @@
+get_field_key($fieldId);
+ $data = array_merge([
+ 'title' => '',
+ 'disabled' => false,
+ 'class' => '',
+ 'css' => '',
+ 'placeholder' => '',
+ 'type' => 'text',
+ 'desc_tip' => false,
+ 'description' => '',
+ 'custom_attributes' => [],
+ ], $fieldConfig);
+
+ $hasTitle = !empty($data['title']);
+
+ // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
+ ob_start();
+ ?>
+
+
+
+
+ |
+
+
+ get_description_html($data); ?>
+ |
+
+ >
+ */
+ protected array $messagesGatewayMap = [];
+
+ public function __construct(ContainerInterface $serviceLocator)
+ {
+ $this->serviceLocator = $serviceLocator;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function translate(string $messageKey, string $gatewayId, array $params = []): string
+ {
+ $messages = $this->messageMap($gatewayId);
+
+ $message = $messages[$messageKey] ?? null;
+
+ if ($message === null) {
+ throw new Exception("Message $messageKey not found.");
+ }
+
+ if (is_callable($message)) {
+ return (string) $message($params);
+ }
+ return (string) $message;
+ }
+
+ protected function messageMap(string $gatewayId): array
+ {
+ if (!isset($this->messagesGatewayMap[$gatewayId])) {
+ $this->messagesGatewayMap[$gatewayId] = array_merge(
+ (array) $this->serviceLocator->get('payment_gateways.i18n.messages'),
+ $this->serviceLocator->has("payment_gateway.$gatewayId.i18n.messages") ?
+ (array) $this->serviceLocator->get("payment_gateway.$gatewayId.i18n.messages") :
+ []
+ );
+ }
+
+ return $this->messagesGatewayMap[$gatewayId];
+ }
+}
diff --git a/lib/payment-gateway/src/NoopPaymentProcessor.php b/lib/payment-gateway/src/NoopPaymentProcessor.php
new file mode 100644
index 000000000..e1ecf740e
--- /dev/null
+++ b/lib/payment-gateway/src/NoopPaymentProcessor.php
@@ -0,0 +1,16 @@
+ 'success',
+ 'redirect' => $gateway->get_return_url($order),
+ ];
+ }
+}
diff --git a/lib/payment-gateway/src/NoopPaymentRequestValidator.php b/lib/payment-gateway/src/NoopPaymentRequestValidator.php
new file mode 100644
index 000000000..b74625c26
--- /dev/null
+++ b/lib/payment-gateway/src/NoopPaymentRequestValidator.php
@@ -0,0 +1,13 @@
+id = $id;
+ $this->serviceLocator = $serviceLocator;
+ $this->supports = $this->locateWithFallback('supports', [
+ 'products',
+ ]);
+ $this->i18n = $serviceLocator->get('payment_gateways.i18n');
+ $this->init_settings();
+ unset($this->order_button_text);
+ unset($this->method_title);
+ unset($this->method_description);
+
+ add_action(
+ 'woocommerce_update_options_payment_gateways_' . $this->id,
+ [$this, 'process_admin_options']
+ );
+
+ add_action('woocommerce_settings_checkout', [$this, 'display_errors']);
+
+ add_filter(
+ 'woocommerce_settings_api_sanitized_fields_' . $this->id,
+ [$this, 'filterVirtualFields'],
+ -1000
+ );
+ }
+
+ public function init_settings()
+ {
+
+ parent::init_settings();
+
+ do_action($this->id . '_after_init_settings', $this);
+ }
+
+ public function get_title(): string
+ {
+ if (!$this->title) {
+ $this->title = $this->locateWithFallback('title', $this->id);
+ }
+
+ return parent::get_title();
+ }
+
+ public function get_description(): string
+ {
+ if (!$this->description) {
+ $this->description = $this->locateWithFallback('description', $this->id);
+ }
+
+ return parent::get_description();
+ }
+
+ /**
+ * Detect payment gateway availability.
+ *
+ * @return bool Whether it is available, true for yes and false for no.
+ */
+ public function is_available(): bool
+ {
+ $isAvailable = parent::is_available();
+
+ if (!$isAvailable) {
+ return false;
+ }
+
+ $canBeUsed = $this->locateWithFallback('availability_callback', static function () {
+ return true;
+ });
+ assert(is_callable($canBeUsed));
+
+ return $canBeUsed($this);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function process_payment($orderId): array
+ {
+ /**
+ * Produce the WC_Order instance first
+ * This should never fail unless there's a bug in WC
+ * But we need to be verbose here
+ */
+ try {
+ $order = $this->getOrder((string) $orderId);
+ $paymentRequestValidator = $this->locate(
+ 'payment_request_validator'
+ );
+ assert($paymentRequestValidator instanceof PaymentRequestValidatorInterface);
+ $paymentRequestValidator->assertIsValid($order, $this);
+ } catch (RuntimeException $exception) {
+ wc_add_notice($exception->getMessage(), 'error');
+ WC()->session->set('refresh_totals', true);
+
+ return [
+ 'result' => 'failure',
+ 'redirect' => '',
+ ];
+ }
+
+ $processor = $this->locate('payment_processor');
+ assert($processor instanceof PaymentProcessorInterface);
+
+ return $processor->processPayment($order, $this);
+ }
+
+ public function get_icon()
+ {
+ try {
+ $iconService = $this->locate('gateway_icons_renderer');
+ assert($iconService instanceof GatewayIconsRendererInterface);
+ } catch (ContainerExceptionInterface $exception) {
+ return apply_filters('woocommerce_gateway_icon', '', $this->id);
+ }
+
+ $output = $iconService->renderIcons();
+
+ return apply_filters('woocommerce_gateway_icon', $output, $this->id);
+ }
+
+ /**
+ * Get order by ID or throw exception.
+ *
+ * @param string $orderId Order ID to get order by.
+ *
+ * @return WC_Order Found order.
+ *
+ * @throws RuntimeException If order not found.
+ */
+ protected function getOrder(string $orderId): WC_Order
+ {
+ $order = wc_get_order($orderId);
+
+ if (!$order instanceof WC_Order) {
+ throw new RuntimeException(
+ sprintf(
+ 'Failed to process order %1$d, it cannot be found.',
+ $orderId
+ )
+ );
+ }
+
+ return $order;
+ }
+
+ /**
+ * Get transaction URL template for order.
+ *
+ * @param $order
+ *
+ * @return string
+ */
+ public function get_transaction_url($order): string
+ {
+ $this->view_transaction_url = (string) $order->get_meta(
+ self::TRANSACTION_URL_TEMPLATE_FIELD_NAME,
+ true
+ );
+
+ return parent::get_transaction_url($order);
+ }
+
+ /**
+ * @inheritDoc
+ * @throws Exception
+ */
+ public function process_refund($orderId, $amount = \null, $reason = '')
+ {
+ $order = wc_get_order($orderId);
+
+ if (!$order instanceof WC_Order) {
+ return new WP_Error(
+ 'refund_order_not_found',
+ $this->i18n->translate('refund_order_not_found', $this->id, [
+ 'orderId' => $orderId,
+ ])
+ );
+ }
+
+ $amount = floatval($amount);
+
+ $refundProcessor = $this->locate('refund_processor');
+ assert($refundProcessor instanceof RefundProcessorInterface);
+
+ $refundProcessor->refundOrderPayment($order, $amount, $reason);
+
+ return true;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function payment_fields(): void
+ {
+ try {
+ $renderer = $this->locate('payment_fields_renderer');
+ assert($renderer instanceof PaymentFieldsRendererInterface);
+ } catch (ContainerExceptionInterface $exception) {
+ parent::payment_fields();
+ return;
+ }
+
+ try {
+ //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $renderer->renderFields();
+ } catch (\Throwable $exception) {
+ do_action($this->id . '_payment_fields_failure', [
+ 'exception' => $exception,
+ ]);
+ echo esc_html($this->i18n->translate(
+ 'payment_method_not_available',
+ $this->id
+ ));
+ }
+ }
+
+ /**
+ * Container-aware re-implementation of the parent method.
+ * It first tries to find a dedicated service and falls back to the original implementation
+ * if none is found.
+ *
+ * @param $formFields
+ * @param $echo
+ *
+ * @return string|void
+ */
+ public function generate_settings_html($formFields = [], $echo = true)
+ {
+ if (empty($formFields)) {
+ $formFields = $this->get_form_fields();
+ }
+
+ $html = '';
+ foreach ($formFields as $key => $value) {
+ $type = $this->get_field_type($value);
+ try {
+ /**
+ * Check if we have a dedicated renderer in our service container
+ */
+ $fieldRenderer = $this->locate(
+ 'settings_field_renderer.' . $type
+ );
+ assert($fieldRenderer instanceof SettingsFieldRendererInterface);
+ $html .= $fieldRenderer->render($key, $value, $this);
+ } catch (ContainerExceptionInterface $exception) {
+ /**
+ * Fallback to WC core implementation
+ */
+ if (method_exists($this, 'generate_' . $type . '_html')) {
+ $html .= $this->{'generate_' . $type . '_html'}($key, $value);
+ continue;
+ }
+ if (has_filter('woocommerce_generate_' . $type . '_html')) {
+ $html .= apply_filters(
+ 'woocommerce_generate_' . $type . '_html',
+ '',
+ $key,
+ $value,
+ $this
+ );
+ continue;
+ }
+ $html .= $this->generate_text_html($key, $value);
+ }
+ }
+ if ($echo) {
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $html;
+ }
+
+ return $html;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Adds support for groups.
+ */
+ public function get_custom_attribute_html($data)
+ {
+ if (!isset($data['custom_attributes'])) {
+ $data['custom_attributes'] = [];
+ }
+
+ if (isset($data['group'])) {
+ $data['custom_attributes']['group'] = $data['group'];
+ }
+
+ if (isset($data['group_role'])) {
+ $data['custom_attributes']['group_role'] = $data['group_role'];
+ }
+
+ $html = parent::get_custom_attribute_html($data);
+
+ return $html;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function process_admin_options(): bool
+ {
+ $result = parent::process_admin_options();
+
+ return $result;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Makes sanitization container-aware.
+ * If a 'inpsyde_payment_gateway.settings_field_sanitizer.' . $type service is found
+ * then it is used instead of WC core sanitization.
+ *
+ * Additional exception handling is applied, so a RangeException thrown by any sanitization
+ * will be rendered as an error
+ */
+ public function get_field_value($key, $field, $postData = [])
+ {
+ $type = $this->get_field_type($field);
+ $fieldKey = $this->get_field_key($key);
+ // phpcs:ignore WordPress.Security
+ $postData = empty($postData) ? $_POST : $postData;
+ $value = $postData[$fieldKey] ?? null;
+ try {
+ if (isset($field['sanitize_callback']) && is_callable($field['sanitize_callback'])) {
+ // keeping WC behavior
+ // phpcs:ignore Inpsyde.CodeQuality.DisableCallUserFunc.call_user_func_call_user_func
+ return call_user_func($field['sanitize_callback'], $value);
+ }
+
+ /**
+ * Check if we have a dedicated field sanitizer in our service container
+ */
+ $sanitizer = $this->locateWithFallback(
+ 'settings_field_sanitizer.' . $key . '_field',
+ $this->locateWithFallback('settings_field_sanitizer.' . $type, null)
+ );
+ if ($sanitizer instanceof SettingsFieldSanitizerInterface) {
+ return $sanitizer->sanitize($key, $value, $this);
+ }
+
+ /**
+ * Fallback to WC core implementation
+ */
+ // Look for a validate_FIELDID_field method for special handling.
+ if (is_callable([$this, 'validate_' . $key . '_field'])) {
+ return $this->{'validate_' . $key . '_field'}($key, $value);
+ }
+
+ // Look for a validate_FIELDTYPE_field method.
+ if (is_callable([$this, 'validate_' . $type . '_field'])) {
+ return $this->{'validate_' . $type . '_field'}($key, $value);
+ }
+
+ // Fallback to text.
+ return $this->validate_text_field($key, $value);
+ } catch (RangeException $exception) {
+ $this->add_error(
+ sprintf('Field "%1$s" is invalid: %2$s', $key, $exception->getMessage())
+ );
+
+ return null;
+ }
+ }
+
+ /**
+ * Retrieves configuration for a field.
+ *
+ * @param string $key The key of the field.
+ *
+ * @return array The field configuration.
+ *
+ * @throws RangeException If field not configured.
+ * @throws RuntimeException If problem retrieving.
+ */
+ protected function getFieldConfig(string $key): array
+ {
+ $fields = $this->get_form_fields();
+ if (!isset($fields[$key])) {
+ throw new RangeException(sprintf('Field "%1$s" is not configured', $key));
+ }
+
+ $field = $fields[$key];
+ if (!is_array($field)) {
+ throw new UnexpectedValueException(
+ sprintf('Invalid configuration for field "%1$s"', $key)
+ );
+ }
+
+ return $field;
+ }
+
+ /**
+ * Retrieves the incoming value of a field with the specified name.
+ *
+ * @param string $key The field key.
+ *
+ * @return scalar The value of the field.
+ *
+ * @throws RangeException If field not configured.
+ * @throws RuntimeException If problem retrieving.
+ */
+ protected function getIncomingFieldValue(string $key)
+ {
+ $field = $this->getFieldConfig($key);
+ /**
+ * See https://github.com/woocommerce/woocommerce/issues/32512
+ */
+ $type = $this->get_field_type($field);
+ // Virtual fields only available in storage.
+ $value = $type === 'virtual'
+ ? $this->get_option($key)
+ : $this->get_field_value($key, $field);
+
+ return $value;
+ }
+
+ /**
+ * Returns the value of a field with the specified key.
+ *
+ * Allows defaults to be overridden.
+ *
+ * @param string $key The field key.
+ *
+ * @return scalar The value of the field.
+ *
+ * @throws RangeException If field not configured.
+ * @throws RuntimeException If problem retrieving.
+ */
+ protected function getFieldValue(string $key)
+ {
+ $value = $this->getIncomingFieldValue($key);
+
+ if ($value === '') {
+ $value = $this->get_option($key);
+ }
+
+ return $value;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function get_form_fields()
+ {
+ if (!$this->form_fields) {
+ $this->form_fields = $this->locateWithFallback('form_fields', [
+ 'enabled' => [
+ 'title' => 'Enable/Disable',
+ 'type' => 'checkbox',
+ 'label' => 'Enable payment method',
+ 'default' => 'no',
+ ],
+ ]);
+ }
+
+ return parent::get_form_fields();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function get_option_key()
+ {
+ try {
+ $optionKey = $this->locate('option_key');
+ assert(is_string($optionKey));
+ } catch (ContainerExceptionInterface $exception) {
+ $optionKey = null;
+ }
+
+ return $optionKey ?? parent::get_option_key();
+ }
+
+ /**
+ * Prevents some fields from being saved to the database.
+ *
+ * It filters fields with the 'virtual' field type
+ * and fields with the 'save` attribute set to false.
+ * Such fields can be used for safely transferring API credentials or
+ * other use-cases that require processing user input without storing it as-is
+ *
+ * @param array $settings
+ *
+ * @return array
+ */
+ public function filterVirtualFields(array $settings): array
+ {
+ $validFields = array_filter($this->get_form_fields(), static function (array $fieldConfig) {
+ if (isset($fieldConfig['save'])) {
+ return $fieldConfig['save'] !== false;
+ }
+ return $fieldConfig['type'] !== 'virtual';
+ });
+ $validKeys = array_keys($validFields);
+ foreach ($settings as $key => $value) {
+ if (!in_array($key, $validKeys, true)) {
+ unset($settings[$key]);
+ }
+ }
+
+ return $settings;
+ }
+
+ /**
+ * @param string $key
+ * @return mixed
+ * @throws NotFoundExceptionInterface No entry was found for this key.
+ * @throws ContainerExceptionInterface Error while retrieving the entry.
+ */
+ private function locate(string $key)
+ {
+ try {
+ return $this->serviceLocator->get($this->createServiceKey($key));
+ } catch (ContainerExceptionInterface $exception) {
+ $globalKey = 'payment_gateways.' . $key;
+ if ($this->serviceLocator->has($globalKey)) {
+ return $this->serviceLocator->get($globalKey);
+ }
+
+ throw $exception;
+ }
+ }
+
+ private function locateWithFallback(string $key, $fallback)
+ {
+ try {
+ return $this->locate($key);
+ } catch (ContainerExceptionInterface $exception) {
+ return $fallback;
+ }
+ }
+
+ private function createServiceKey(string $key): string
+ {
+ return 'payment_gateway.' . $this->id . '.' . $key;
+ }
+
+ public function has_fields()
+ {
+ try {
+ return (bool) $this->locate('has_fields');
+ } catch (ContainerExceptionInterface $exception) {
+ return parent::has_fields();
+ }
+ }
+
+ public function __get($name)
+ {
+ if ($name === 'order_button_text') {
+ return $this->locateWithFallback($name, null);
+ }
+
+ if ($name === 'method_title') {
+ return $this->locateWithFallback($name, $this->id);
+ }
+
+ if ($name === 'method_description') {
+ return $this->locateWithFallback($name, $this->id);
+ }
+
+ return $this->$name;
+ }
+}
diff --git a/lib/payment-gateway/src/PaymentGatewayBlocks.php b/lib/payment-gateway/src/PaymentGatewayBlocks.php
new file mode 100644
index 000000000..243dc38d9
--- /dev/null
+++ b/lib/payment-gateway/src/PaymentGatewayBlocks.php
@@ -0,0 +1,112 @@
+container = $container;
+ $this->name = $gatewayId;
+ }
+
+ public function initialize()
+ {
+ // TODO: Implement initialize() method.
+ }
+
+ public function is_active()
+ {
+ return true;
+ }
+
+ /**
+ * Returns an array of scripts/handles to be registered for this payment method.
+ *
+ * @return array
+ */
+ public function get_payment_method_script_handles()
+ {
+ $scriptPath = '/js/frontend/blocks.js';
+ $scriptAssetPath = $this->container
+ ->get('payment_gateways.assets_path') . '/js/frontend/blocks.asset.php';
+ $scriptAsset = file_exists($scriptAssetPath)
+ ? require($scriptAssetPath)
+ : [
+ 'dependencies' => [],
+ 'version' => '0.1.0',
+ ];
+ $scriptUrl = $this->container->get('payment_gateways.assets_url') . $scriptPath;
+ $scriptId = 'inpsyde-blocks';
+ /**
+ * @psalm-suppress MixedArgument
+ */
+ wp_register_script(
+ $scriptId,
+ $scriptUrl,
+ $scriptAsset['dependencies'],
+ $scriptAsset['version'],
+ true
+ );
+ /**
+ * @psalm-suppress MixedArgument
+ */
+ wp_localize_script($scriptId, 'inpsydeGateways', $this->container->get('payment_gateways'));
+
+ return [$scriptId];
+ }
+
+ public function get_payment_method_data()
+ {
+ $gateway = $this->gateway();
+
+ return [
+ 'title' => $gateway->get_title(),
+ 'description' => $gateway->get_description(),
+ 'supports' => array_filter($gateway->supports, [$gateway, 'supports']),
+ 'placeOrderButtonLabel' => $gateway->order_button_text,
+ ];
+ }
+
+ protected function gateway(): PaymentGateway
+ {
+ if ($this->gateway !== null) {
+ return $this->gateway;
+ }
+
+ $wcPaymentGateways = WC_Payment_Gateways::instance();
+ $gateways = $wcPaymentGateways->payment_gateways();
+ foreach ($gateways as $gatewayId => $gateway) {
+ if ($gatewayId === $this->name) {
+ assert($gateway instanceof PaymentGateway);
+
+ $this->gateway = $gateway;
+
+ return $this->gateway;
+ }
+ }
+ throw new \RuntimeException('Gateway not found');
+ }
+}
diff --git a/lib/payment-gateway/src/PaymentGatewayModule.php b/lib/payment-gateway/src/PaymentGatewayModule.php
new file mode 100644
index 000000000..06b3f7435
--- /dev/null
+++ b/lib/payment-gateway/src/PaymentGatewayModule.php
@@ -0,0 +1,192 @@
+ function (): string {
+ return $this->getPluginFileUrlFromAbsolutePath(dirname(__DIR__) . '/assets');
+ },
+ 'payment_gateways.assets_path' => static function (): string {
+ return dirname(__DIR__) . '/assets';
+ },
+ 'payment_gateways.noop_payment_request_validator' => static function (): PaymentRequestValidatorInterface {
+ return new NoopPaymentRequestValidator();
+ },
+ 'payment_gateways.noop_payment_processor' => static function (): PaymentProcessorInterface {
+ return new NoopPaymentProcessor();
+ },
+ 'payment_gateways.noop_refund_processor' => static function (): RefundProcessorInterface {
+ return new NoopRefundProcessor();
+ },
+ 'payment_gateways.settings_field_renderer.content' => static function (): SettingsFieldRendererInterface {
+ return new ContentField();
+ },
+ 'payment_gateways' => static function (): array {
+ return [];
+ },
+ 'payment_gateways.required_services' => static function (): array {
+ return [
+ 'payment_gateway.%s.payment_request_validator',
+ 'payment_gateway.%s.payment_processor',
+ ];
+ },
+ 'payment_gateways.validator' => static function (ContainerInterface $container): PaymentGatewayValidator {
+ $requiredServices = $container->get('payment_gateways.required_services');
+ assert(is_array($requiredServices));
+ return new PaymentGatewayValidator($container, $requiredServices);
+ },
+ 'payment_gateways.i18n' => static fn (ContainerInterface $container): I18n => new I18n($container),
+ 'payment_gateways.i18n.messages' => static fn (): array => [
+ 'refund_order_not_found' => static fn (array $params): string => sprintf(
+ /* translators: %1$s is replaced with the actual order ID. */
+ __(
+ 'Failed to process the refund: the order with ID %1$s not found',
+ 'syde-payment-gateway'
+ ),
+ (string) $params['orderId']
+ ),
+ 'refund_failed' => __(
+ 'Failed to refund the order payment',
+ 'syde-payment-gateway'
+ ),
+ 'payment_method_not_available' => __(
+ 'Payment method not available. Please select another payment method.',
+ 'syde-payment-gateway'
+ ),
+ ],
+ ];
+ }
+
+ /**
+ * Get the full URL to a file within a plugin, given its absolute file path.
+ *
+ * @param string $absoluteFilePath The absolute path to the file.
+ *
+ * @return string The full URL to the file.
+ * @throws \RuntimeException if not found in active plugins.
+ */
+ private function getPluginFileUrlFromAbsolutePath(string $absoluteFilePath): string
+ {
+ $activePlugins = wp_get_active_and_valid_plugins();
+ $networkPlugins = function_exists('wp_get_active_network_plugins') ?
+ wp_get_active_network_plugins() :
+ [];
+ $plugins = array_merge($activePlugins, $networkPlugins);
+
+ // Iterate through active plugins to find the matching one
+ foreach ($plugins as $plugin) {
+ $pluginPath = \WP_PLUGIN_DIR . '/' . dirname(plugin_basename($plugin));
+ if (0 === strpos($absoluteFilePath, $pluginPath)) {
+ $relativePath = (string) substr($absoluteFilePath, strlen($pluginPath) + 1);
+ $baseUrl = plugins_url('', $plugin);
+ return $baseUrl . '/' . $relativePath;
+ }
+ }
+
+ throw new \RuntimeException('Could not derive plugin path'); // File not found in active plugins
+ }
+
+ public function run(ContainerInterface $container): bool
+ {
+ add_filter('woocommerce_payment_gateways', static function (array $gateways) use ($container) {
+ $gatewayIds = $container->get('payment_gateways');
+ $gatewayValidator = $container->get('payment_gateways.validator');
+ assert($gatewayValidator instanceof PaymentGatewayValidator);
+ foreach ($gatewayIds as $gatewayId) {
+ assert(is_string($gatewayId));
+ if ($gatewayValidator->validate($gatewayId)) {
+ $gateways[] = new PaymentGateway($gatewayId, $container);
+ }
+ }
+
+ return $gateways;
+ });
+
+ /**
+ * Registers WooCommerce Blocks integration.
+ *
+ */
+ add_action('woocommerce_blocks_loaded', function () use ($container): void {
+ if (!class_exists(AbstractPaymentMethodType::class)) {
+ return;
+ }
+
+ add_action(
+ 'woocommerce_blocks_payment_method_type_registration',
+ function (PaymentMethodRegistry $registry) use ($container) {
+ $gatewayIds = $container->get('payment_gateways');
+ $gatewayValidator = $container->get('payment_gateways.validator');
+ assert($gatewayValidator instanceof PaymentGatewayValidator);
+ foreach ($gatewayIds as $gatewayId) {
+ assert(is_string($gatewayId));
+ if (!$gatewayValidator->validate($gatewayId)) {
+ continue;
+ }
+ $this->registerBlocksSupportUnlessDisabled(
+ $gatewayId,
+ $container,
+ $registry
+ );
+ }
+ }
+ );
+ });
+
+ return true;
+ }
+
+ /**
+ * Register blocks integration after checking a method-specific key to control whether this method
+ * opts out of the functionality. This might be needed for integrations that do not yet support the
+ * needed JS components but also cannot work with a generic approach.
+ *
+ * @param string $gatewayId
+ * @param ContainerInterface $container
+ * @param PaymentMethodRegistry $registry
+ *
+ * @return void
+ * @throws ContainerExceptionInterface
+ */
+ private function registerBlocksSupportUnlessDisabled(
+ string $gatewayId,
+ ContainerInterface $container,
+ PaymentMethodRegistry $registry
+ ): void {
+
+ $registerBlocksKey = 'payment_gateway.' . $gatewayId . '.register_blocks';
+ $shouldRegister = true;
+
+ if ($container->has($registerBlocksKey)) {
+ $shouldRegister = (bool) $container->get($registerBlocksKey);
+ }
+
+ if (!$shouldRegister) {
+ return;
+ }
+ $registry->register(
+ new PaymentGatewayBlocks($container, $gatewayId)
+ );
+ }
+}
diff --git a/lib/payment-gateway/src/PaymentGatewayValidator.php b/lib/payment-gateway/src/PaymentGatewayValidator.php
new file mode 100644
index 000000000..cb5cc6909
--- /dev/null
+++ b/lib/payment-gateway/src/PaymentGatewayValidator.php
@@ -0,0 +1,35 @@
+container = $container;
+ $this->requiredServices = $requiredServices;
+ }
+
+ public function validate(string $gatewayId): bool
+ {
+ /** @var string $requiredService */
+ foreach ($this->requiredServices as $requiredService) {
+ $service = sprintf($requiredService, $gatewayId);
+ if (!$this->container->has($service)) {
+ throw new \Exception(
+ "Please define a service: '$service' for a gateway with the ID: $gatewayId"
+ );
+ }
+ }
+ return true;
+ }
+}
diff --git a/lib/payment-gateway/src/PaymentProcessorInterface.php b/lib/payment-gateway/src/PaymentProcessorInterface.php
new file mode 100644
index 000000000..dfb27679b
--- /dev/null
+++ b/lib/payment-gateway/src/PaymentProcessorInterface.php
@@ -0,0 +1,10 @@
+ {
+ if (wcDepMap[request]) {
+ return wcDepMap[request];
+ }
+};
+
+const requestToHandle = (request) => {
+ if (wcHandleMap[request]) {
+ return wcHandleMap[request];
+ }
+};
+
+module.exports = {
+ ...defaultConfig,
+ entry: {
+ 'frontend/blocks': './resources/js/blocks/index',
+ 'backend': './resources/js/backend',
+ },
+ output: {
+ publicPath: './',
+ path: __dirname + '/assets/js',
+ filename: '[name].js',
+ },
+ plugins: [
+ ...defaultConfig.plugins.filter(
+ (plugin) =>
+ plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
+ ),
+ new WooCommerceDependencyExtractionWebpackPlugin({
+ requestToExternal,
+ requestToHandle
+ })
+ ]
+};
diff --git a/mollie-payments-for-woocommerce.php b/mollie-payments-for-woocommerce.php
index 096abea8b..dbaa1107f 100644
--- a/mollie-payments-for-woocommerce.php
+++ b/mollie-payments-for-woocommerce.php
@@ -119,47 +119,46 @@ function handleException(Throwable $throwable)
*/
function initialize()
{
- try {
- require_once __DIR__ . '/inc/functions.php';
+ static $package;
+ if (!$package) {
+ try {
+ require_once __DIR__ . '/inc/functions.php';
- if (!mollie_wc_plugin_autoload()) {
- return;
- }
+ if (!mollie_wc_plugin_autoload()) {
+ return;
+ }
- $checker = new ConstraintsChecker();
- $meetRequirements = $checker->handleActivation();
- if (!$meetRequirements) {
- $nextScheduledTime = wp_next_scheduled('pending_payment_confirmation_check');
- if ($nextScheduledTime) {
- wp_unschedule_event($nextScheduledTime, 'pending_payment_confirmation_check');
+ $checker = new ConstraintsChecker();
+ $meetRequirements = $checker->handleActivation();
+ if (!$meetRequirements) {
+ $nextScheduledTime = wp_next_scheduled('pending_payment_confirmation_check');
+ if ($nextScheduledTime) {
+ wp_unschedule_event($nextScheduledTime, 'pending_payment_confirmation_check');
+ }
+ return;
}
- return;
- }
- // Initialize plugin.
- $properties = PluginProperties::new(__FILE__);
- $bootstrap = Package::new($properties);
- $modules = [
- new ActivationModule(__FILE__, $properties->get('version')),
- new NoticeModule(),
- new SharedModule(),
- new SDKModule(),
- new SettingsModule(),
- new LogModule('mollie-payments-for-woocommerce-'),
- new AssetsModule(),
- new GatewayModule(),
- new VoucherModule(),
- new PaymentModule(),
- new MerchantCaptureModule(),
- new UninstallModule(),
- ];
- $modules = apply_filters('mollie_wc_plugin_modules', $modules);
- foreach ($modules as $module) {
- $bootstrap->addModule($module);
+
+ // Initialize plugin.
+ $properties = PluginProperties::new(__FILE__);
+ $package = Package::new($properties);
+ $modules = (require __DIR__ . '/inc/modules.php')();
+ $modules = apply_filters('mollie_wc_plugin_modules', $modules);
+ foreach ($modules as $module) {
+ $package->addModule($module);
+ }
+ $package->boot();
+ } catch (Throwable $throwable) {
+ handleException($throwable);
}
- $bootstrap->boot();
- } catch (Throwable $throwable) {
- handleException($throwable);
}
+
+ /** @var Package $package */
+ return $package;
}
-add_action('plugins_loaded', __NAMESPACE__ . '\\initialize');
+add_action(
+/**
+ * @throws Throwable
+ */ 'after_setup_theme', static function () {
+ initialize();
+});
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 6e33896a4..dff5ee390 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -19,4 +19,9 @@
tests/php/Functional
+
+
+ skip
+
+
diff --git a/src/Activation/ActivationModule.php b/src/Activation/ActivationModule.php
index 270ba92ea..3389c4c8f 100644
--- a/src/Activation/ActivationModule.php
+++ b/src/Activation/ActivationModule.php
@@ -20,15 +20,6 @@ class ActivationModule implements ExecutableModule
private $baseFile;
private $pluginVersion;
- /**
- * ActivationModule constructor.
- */
- public function __construct($baseFile, $pluginVersion)
- {
- $this->baseFile = $baseFile;
- $this->pluginVersion = $pluginVersion;
- }
-
/**
* @param ContainerInterface $container
*
@@ -36,6 +27,8 @@ public function __construct($baseFile, $pluginVersion)
*/
public function run(ContainerInterface $container): bool
{
+ $this->pluginVersion = $container->get('shared.plugin_version');
+ $this->baseFile = M4W_FILE;
add_action(
'init',
[$this, 'pluginInit']
@@ -148,12 +141,6 @@ protected function markUpdatedOrNew()
*/
public function pluginInit()
{
- load_plugin_textdomain(
- 'mollie-payments-for-woocommerce',
- false,
- dirname(plugin_basename($this->baseFile)) . '/languages/'
- );
-
$this->markUpdatedOrNew();
$this->initDb();
}
diff --git a/src/Assets/AssetsModule.php b/src/Assets/AssetsModule.php
index 5e839f478..9512f91fb 100644
--- a/src/Assets/AssetsModule.php
+++ b/src/Assets/AssetsModule.php
@@ -533,7 +533,7 @@ protected function setupModuleActions(ContainerInterface $container): void
$pluginPath = $container->get('shared.plugin_path');
/** @var Settings */
$settingsHelper = $container->get('settings.settings_helper');
- $gatewayInstances = $container->get('gateway.instances');
+ $gatewayInstances = $container->get('__deprecated.gateway_helpers');
/** Add support to Mollie blocks for WooCommerce checkout blocks functionality */
//https://github.com/woocommerce/woocommerce-blocks/blob/trunk/docs/third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md#putting-it-all-together
@@ -588,7 +588,7 @@ function () use ($container, $hasBlocksEnabled, $settingsHelper, $pluginUrl, $pl
if ($hasBlocksEnabled) {
/** @var array */
- $gatewayInstances = $container->get('gateway.instances');
+ $gatewayInstances = $container->get('__deprecated.gateway_helpers');
self::registerBlockScripts($pluginUrl, $pluginPath);
add_action('wp_enqueue_scripts', function () use ($dataService, $gatewayInstances) {
$this->enqueueBlockCheckoutScripts($dataService, $gatewayInstances);
diff --git a/src/Assets/MollieCheckoutBlocksSupport.php b/src/Assets/MollieCheckoutBlocksSupport.php
index 16d2d7481..50fff97ce 100644
--- a/src/Assets/MollieCheckoutBlocksSupport.php
+++ b/src/Assets/MollieCheckoutBlocksSupport.php
@@ -3,8 +3,9 @@
namespace Mollie\WooCommerce\Assets;
use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Gateway\MolliePaymentGatewayI;
+use Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies\DefaultFieldsStrategy;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\Shared\Data;
@@ -75,13 +76,14 @@ public static function localizeWCBlocksData($dataService, $gatewayInstances)
);
}
- public static function gatewayDataForWCBlocks(Data $dataService, array $gatewayInstances): array
+ public static function gatewayDataForWCBlocks(Data $dataService, array $deprecatedGatewayHelpers): array
{
$filters = $dataService->wooCommerceFiltersForCheckout();
$availableGateways = WC()->payment_gateways()->get_available_payment_gateways();
$availablePaymentMethods = [];
+
/**
- * @var MolliePaymentGatewayI $gateway
+ * @var $gateway
* psalm-suppress UnusedForeachValue
*/
foreach ($availableGateways as $key => $gateway) {
@@ -96,7 +98,9 @@ public static function gatewayDataForWCBlocks(Data $dataService, array $gatewayI
) {
$filterKey = "{$filters['amount']['currency']}-{$filters['locale']}-{$filters['billingCountry']}";
foreach ($availableGateways as $key => $gateway) {
- $availablePaymentMethods[$filterKey][$key] = $gateway->paymentMethod()->getProperty('id');
+ $gatewayId = $gateway->id;
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $availablePaymentMethods[$filterKey][$key] = $methodId;
}
}
@@ -110,10 +114,11 @@ public static function gatewayDataForWCBlocks(Data $dataService, array $gatewayI
],
];
$gatewayData = [];
- $isSepaEnabled = isset($gatewayInstances['mollie_wc_gateway_directdebit']) && $gatewayInstances['mollie_wc_gateway_directdebit']->enabled === 'yes';
- /** @var MolliePaymentGateway $gateway */
- foreach ($gatewayInstances as $gatewayKey => $gateway) {
- $method = $gateway->paymentMethod();
+ $isSepaEnabled = isset($deprecatedGatewayHelpers['mollie_wc_gateway_directdebit']) && $deprecatedGatewayHelpers['mollie_wc_gateway_directdebit']->enabled === 'yes';
+ /** @var PaymentGateway $gateway */
+ foreach ($availableGateways as $gatewayKey => $gateway) {
+ $deprecatedGateway = $deprecatedGatewayHelpers[$gatewayKey];
+ $method = $deprecatedGateway->paymentMethod();
$gatewayId = is_string($method->getProperty('id')) ? $method->getProperty('id') : "";
if ($gateway->enabled !== 'yes' || ($gatewayId === 'directdebit' && !is_admin())) {
@@ -122,16 +127,20 @@ public static function gatewayDataForWCBlocks(Data $dataService, array $gatewayI
$content = $method->getProcessedDescriptionForBlock();
$issuers = false;
if ($method->getProperty('paymentFields') === true) {
- $paymentFieldsService = $method->paymentFieldsService();
- $paymentFieldsService->setStrategy($method);
- $issuers = $method->paymentFieldsService()->getStrategyMarkup($gateway);
+ $className = 'Mollie\\WooCommerce\\PaymentMethods\\PaymentFieldsStrategies\\' . ucfirst($method->getProperty('id')) . 'FieldsStrategy';
+ $paymentFieldsStrategy = class_exists($className) ? new $className(
+ $deprecatedGateway,
+ $gateway->get_description(),
+ $dataService
+ ) : new DefaultFieldsStrategy($deprecatedGateway, $gateway->get_description(), $dataService);
+ $issuers = $paymentFieldsStrategy->getFieldMarkup($deprecatedGateway, $dataService);
}
if ($gatewayId === 'creditcard') {
$content .= $issuers;
$issuers = false;
}
$title = $method->title();
- $labelMarkup = "{$title}{$gateway->icon}";
+ $labelMarkup = "{$title}{$gateway->get_icon()}";
$hasSurcharge = $method->hasSurcharge();
$countryCodes = [
'BE' => '+32xxxxxxxxx',
diff --git a/src/Buttons/ApplePayButton/ResponsesToApple.php b/src/Buttons/ApplePayButton/ResponsesToApple.php
index 2f9f34cde..d09608e52 100644
--- a/src/Buttons/ApplePayButton/ResponsesToApple.php
+++ b/src/Buttons/ApplePayButton/ResponsesToApple.php
@@ -14,17 +14,17 @@ class ResponsesToApple
*/
protected $logger;
/**
- * @var MolliePaymentGatewayI
+ * @var
*/
- protected $gateway;
+ protected $deprecatedAppleHelper;
/**
* ResponsesToApple constructor.
*/
- public function __construct(Logger $logger, MolliePaymentGatewayI $appleGateway)
+ public function __construct(Logger $logger, $deprecatedAppleHelper)
{
$this->logger = $logger;
- $this->gateway = $appleGateway;
+ $this->deprecatedAppleHelper = $deprecatedAppleHelper;
}
/**
@@ -126,7 +126,6 @@ private function reorderShippingMethods(array $methods, array $selectedShippingM
return array_merge($reordered_methods, array_values($methods));
}
-
/**
* Returns a success response to be handled by the script
*/
@@ -238,7 +237,7 @@ protected function appleNewLineItemsResponse(array $paymentDetails): array
protected function redirectUrlOnSuccessfulPayment($orderId)
{
$order = wc_get_order($orderId);
- $redirect_url = $this->gateway->getReturnRedirectUrlForOrder($order);
+ $redirect_url = $this->deprecatedAppleHelper->getReturnRedirectUrlForOrder($order);
// Add utm_nooverride query string
$redirect_url = add_query_arg(['utm_nooverride' => 1], $redirect_url);
@@ -246,7 +245,7 @@ protected function redirectUrlOnSuccessfulPayment($orderId)
__METHOD__
. sprintf(
': Redirect url on return order %s, order %s: %s',
- $this->gateway->paymentMethod()->getProperty('id'),
+ $this->deprecatedAppleHelper->paymentMethod()->getProperty('id'),
$orderId,
$redirect_url
)
diff --git a/src/Buttons/PayPalButton/PayPalAjaxRequests.php b/src/Buttons/PayPalButton/PayPalAjaxRequests.php
index 30e65bc31..f6cea621d 100644
--- a/src/Buttons/PayPalButton/PayPalAjaxRequests.php
+++ b/src/Buttons/PayPalButton/PayPalAjaxRequests.php
@@ -4,6 +4,7 @@
namespace Mollie\WooCommerce\Buttons\PayPalButton;
+use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\WooCommerce\Gateway\Surcharge;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Shared\GatewaySurchargeHandler;
@@ -31,7 +32,7 @@ class PayPalAjaxRequests
*
* @param $gateway
*/
- public function __construct($gateway, NoticeInterface $notice, Logger $logger)
+ public function __construct(PaymentGateway $gateway, NoticeInterface $notice, Logger $logger)
{
$this->gateway = $gateway;
$this->notice = $notice;
diff --git a/src/Gateway/DeprecatedGatewayBuilder.php b/src/Gateway/DeprecatedGatewayBuilder.php
new file mode 100644
index 000000000..e2b162759
--- /dev/null
+++ b/src/Gateway/DeprecatedGatewayBuilder.php
@@ -0,0 +1,107 @@
+get(Logger::class);
+ assert($logger instanceof Logger);
+ $notice = $container->get(FrontendNotice::class);
+ assert($notice instanceof FrontendNotice);
+ $mollieOrderService = $container->get(MollieOrderService::class);
+ assert($mollieOrderService instanceof MollieOrderService);
+ $HttpResponseService = $container->get('SDK.HttpResponse');
+ assert($HttpResponseService instanceof HttpResponse);
+ $settingsHelper = $container->get('settings.settings_helper');
+ assert($settingsHelper instanceof Settings);
+ $apiHelper = $container->get('SDK.api_helper');
+ assert($apiHelper instanceof Api);
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $data = $container->get('settings.data_helper');
+ assert($data instanceof Data);
+ $orderInstructionsManager = new OrderInstructionsManager();
+ $mollieObject = $container->get(MollieObject::class);
+ assert($mollieObject instanceof MollieObject);
+ $paymentFactory = $container->get(PaymentFactory::class);
+ assert($paymentFactory instanceof PaymentFactory);
+ $pluginId = $container->get('shared.plugin_id');
+ $gateways = [];
+ if (empty($paymentMethods)) {
+ return $gateways;
+ }
+
+ foreach ($paymentMethods as $paymentMethod) {
+ $paymentMethodId = $paymentMethod->getIdFromConfig();
+ if (! in_array($paymentMethodId, $container->get('gateway.paymentMethodsEnabledAtMollie'))) {
+ continue;
+ }
+ $isSepa = $paymentMethod->getProperty('SEPA');
+ $key = 'mollie_wc_gateway_' . $paymentMethodId;
+ if ($isSepa) {
+ $directDebit = $paymentMethods[Constants::DIRECTDEBIT];
+ $gateways[$key] = new MollieSepaRecurringGatewayHandler(
+ $directDebit,
+ $paymentMethod,
+ $orderInstructionsManager,
+ $mollieOrderService,
+ $data,
+ $logger,
+ $notice,
+ $HttpResponseService,
+ $settingsHelper,
+ $mollieObject,
+ $paymentFactory,
+ $pluginId,
+ $apiHelper
+ );
+ } elseif ($paymentMethod->getProperty('Subscription')) {
+ $gateways[$key] = new MollieSubscriptionGatewayHandler(
+ $paymentMethod,
+ $orderInstructionsManager,
+ $mollieOrderService,
+ $data,
+ $logger,
+ $notice,
+ $HttpResponseService,
+ $settingsHelper,
+ $mollieObject,
+ $paymentFactory,
+ $pluginId,
+ $apiHelper
+ );
+ } else {
+ $gateways[$key] = new MolliePaymentGatewayHandler(
+ $paymentMethod,
+ $orderInstructionsManager,
+ $mollieOrderService,
+ $data,
+ $logger,
+ $notice,
+ $HttpResponseService,
+ $mollieObject,
+ $paymentFactory,
+ $pluginId
+ );
+ }
+ }
+ return $gateways;
+ }
+}
diff --git a/src/Gateway/GatewayModule.php b/src/Gateway/GatewayModule.php
index b8987f101..b42107d22 100644
--- a/src/Gateway/GatewayModule.php
+++ b/src/Gateway/GatewayModule.php
@@ -8,44 +8,23 @@
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
-use DateTime;
use Inpsyde\Modularity\Module\ExecutableModule;
+use Inpsyde\Modularity\Module\ExtendingModule;
use Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
use Inpsyde\Modularity\Module\ServiceModule;
use Mollie\WooCommerce\BlockService\CheckoutBlockService;
-use Mollie\WooCommerce\Buttons\ApplePayButton\AppleAjaxRequests;
use Mollie\WooCommerce\Buttons\ApplePayButton\ApplePayDirectHandler;
-use Mollie\WooCommerce\Buttons\ApplePayButton\ResponsesToApple;
-use Mollie\WooCommerce\Buttons\PayPalButton\DataToPayPal;
-use Mollie\WooCommerce\Buttons\PayPalButton\PayPalAjaxRequests;
use Mollie\WooCommerce\Buttons\PayPalButton\PayPalButtonHandler;
use Mollie\WooCommerce\Gateway\Voucher\MaybeDisableGateway;
-use Mollie\WooCommerce\Notice\AdminNotice;
-use Mollie\WooCommerce\Notice\FrontendNotice;
-use Mollie\WooCommerce\Notice\NoticeInterface;
-use Mollie\WooCommerce\Payment\MollieObject;
-use Mollie\WooCommerce\Payment\MollieOrderService;
-use Mollie\WooCommerce\Payment\OrderInstructionsService;
-use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
-use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentFieldsService;
-use Mollie\WooCommerce\Payment\PaymentService;
use Mollie\WooCommerce\PaymentMethods\IconFactory;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
-use Mollie\WooCommerce\SDK\Api;
-use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\GatewaySurchargeHandler;
-use Mollie\WooCommerce\Shared\SharedDataDictionary;
-use Mollie\WooCommerce\Subscription\MollieSepaRecurringGateway;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
use Mollie\WooCommerce\PaymentMethods\Constants;
use Psr\Container\ContainerInterface;
-use Psr\Log\LoggerInterface as Logger;
-use WP_Post;
-class GatewayModule implements ServiceModule, ExecutableModule
+class GatewayModule implements ServiceModule, ExecutableModule, ExtendingModule
{
use ModuleClassNameIdTrait;
@@ -63,153 +42,6 @@ class GatewayModule implements ServiceModule, ExecutableModule
const FIELD_IN3_BIRTHDATE = 'billing_birthdate';
const GATEWAY_NAME_IN3 = "mollie_wc_gateway_in3";
- public function services(): array
- {
- return [
- 'gateway.classnames' => static function (): array {
- return SharedDataDictionary::GATEWAY_CLASSNAMES;
- },
- 'gateway.instances' => function (ContainerInterface $container): array {
- return $this->instantiatePaymentMethodGateways($container);
- },
- 'gateway.paymentMethods' => static function (ContainerInterface $container): array {
- return (new self())->instantiatePaymentMethods($container);
- },
- 'gateway.paymentMethodsEnabledAtMollie' => static function (ContainerInterface $container): array {
- $dataHelper = $container->get('settings.data_helper');
- assert($dataHelper instanceof Data);
- $settings = $container->get('settings.settings_helper');
- assert($settings instanceof Settings);
- $apiKey = $settings->getApiKey();
- $methods = $apiKey ? $dataHelper->getAllPaymentMethods($apiKey) : [];
- $enabledMethods = [];
- foreach ($methods as $method) {
- $enabledMethods[] = $method['id'];
- }
- return $enabledMethods;
- },
- 'gateway.listAllMethodsAvailable' => static function (ContainerInterface $container): array {
- $dataHelper = $container->get('settings.data_helper');
- assert($dataHelper instanceof Data);
- $settings = $container->get('settings.settings_helper');
- assert($settings instanceof Settings);
- $apiKey = $settings->getApiKey();
- $methods = $apiKey ? $dataHelper->getAllAvailablePaymentMethods() : [];
- $availableMethods = [];
- $implementedMethods = $container->get('gateway.classnames');
- foreach ($methods as $method) {
- if (in_array('Mollie_WC_Gateway_' . ucfirst($method['id']), $implementedMethods, true)) {
- $availableMethods[] = $method;
- }
- }
- return $availableMethods;
- },
- 'gateway.getPaymentMethodsAfterFeatureFlag' => static function (ContainerInterface $container): array {
- $availablePaymentMethods = $container->get('gateway.listAllMethodsAvailable');
- $klarnaOneFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.klarna_one_enabled', true);
- if (!$klarnaOneFlag) {
- $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
- return $method['id'] !== Constants::KLARNA;
- });
- }
- $bancomatpayFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.bancomatpay_enabled', true);
- if (!$bancomatpayFlag) {
- $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
- return $method['id'] !== Constants::BANCOMATPAY;
- });
- }
- $almaFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.alma_enabled', true);
- if (!$almaFlag) {
- $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
- return $method['id'] !== Constants::ALMA;
- });
- }
- $swishFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.swish_enabled', false);
- if (!$swishFlag) {
- $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
- return $method['id'] !== Constants::SWISH;
- });
- }
- return $availablePaymentMethods;
- },
- 'gateway.isSDDGatewayEnabled' => static function (ContainerInterface $container): bool {
- $enabledMethods = $container->get('gateway.paymentMethodsEnabledAtMollie');
- return in_array(Constants::DIRECTDEBIT, $enabledMethods, true);
- },
- IconFactory::class => static function (ContainerInterface $container): IconFactory {
- $pluginUrl = $container->get('shared.plugin_url');
- $pluginPath = $container->get('shared.plugin_path');
- return new IconFactory($pluginUrl, $pluginPath);
- },
- PaymentService::class => static function (ContainerInterface $container): PaymentService {
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $notice = $container->get(AdminNotice::class);
- assert($notice instanceof AdminNotice);
- $paymentFactory = $container->get(PaymentFactory::class);
- assert($paymentFactory instanceof PaymentFactory);
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- $api = $container->get('SDK.api_helper');
- assert($api instanceof Api);
- $settings = $container->get('settings.settings_helper');
- assert($settings instanceof Settings);
- $pluginId = $container->get('shared.plugin_id');
- $paymentCheckoutRedirectService = $container->get(PaymentCheckoutRedirectService::class);
- assert($paymentCheckoutRedirectService instanceof PaymentCheckoutRedirectService);
- $voucherDefaultCategory = $container->get('voucher.defaultCategory');
- return new PaymentService($notice, $logger, $paymentFactory, $data, $api, $settings, $pluginId, $paymentCheckoutRedirectService, $voucherDefaultCategory);
- },
- OrderInstructionsService::class => static function (): OrderInstructionsService {
- return new OrderInstructionsService();
- },
- PaymentFieldsService::class => static function (ContainerInterface $container): PaymentFieldsService {
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- return new PaymentFieldsService($data);
- },
- PaymentCheckoutRedirectService::class => static function (
- ContainerInterface $container
- ): PaymentCheckoutRedirectService {
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- return new PaymentCheckoutRedirectService($data);
- },
- Surcharge::class => static function (ContainerInterface $container): Surcharge {
- return new Surcharge();
- },
- MollieOrderService::class => static function (ContainerInterface $container): MollieOrderService {
- $HttpResponseService = $container->get('SDK.HttpResponse');
- assert($HttpResponseService instanceof HttpResponse);
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $paymentFactory = $container->get(PaymentFactory::class);
- assert($paymentFactory instanceof PaymentFactory);
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- $pluginId = $container->get('shared.plugin_id');
- return new MollieOrderService($HttpResponseService, $logger, $paymentFactory, $data, $pluginId);
- },
- OrderMandatoryGatewayDisabler::class => static function (ContainerInterface $container): OrderMandatoryGatewayDisabler {
- $settings = $container->get('settings.settings_helper');
- assert($settings instanceof Settings);
- $isSettingsOrderApi = $settings->isOrderApiSetting();
- return new OrderMandatoryGatewayDisabler($isSettingsOrderApi);
- },
- 'gateway.isBillieEnabled' => static function (ContainerInterface $container): bool {
- $settings = $container->get('settings.settings_helper');
- assert($settings instanceof Settings);
- $isSettingsOrderApi = $settings->isOrderApiSetting();
- $billie = isset($container->get('gateway.paymentMethods')['billie']) ? $container->get('gateway.paymentMethods')['billie'] : null;
- $isBillieEnabled = false;
- if ($billie instanceof PaymentMethodI) {
- $isBillieEnabled = $billie->getProperty('enabled') === 'yes';
- }
- return $isSettingsOrderApi && $isBillieEnabled;
- },
- ];
- }
-
public function run(ContainerInterface $container): bool
{
$this->pluginId = $container->get('shared.plugin_id');
@@ -217,11 +49,6 @@ public function run(ContainerInterface $container): bool
add_filter($this->pluginId . '_retrieve_payment_gateways', function () {
return $this->gatewayClassnames;
});
-
- add_filter('woocommerce_payment_gateways', static function ($gateways) use ($container) {
- $mollieGateways = $container->get('gateway.instances');
- return array_merge($gateways, $mollieGateways);
- });
add_filter('woocommerce_payment_gateways', static function ($gateways) use ($container) {
$orderMandatoryGatewayDisabler = $container->get(OrderMandatoryGatewayDisabler::class);
assert($orderMandatoryGatewayDisabler instanceof OrderMandatoryGatewayDisabler);
@@ -229,14 +56,43 @@ public function run(ContainerInterface $container): bool
});
add_filter('woocommerce_payment_gateways', static function ($gateways) {
$maybeEnablegatewayHelper = new MaybeDisableGateway();
-
+ $gateways = $maybeEnablegatewayHelper->maybeDisableBankTransferGateway($gateways);
return $maybeEnablegatewayHelper->maybeDisableMealVoucherGateway($gateways);
});
+
add_filter(
'woocommerce_payment_gateways',
- [$this, 'maybeDisableBankTransferGateway'],
- 20
+ static function ($gateways) use ($container) {
+ $deprecatedGatewayHelpers = $container->get('__deprecated.gateway_helpers');
+ foreach ($gateways as $gateway) {
+ $isMolliegateway = is_string($gateway) && strpos($gateway, 'mollie_wc_gateway_') !== false
+ || is_object($gateway) && strpos($gateway->id, 'mollie_wc_gateway_') !== false;
+ if (!$isMolliegateway) {
+ continue;
+ }
+ // Add subscription filters after payment gateways are loaded
+ $isSubscriptiongateway = $gateway->supports('subscriptions');
+ if ($isSubscriptiongateway) {
+ $deprecatedGatewayHelpers[$gateway->id]->addSubscriptionFilters($gateway);
+ }
+
+ // Add payment instructions
+ $displayInstructionsService = $container->get('gateway.hooks.displayInstructions');
+ $displayInstructionsService($gateway);
+ // Add thankyou page actions for gateway
+ $thankyouPageService = $container->get('gateway.hooks.thankyouPage');
+ if (!has_action('woocommerce_thankyou_' . $gateway->id)) {
+ $thankyouPageService($gateway);
+ }
+ // Add subscription payment hooks
+ $isSubscriptionPaymentService = $container->get('gateway.hooks.isSubscriptionPayment');
+ $isSubscriptionPaymentService($gateway);
+ }
+ return $gateways;
+ },
+ 30
);
+
// Disable SEPA as payment option in WooCommerce checkout
add_filter(
'woocommerce_available_payment_gateways',
@@ -294,31 +150,12 @@ static function () {
// Set order to paid and processed when eventually completed without Mollie
add_action('woocommerce_payment_complete', [$this, 'setOrderPaidByOtherGateway'], 10, 1);
- $appleGateway = isset($container->get('gateway.instances')['mollie_wc_gateway_applepay']) ? $container->get(
- 'gateway.instances'
- )['mollie_wc_gateway_applepay'] : false;
- $notice = $container->get(AdminNotice::class);
- assert($notice instanceof AdminNotice);
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $pluginUrl = $container->get('shared.plugin_url');
- $apiHelper = $container->get('SDK.api_helper');
- assert($apiHelper instanceof Api);
- $settingsHelper = $container->get('settings.settings_helper');
- assert($settingsHelper instanceof Settings);
+
$surchargeService = $container->get(Surcharge::class);
assert($surchargeService instanceof Surcharge);
$this->gatewaySurchargeHandling($surchargeService);
- if ($appleGateway) {
- $this->mollieApplePayDirectHandling($notice, $logger, $apiHelper, $settingsHelper, $appleGateway);
- }
- $paypalGateway = isset($container->get('gateway.instances')['mollie_wc_gateway_paypal']) ? $container->get(
- 'gateway.instances'
- )['mollie_wc_gateway_paypal'] : false;
- if ($paypalGateway) {
- $this->molliePayPalButtonHandling($paypalGateway, $notice, $logger, $pluginUrl);
- }
+ $this->paymentButtonsBootstrap($container);
$maybeDisableVoucher = new MaybeDisableGateway();
$dataService = $container->get('settings.data_helper');
@@ -349,9 +186,35 @@ static function ($paymentContext) {
}
return $fields;
}, 10, 3);
+
return true;
}
+ public function services(): array
+ {
+ static $services;
+
+ if ($services === null) {
+ $services = require_once __DIR__ . '/inc/services.php';
+ }
+
+ return $services();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function extensions(): array
+ {
+ static $extensions;
+
+ if ($extensions === null) {
+ $extensions = require_once __DIR__ . '/inc/extensions.php';
+ }
+
+ return $extensions();
+ }
+
/**
* @param Object $post
* @return void
@@ -377,49 +240,6 @@ public function addShopOrderMetabox(object $post)
}, $screen, 'side', 'high');
}
- /**
- * Disable Bank Transfer Gateway
- *
- * @param ?array $gateways
- * @return array
- */
- public function maybeDisableBankTransferGateway(?array $gateways): array
- {
- if (!is_array($gateways)) {
- return [];
- }
- $isWcApiRequest = (bool)filter_input(INPUT_GET, 'wc-api', FILTER_SANITIZE_SPECIAL_CHARS);
-
- $bankTransferSettings = get_option('mollie_wc_gateway_banktransfer_settings', false);
- //If the setting is active is forced Payment API so we need to filter the gateway when order is in pay-page
- // as it might have been created with Orders API
- $isActiveExpiryDate = $bankTransferSettings
- && isset($bankTransferSettings['activate_expiry_days_setting'])
- && $bankTransferSettings['activate_expiry_days_setting'] === "yes"
- && isset($bankTransferSettings['order_dueDate'])
- && $bankTransferSettings['order_dueDate'] > 0;
-
- /*
- * There is only one case where we want to filter the gateway and it's when the
- * pay-page render the available payments methods AND the setting is enabled
- *
- * For any other case we want to be sure bank transfer gateway is included.
- */
- if (
- $isWcApiRequest ||
- !$isActiveExpiryDate ||
- is_checkout() && ! is_wc_endpoint_url('order-pay') ||
- !wp_doing_ajax() && ! is_wc_endpoint_url('order-pay') ||
- is_admin()
- ) {
- return $gateways;
- }
- $bankTransferGatewayClassName = 'mollie_wc_gateway_banktransfer';
- unset($gateways[$bankTransferGatewayClassName]);
-
- return $gateways;
- }
-
public function gatewaySurchargeHandling(Surcharge $surcharge)
{
new GatewaySurchargeHandler($surcharge);
@@ -483,132 +303,32 @@ public function setOrderPaidByOtherGateway($order_id)
}
/**
- * Bootstrap the ApplePay button logic if feature enabled
+ * @param ContainerInterface $container
+ * @return void
+ * @throws \Psr\Container\ContainerExceptionInterface
+ * @throws \Psr\Container\NotFoundExceptionInterface
*/
- public function mollieApplePayDirectHandling(NoticeInterface $notice, Logger $logger, Api $apiHelper, Settings $settingsHelper, MollieSubscriptionGateway $appleGateway)
+ public function paymentButtonsBootstrap(ContainerInterface $container): void
{
- $buttonEnabledCart = mollieWooCommerceIsApplePayDirectEnabled('cart');
- $buttonEnabledProduct = mollieWooCommerceIsApplePayDirectEnabled('product');
-
- if ($buttonEnabledCart || $buttonEnabledProduct) {
- $notices = new AdminNotice();
- $responseTemplates = new ResponsesToApple($logger, $appleGateway);
- $ajaxRequests = new AppleAjaxRequests($responseTemplates, $notice, $logger, $apiHelper, $settingsHelper);
- $applePayHandler = new ApplePayDirectHandler($notices, $ajaxRequests);
- $applePayHandler->bootstrap($buttonEnabledProduct, $buttonEnabledCart);
- }
- }
-
- /**
- * Bootstrap the Mollie_WC_Gateway_PayPal button logic if feature enabled
- */
- public function molliePayPalButtonHandling(
- $gateway,
- NoticeInterface $notice,
- Logger $logger,
- string $pluginUrl
- ) {
-
- $enabledInProduct = (mollieWooCommerceIsPayPalButtonEnabled('product'));
- $enabledInCart = (mollieWooCommerceIsPayPalButtonEnabled('cart'));
- $shouldBuildIt = $enabledInProduct || $enabledInCart;
-
- if ($shouldBuildIt) {
- $ajaxRequests = new PayPalAjaxRequests($gateway, $notice, $logger);
- $data = new DataToPayPal($pluginUrl);
- $payPalHandler = new PayPalButtonHandler($ajaxRequests, $data);
- $payPalHandler->bootstrap($enabledInProduct, $enabledInCart);
+ $applePayDirectHandler = $container->get(ApplePayDirectHandler::class);
+ if ($applePayDirectHandler instanceof ApplePayDirectHandler) {
+ $buttonEnabledCart = mollieWooCommerceIsApplePayDirectEnabled('cart');
+ $buttonEnabledProduct = mollieWooCommerceIsApplePayDirectEnabled('product');
+ if ($buttonEnabledCart || $buttonEnabledProduct) {
+ $applePayDirectHandler->bootstrap($buttonEnabledProduct, $buttonEnabledCart);
+ }
}
- }
- public function instantiatePaymentMethodGateways(ContainerInterface $container): array
- {
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $notice = $container->get(FrontendNotice::class);
- assert($notice instanceof FrontendNotice);
- $paymentService = $container->get(PaymentService::class);
- assert($paymentService instanceof PaymentService);
- $mollieOrderService = $container->get(MollieOrderService::class);
- assert($mollieOrderService instanceof MollieOrderService);
- $HttpResponseService = $container->get('SDK.HttpResponse');
- assert($HttpResponseService instanceof HttpResponse);
- $settingsHelper = $container->get('settings.settings_helper');
- assert($settingsHelper instanceof Settings);
- $apiHelper = $container->get('SDK.api_helper');
- assert($apiHelper instanceof Api);
- $paymentMethods = $container->get('gateway.paymentMethods');
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- $orderInstructionsService = new OrderInstructionsService();
- $mollieObject = $container->get(MollieObject::class);
- assert($mollieObject instanceof MollieObject);
- $paymentFactory = $container->get(PaymentFactory::class);
- assert($paymentFactory instanceof PaymentFactory);
- $pluginId = $container->get('shared.plugin_id');
- $gateways = [];
- if (empty($paymentMethods)) {
- return $gateways;
- }
+ $paypalButtonHandler = $container->get(PayPalButtonHandler::class);
+ if ($paypalButtonHandler instanceof PayPalButtonHandler) {
+ $enabledInProduct = (mollieWooCommerceIsPayPalButtonEnabled('product'));
+ $enabledInCart = (mollieWooCommerceIsPayPalButtonEnabled('cart'));
+ $shouldBuildIt = $enabledInProduct || $enabledInCart;
- foreach ($paymentMethods as $paymentMethod) {
- $paymentMethodId = $paymentMethod->getIdFromConfig();
- if (! in_array($paymentMethodId, $container->get('gateway.paymentMethodsEnabledAtMollie'))) {
- continue;
- }
- $isSepa = $paymentMethod->getProperty('SEPA');
- $key = 'mollie_wc_gateway_' . $paymentMethodId;
- if ($isSepa) {
- $directDebit = $paymentMethods[Constants::DIRECTDEBIT];
- $gateways[$key] = new MollieSepaRecurringGateway(
- $directDebit,
- $paymentMethod,
- $paymentService,
- $orderInstructionsService,
- $mollieOrderService,
- $data,
- $logger,
- $notice,
- $HttpResponseService,
- $settingsHelper,
- $mollieObject,
- $paymentFactory,
- $pluginId,
- $apiHelper
- );
- } elseif ($paymentMethod->getProperty('Subscription')) {
- $gateways[$key] = new MollieSubscriptionGateway(
- $paymentMethod,
- $paymentService,
- $orderInstructionsService,
- $mollieOrderService,
- $data,
- $logger,
- $notice,
- $HttpResponseService,
- $settingsHelper,
- $mollieObject,
- $paymentFactory,
- $pluginId,
- $apiHelper
- );
- } else {
- $gateways[$key] = new MolliePaymentGateway(
- $paymentMethod,
- $paymentService,
- $orderInstructionsService,
- $mollieOrderService,
- $data,
- $logger,
- $notice,
- $HttpResponseService,
- $mollieObject,
- $paymentFactory,
- $pluginId
- );
+ if ($shouldBuildIt) {
+ $paypalButtonHandler->bootstrap($enabledInProduct, $enabledInCart);
}
}
- return $gateways;
}
/**
@@ -625,15 +345,12 @@ protected function instantiatePaymentMethods($container): array
assert($settingsHelper instanceof Settings);
$surchargeService = $container->get(Surcharge::class);
assert($surchargeService instanceof Surcharge);
- $paymentFieldsService = $container->get(PaymentFieldsService::class);
- assert($paymentFieldsService instanceof PaymentFieldsService);
foreach ($listAllAvailablePaymentMethods as $paymentMethodAvailable) {
$paymentMethodId = $paymentMethodAvailable['id'];
$paymentMethods[$paymentMethodId] = $this->buildPaymentMethod(
$paymentMethodId,
$iconFactory,
$settingsHelper,
- $paymentFieldsService,
$surchargeService,
$paymentMethodAvailable
);
@@ -646,13 +363,39 @@ protected function instantiatePaymentMethods($container): array
$paymentMethodId,
$iconFactory,
$settingsHelper,
- $paymentFieldsService,
$surchargeService,
[]
);
}
return $paymentMethods;
}
+ /**
+ * @param string $id
+ * @param IconFactory $iconFactory
+ * @param Settings $settingsHelper
+ * @param Surcharge $surchargeService
+ * @param array $paymentMethods
+ * @return PaymentMethodI | array
+ */
+ public function buildPaymentMethod(
+ string $id,
+ IconFactory $iconFactory,
+ Settings $settingsHelper,
+ Surcharge $surchargeService,
+ array $apiMethod
+ ) {
+
+ $transformedId = ucfirst($id);
+ $paymentMethodClassName = 'Mollie\\WooCommerce\\PaymentMethods\\' . $transformedId;
+ $paymentMethod = new $paymentMethodClassName(
+ $iconFactory,
+ $settingsHelper,
+ $surchargeService,
+ $apiMethod
+ );
+
+ return $paymentMethod;
+ }
public function BillieFieldsMandatory($fields, $errors)
{
@@ -690,37 +433,6 @@ public function in3FieldsMandatoryPayForOrder($order)
}
}
- /**
- * @param string $id
- * @param IconFactory $iconFactory
- * @param Settings $settingsHelper
- * @param PaymentFieldsService $paymentFieldsService
- * @param Surcharge $surchargeService
- * @param array $paymentMethods
- * @return PaymentMethodI | array
- */
- public function buildPaymentMethod(
- string $id,
- IconFactory $iconFactory,
- Settings $settingsHelper,
- PaymentFieldsService $paymentFieldsService,
- Surcharge $surchargeService,
- array $apiMethod
- ) {
-
- $transformedId = ucfirst($id);
- $paymentMethodClassName = 'Mollie\\WooCommerce\\PaymentMethods\\' . $transformedId;
- $paymentMethod = new $paymentMethodClassName(
- $iconFactory,
- $settingsHelper,
- $paymentFieldsService,
- $surchargeService,
- $apiMethod
- );
-
- return $paymentMethod;
- }
-
/**
* Some payment methods require mandatory fields, this function will add them to the checkout fields array
* @param $fields
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGatewayHandler.php
similarity index 53%
rename from src/Gateway/MolliePaymentGateway.php
rename to src/Gateway/MolliePaymentGatewayHandler.php
index 18ef627a6..1473714dc 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGatewayHandler.php
@@ -5,16 +5,13 @@
namespace Mollie\WooCommerce\Gateway;
use InvalidArgumentException;
-use Mollie\Api\Exceptions\ApiException;
-use Mollie\Api\Resources\Method;
use Mollie\Api\Resources\Payment;
-use Mollie\Api\Types\SequenceType;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\MollieOrderService;
-use Mollie\WooCommerce\Payment\OrderInstructionsService;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
+use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\Shared\Data;
@@ -22,10 +19,8 @@
use Psr\Log\LoggerInterface as Logger;
use UnexpectedValueException;
use WC_Order;
-use WC_Payment_Gateway;
-use WP_Error;
-class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGatewayI
+class MolliePaymentGatewayHandler
{
/**
* @var bool
@@ -35,13 +30,13 @@ class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGa
/**
* Recurring total, zero does not define a recurring total
*
- * @var int
+ * @var array
*/
- protected $recurring_totals = 0;
+ protected $recurring_totals = [];
/**
* @var PaymentMethodI
*/
- protected $paymentMethod;
+ protected PaymentMethodI $paymentMethod;
/**
* @var string
*/
@@ -54,10 +49,7 @@ class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGa
* @var NoticeInterface
*/
protected $notice;
- /**
- * @var PaymentService
- */
- protected $paymentService;
+
/**
* @var MollieOrderService
*/
@@ -67,9 +59,9 @@ class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGa
*/
protected $httpResponse;
/**
- * @var OrderInstructionsService
+ * @var OrderInstructionsManager
*/
- protected $orderInstructionsService;
+ protected $orderInstructionsManager;
/**
* @var Data
*/
@@ -87,13 +79,15 @@ class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGa
*/
protected $pluginId;
+ public string $enabled;
+ public string $id;
+
/**
*
*/
public function __construct(
PaymentMethodI $paymentMethod,
- PaymentService $paymentService,
- OrderInstructionsService $orderInstructionsService,
+ OrderInstructionsManager $orderInstructionsProcessor,
MollieOrderService $mollieOrderService,
Data $dataService,
Logger $logger,
@@ -107,8 +101,7 @@ public function __construct(
$this->paymentMethod = $paymentMethod;
$this->logger = $logger;
$this->notice = $notice;
- $this->paymentService = $paymentService;
- $this->orderInstructionsService = $orderInstructionsService;
+ $this->orderInstructionsManager = $orderInstructionsProcessor;
$this->mollieOrderService = $mollieOrderService;
$this->httpResponse = $httpResponse;
$this->dataService = $dataService;
@@ -116,53 +109,15 @@ public function __construct(
$this->paymentFactory = $paymentFactory;
$this->pluginId = $pluginId;
- // No plugin id, gateway id is unique enough
- $this->plugin_id = '';
// Use gateway class name as gateway id
$this->gatewayId();
- // Set gateway title (visible in admin)
- $this->method_title = 'Mollie - ' . $this->paymentMethod->title();
- $this->method_description = $this->paymentMethod->getProperty(
- 'settingsDescription'
- );
- $this->supports = $this->paymentMethod->getProperty('supports');
-
- // Load the settings.
- $this->init_form_fields();
- $this->init_settings();
- $this->title = $this->paymentMethod->title();
- $this->initDescription();
- $this->initIcon();
-
- if (!has_action('woocommerce_thankyou_' . $this->id)) {
- add_action(
- 'woocommerce_thankyou_' . $this->id,
- [$this, 'thankyou_page']
- );
- }
$this->mollieOrderService->setGateway($this);
add_action(
'woocommerce_api_' . $this->id,
[$this->mollieOrderService, 'onWebhookAction']
);
- add_action(
- 'woocommerce_update_options_payment_gateways_' . $this->id,
- [$this, 'process_admin_options']
- );
- add_action(
- 'woocommerce_email_after_order_table',
- [$this, 'displayInstructions'],
- 10,
- 3
- );
- add_action(
- 'woocommerce_email_order_meta',
- [$this, 'displayInstructions'],
- 10,
- 3
- );
// Adjust title and text on Order Received page in some cases, see issue #166
add_filter('the_title', [$this, 'onOrderReceivedTitle'], 10, 2);
@@ -172,14 +127,13 @@ public function __construct(
10,
2
);
- $this->gatewayHasFields();
$isEnabledAtWoo = $this->paymentMethod->getProperty('enabled') ?
$this->paymentMethod->getProperty('enabled') :
'yes';
$this->enabled = $isEnabledAtWoo;
- if ($this->enabled && $this->paymentMethod->getProperty('filtersOnBuild')) {
+ if ($this->enabled === 'yes' && $this->paymentMethod->getProperty('filtersOnBuild')) {
$this->paymentMethod->filtersOnBuild();
}
}
@@ -189,11 +143,6 @@ public function paymentMethod(): PaymentMethodI
return $this->paymentMethod;
}
- public function paymentService()
- {
- return $this->paymentService;
- }
-
public function dataService()
{
return $this->dataService;
@@ -204,23 +153,6 @@ public function pluginId()
return $this->pluginId;
}
- public function initIcon()
- {
- if ($this->paymentMethod->shouldDisplayIcon()) {
- $defaultIcon = $this->paymentMethod->getIconUrl();
- $this->icon = apply_filters(
- $this->id . '_icon_url',
- $defaultIcon
- );
- }
- }
-
- public function get_icon()
- {
- $output = $this->icon ?: '';
- return apply_filters('woocommerce_gateway_icon', $output, $this->id);
- }
-
protected function gatewayId()
{
$paymentMethodId = $this->paymentMethod->getProperty('id');
@@ -228,213 +160,21 @@ protected function gatewayId()
return $this->id;
}
- /**
- * Initialise Gateway Settings Form Fields
- */
- public function init_form_fields()
- {
- $this->form_fields = $this->paymentMethod->getAllFormFields();
- }
-
- /**
- * Display fields below payment method in checkout
- */
- public function payment_fields()
- {
- // Display description above issuers
- parent::payment_fields();
- $this->paymentMethod->paymentFieldsStrategy($this);
- }
-
- /**
- * Save settings
- *
- * @since 1.0
- */
- public function init_settings()
- {
- parent::init_settings();
- }
-
- protected function initDescription()
- {
- $description = $this->paymentMethod->getProcessedDescription();
- $this->description = empty($description) ? false : $description;
- }
-
- /**
- * Check if this gateway can be used
- *
- * @return bool
- */
- public function isValidForUse(): bool
- {
- if (is_admin()) {
- if (!$this->dataService->isValidApiKeyProvided()) {
- $test_mode = $this->dataService->isTestModeEnabled();
-
- $this->errors[] = ($test_mode ? __(
- 'Test mode enabled.',
- 'mollie-payments-for-woocommerce'
- ) . ' ' : '') . sprintf(
- /* translators: The surrounding %s's Will be replaced by a link to the global setting page */
- __(
- 'No API key provided. Please %1$sset you Mollie API key%2$s first.',
- 'mollie-payments-for-woocommerce'
- ),
- '',
- ''
- );
-
- return false;
- }
-
- // This should be simpler, check for specific payment method in settings, not on all pages
- if (null === $this->getMollieMethod()) {
- $this->errors[] = sprintf(
- /* translators: Placeholder 1: payment method title. The surrounding %s's Will be replaced by a link to the Mollie profile */
- __(
- '%1$s not enabled in your Mollie profile. You can enable it by editing your %2$sMollie profile%3$s.',
- 'mollie-payments-for-woocommerce'
- ),
- $this->paymentMethod->getProperty('defaultTitle'),
- '',
- ''
- );
-
- return false;
- }
-
- if (!$this->isCurrencySupported()) {
- $this->errors[] = sprintf(
- /* translators: Placeholder 1: WooCommerce currency, placeholder 2: Supported Mollie currencies */
- __(
- 'Current shop currency %1$s not supported by Mollie. Read more about %2$ssupported currencies and payment methods.%3$s ',
- 'mollie-payments-for-woocommerce'
- ),
- get_woocommerce_currency(),
- '',
- ''
- );
-
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * @return Method|null
- */
- public function getMollieMethod()
- {
- return $this->dataService->getPaymentMethod(
- $this->paymentMethod->getProperty('id')
- );
- }
-
- /**
- * @return bool
- */
- protected function isCurrencySupported(): bool
- {
- return in_array(
- get_woocommerce_currency(),
- $this->getSupportedCurrencies(),
- true
- );
- }
-
- /**
- * @return array
- */
- protected function getSupportedCurrencies(): array
- {
- $default = [
- 'AUD',
- 'BGN',
- 'BRL',
- 'CAD',
- 'CHF',
- 'CZK',
- 'DKK',
- 'EUR',
- 'GBP',
- 'HKD',
- 'HRK',
- 'HUF',
- 'ILS',
- 'ISK',
- 'JPY',
- 'MXN',
- 'MYR',
- 'NOK',
- 'NZD',
- 'PHP',
- 'PLN',
- 'RON',
- 'RUB',
- 'SEK',
- 'SGD',
- 'THB',
- 'TWD',
- 'USD',
- ];
-
- return apply_filters(
- 'woocommerce_' . $this->id . '_supported_currencies',
- $default
- );
- }
-
- /**
- * Save options in admin.
- */
- public function process_admin_options()
- {
- $this->dataService->processSettings($this);
-
- parent::process_admin_options();
- }
-
- public function admin_options()
- {
- $this->dataService->processAdminOptions($this);
- }
-
- /**
- * Validates the multiselect country field.
- * Overrides the one called by get_field_value() on WooCommerce abstract-wc-settings-api.php
- *
- * @param $key
- * @param $value
- *
- * @return array|string
- */
- public function validate_multi_select_countries_field($key, $value)
- {
- return is_array($value) ? array_map(
- 'wc_clean',
- array_map('stripslashes', $value)
- ) : '';
- }
-
/**
* Check if the gateway is available for use
*
* @return bool
*/
- public function is_available(): bool
+ public function is_available($gateway): bool
{
- if (!$this->checkEnabledNorDirectDebit()) {
+ if (!$this->checkEnabledNorDirectDebit($gateway)) {
return false;
}
if (!$this->cartAmountAvailable()) {
return true;
}
- $order_total = $this->get_order_total();
+ $order_total = WC()->cart ? WC()->cart->get_total('edit') : 0;
$currency = $this->getCurrencyFromOrder();
$billingCountry = $this->getBillingCountry();
$paymentLocale = $this->dataService->getPaymentLocale();
@@ -511,23 +251,6 @@ public function get_recurring_total()
return $this->recurring_totals;
}
- /**
- * @param int $orderId
- *
- * @return array
- */
- public function process_payment($orderId)
- {
- $order = wc_get_order($orderId);
- if (!$order) {
- return $this->noOrderPaymentFailure($orderId);
- }
- $paymentMethod = $this->paymentMethod;
- $redirectUrl = $this->get_return_url($order);
- $this->paymentService->setGateway($this);
- return $this->paymentService->processPayment($orderId, $order, $paymentMethod, $redirectUrl);
- }
-
/**
* @param $order
* @param $payment
@@ -559,7 +282,8 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
. " {$order_id}: Determine what the redirect URL in WooCommerce should be.";
$this->logger->debug($debugLine);
$hookReturnPaymentStatus = 'success';
- $returnRedirect = $this->get_return_url($order);
+ $gateway = wc_get_payment_gateway_by_order($order);
+ $returnRedirect = $gateway->get_return_url($order);
$failedRedirect = $order->get_checkout_payment_url(false);
$this->mollieOrderService->setGateway($this);
@@ -575,7 +299,7 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
// order being cancelled. Otherwise redirect to /checkout/order-pay/ so
// customers can try to pay with another payment method.
if ($order_status_cancelled_payments === 'cancelled') {
- return $this->get_return_url($order);
+ return $returnRedirect;
} else {
$this->notice->addNotice(
'error',
@@ -634,38 +358,15 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
/*
* Return to order received page
*/
- return $this->get_return_url($order);
+ return $returnRedirect;
}
- /**
- * @param $orderId
- * @return string[]
- */
- protected function noOrderPaymentFailure($orderId): array
- {
- $this->logger->debug(
- $this->id . ': Could not process payment, order ' . $orderId . ' not found.'
- );
-
- $this->notice->addNotice(
- 'error',
- sprintf(
- /* translators: Placeholder 1: order id. */
- __(
- 'Could not load order %s',
- 'mollie-payments-for-woocommerce'
- ),
- $orderId
- )
- );
- return ['result' => 'failure'];
- }
/**
* Retrieve the payment object
*
* @return MollieObject
*/
- protected function paymentObject(): MollieObject
+ public function paymentObject(): MollieObject
{
return $this->mollieObject;
}
@@ -679,7 +380,7 @@ protected function paymentObject(): MollieObject
* @return Payment
* @throws UnexpectedValueException
*/
- protected function activePaymentObject($orderId, $useCache): Payment
+ public function activePaymentObject($orderId, $useCache): Payment
{
$paymentObject = $this->paymentObject();
$activePaymentObject = $paymentObject->getActiveMolliePayment(
@@ -696,180 +397,6 @@ protected function activePaymentObject($orderId, $useCache): Payment
return $activePaymentObject;
}
- /**
- * Process a refund if supported
- *
- * @param int $order_id
- * @param float $amount
- * @param string $reason
- *
- * @return bool|wp_error True or false based on success, or a WP_Error object
- * @since WooCommerce 2.2
- */
- public function process_refund($order_id, $amount = null, $reason = '')
- {
- // Get the WooCommerce order
- $order = wc_get_order($order_id);
-
- // WooCommerce order not found
- if (!$order) {
- $error_message = "Could not find WooCommerce order $order_id.";
-
- $this->logger->debug(
- __METHOD__ . ' - ' . $error_message
- );
-
- return new WP_Error('1', $error_message);
- }
-
- // Check if there is a Mollie Payment Order object connected to this WooCommerce order
- $payment_object_id = $this->paymentObject()->getActiveMollieOrderId(
- $order_id
- );
-
- // If there is no Mollie Payment Order object, try getting a Mollie Payment Payment object
- if (!$payment_object_id) {
- $payment_object_id = $this->paymentObject()
- ->getActiveMolliePaymentId($order_id);
- }
-
- // Mollie Payment object not found
- if (!$payment_object_id) {
- $error_message = "Can\'t process refund. Could not find Mollie Payment object id for order $order_id.";
-
- $this->logger->debug(
- __METHOD__ . ' - ' . $error_message
- );
-
- return new WP_Error('1', $error_message);
- }
-
- try {
- $payment_object = $this->paymentFactory
- ->getPaymentObject(
- $payment_object_id
- );
- } catch (ApiException $exception) {
- $exceptionMessage = $exception->getMessage();
- $this->logger->debug($exceptionMessage);
- return new WP_Error('error', $exceptionMessage);
- }
-
- if (!$payment_object) {
- $error_message = "Can\'t process refund. Could not find Mollie Payment object data for order $order_id.";
-
- $this->logger->debug(
- __METHOD__ . ' - ' . $error_message
- );
-
- return new WP_Error('1', $error_message);
- }
-
- return $payment_object->refund(
- $order,
- $order_id,
- $payment_object,
- $amount,
- $reason
- );
- }
-
- /**
- * Output for the order received page.
- */
- public function thankyou_page($order_id)
- {
- $order = wc_get_order($order_id);
-
- // Order not found
- if (!$order) {
- return;
- }
-
- // Empty cart
- if (WC()->cart) {
- WC()->cart->empty_cart();
- }
-
- // Same as email instructions, just run that
- $this->displayInstructions(
- $order,
- $admin_instructions = false,
- $plain_text = false
- );
- }
-
- /**
- * Add content to the WC emails.
- *
- * @param WC_Order $order
- * @param bool $admin_instructions (default: false)
- * @param bool $plain_text (default: false)
- *
- * @return void
- */
- public function displayInstructions(
- WC_Order $order,
- $admin_instructions = false,
- $plain_text = false
- ) {
-
- if (
- ($admin_instructions && !$this::$alreadyDisplayedAdminInstructions)
- || (!$admin_instructions && !$this::$alreadyDisplayedCustomerInstructions)
- ) {
- $order_payment_method = $order->get_payment_method();
-
- // Invalid gateway
- if ($this->id !== $order_payment_method) {
- return;
- }
-
- $payment = $this->paymentObject()->getActiveMolliePayment(
- $order->get_id()
- );
-
- // Mollie payment not found or invalid gateway
- if (
- !$payment
- || $payment->method !== $this->paymentMethod->getProperty('id')
- ) {
- return;
- }
- $this->orderInstructionsService->setStrategy($this);
- $instructions = $this->orderInstructionsService->executeStrategy(
- $this,
- $payment,
- $order,
- $admin_instructions
- );
-
- if (!empty($instructions)) {
- $instructions = wptexturize($instructions);
- //save instructions in order meta
- $order->update_meta_data(
- '_mollie_payment_instructions',
- $instructions
- );
- $order->save();
-
- if ($plain_text) {
- echo esc_html($instructions) . PHP_EOL;
- } else {
- echo '';
- echo wp_kses(wpautop($instructions), ['p' => [], 'strong' => [], 'br' => []]) . PHP_EOL;
- echo '';
- }
- }
- }
- if ($admin_instructions && !$this::$alreadyDisplayedAdminInstructions) {
- $this::$alreadyDisplayedAdminInstructions = true;
- }
- if (!$admin_instructions && !$this::$alreadyDisplayedCustomerInstructions) {
- $this::$alreadyDisplayedCustomerInstructions = true;
- }
- }
-
/**
* @param $title
* @param null $id
@@ -879,12 +406,11 @@ public function displayInstructions(
public function onOrderReceivedTitle($title, $id = null)
{
if (is_order_received_page() && get_the_ID() === $id) {
- global $wp;
-
$order = false;
+ $orderReceived = get_query_var('order-received');
$order_id = apply_filters(
'woocommerce_thankyou_order_id',
- absint($wp->query_vars['order-received'])
+ absint($orderReceived)
);
$order_key = apply_filters(
'woocommerce_thankyou_order_key',
@@ -1009,17 +535,6 @@ public function onOrderReceivedText($text, $order)
return $text;
}
- /**
- * @return string|NULL
- */
- public function getSelectedIssuer(): ?string
- {
- $issuer_id = $this->pluginId . '_issuer_' . $this->id;
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $postedIssuer = wc_clean(wp_unslash($_POST[$issuer_id] ?? ''));
- return !empty($postedIssuer) ? $postedIssuer : null;
- }
-
/**
* Get the transaction URL.
*
@@ -1027,7 +542,7 @@ public function getSelectedIssuer(): ?string
*
* @return string
*/
- public function get_transaction_url($order): string
+ /*public function get_transaction_url($order): string
{
$isPaymentApi = substr($order->get_meta('_mollie_order_id', true), 0, 3) === 'tr_' ;
$resource = ($order->get_meta('_mollie_order_id', true) && !$isPaymentApi) ? 'orders' : 'payments';
@@ -1036,22 +551,7 @@ public function get_transaction_url($order): string
. $resource . '/%s?utm_source=woocommerce&utm_medium=plugin&utm_campaign=partner';
return parent::get_transaction_url($order);
- }
-
- protected function gatewayHasFields(): void
- {
- if ($this->paymentMethod->getProperty('paymentFields')) {
- $this->has_fields = true;
- }
-
- /* Override show issuers dropdown? */
- $dropdownDisabled = $this->paymentMethod->hasProperty('issuers_dropdown_shown')
- && $this->paymentMethod->getProperty('issuers_dropdown_shown')
- === 'no';
- if ($dropdownDisabled) {
- $this->has_fields = false;
- }
- }
+ }*/
/**
* Get the correct currency for this payment or order
@@ -1123,12 +623,12 @@ protected function isAllowedBillingCountry($billingCountry, $status)
*
* @return bool
*/
- protected function checkEnabledNorDirectDebit(): bool
+ protected function checkEnabledNorDirectDebit($gateway): bool
{
- if ($this->enabled !== 'yes') {
+ if ($gateway->enabled !== 'yes') {
return false;
}
- if ($this->id === SharedDataDictionary::DIRECTDEBIT) {
+ if ($gateway->id === SharedDataDictionary::DIRECTDEBIT) {
return false;
}
return true;
@@ -1141,6 +641,24 @@ protected function checkEnabledNorDirectDebit(): bool
*/
protected function cartAmountAvailable()
{
- return WC()->cart && $this->get_order_total() > 0;
+ return WC()->cart && WC()->cart->get_total('edit') > 0;
+ }
+
+ /**
+ * TODO still used by the refund processor
+ * @return Logger
+ */
+ public function getLogger(): Logger
+ {
+ return $this->logger;
+ }
+
+ /**
+ * TODO still used by the refund processor
+ * @return PaymentFactory
+ */
+ public function getPaymentFactory(): PaymentFactory
+ {
+ return $this->paymentFactory;
}
}
diff --git a/src/Gateway/MolliePaymentGatewayI.php b/src/Gateway/MolliePaymentGatewayI.php
deleted file mode 100644
index 5efdb62ea..000000000
--- a/src/Gateway/MolliePaymentGatewayI.php
+++ /dev/null
@@ -1,186 +0,0 @@
-isSettingsOrderApi = $isSettingsOrderApi;
+ $this->paymentMethods = $paymentMethods;
}
/**
@@ -44,11 +48,17 @@ public function processGateways(array $gateways): array
if ($this->isSettingsOrderApi) {
return $gateways;
}
+ $paymentMethods = $this->paymentMethods;
return array_filter(
$gateways,
- static function ($gateway) {
- return !($gateway instanceof MolliePaymentGateway)
- || !$gateway->paymentMethod()->getProperty('orderMandatory');
+ static function ($gateway) use ($paymentMethods) {
+ if (! mollieWooCommerceIsMollieGateway($gateway)) {
+ return true;
+ }
+ $gatewayId = $gateway->id;
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $method = $paymentMethods[$methodId] ?? null;
+ return !$method->getProperty('orderMandatory');
}
);
}
diff --git a/src/Payment/OrderItemsRefunder.php b/src/Gateway/Refund/OrderItemsRefunder.php
similarity index 98%
rename from src/Payment/OrderItemsRefunder.php
rename to src/Gateway/Refund/OrderItemsRefunder.php
index 09a9a01cb..43521e311 100644
--- a/src/Payment/OrderItemsRefunder.php
+++ b/src/Gateway/Refund/OrderItemsRefunder.php
@@ -2,13 +2,12 @@
declare(strict_types=1);
-namespace Mollie\WooCommerce\Payment;
+namespace Mollie\WooCommerce\Gateway\Refund;
use Mollie\Api\Endpoints\OrderEndpoint;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Refund;
-use Mollie\WooCommerce\Plugin;
use Mollie\WooCommerce\Shared\Data;
use UnexpectedValueException;
use WC_Order;
diff --git a/src/Payment/OrderLineStatus.php b/src/Gateway/Refund/OrderLineStatus.php
similarity index 91%
rename from src/Payment/OrderLineStatus.php
rename to src/Gateway/Refund/OrderLineStatus.php
index 6b9238bcb..853b541cf 100644
--- a/src/Payment/OrderLineStatus.php
+++ b/src/Gateway/Refund/OrderLineStatus.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Mollie\WooCommerce\Payment;
+namespace Mollie\WooCommerce\Gateway\Refund;
use Mollie\Api\Types\OrderLineStatus as ApiOrderLineStatus;
diff --git a/src/Payment/PartialRefundException.php b/src/Gateway/Refund/PartialRefundException.php
similarity index 74%
rename from src/Payment/PartialRefundException.php
rename to src/Gateway/Refund/PartialRefundException.php
index 348d066fb..361903a00 100644
--- a/src/Payment/PartialRefundException.php
+++ b/src/Gateway/Refund/PartialRefundException.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Mollie\WooCommerce\Payment;
+namespace Mollie\WooCommerce\Gateway\Refund;
use UnexpectedValueException;
diff --git a/src/Payment/RefundLineItemsBuilder.php b/src/Gateway/Refund/RefundLineItemsBuilder.php
similarity index 99%
rename from src/Payment/RefundLineItemsBuilder.php
rename to src/Gateway/Refund/RefundLineItemsBuilder.php
index 2815fad7b..b23cd5c23 100644
--- a/src/Payment/RefundLineItemsBuilder.php
+++ b/src/Gateway/Refund/RefundLineItemsBuilder.php
@@ -2,7 +2,7 @@
declare(strict_types=1);
-namespace Mollie\WooCommerce\Payment;
+namespace Mollie\WooCommerce\Gateway\Refund;
use Mollie\WooCommerce\Shared\Data;
use stdClass;
diff --git a/src/Gateway/Refund/RefundProcessor.php b/src/Gateway/Refund/RefundProcessor.php
new file mode 100644
index 000000000..1d16e22b1
--- /dev/null
+++ b/src/Gateway/Refund/RefundProcessor.php
@@ -0,0 +1,85 @@
+deprecatedGatewayHelper = $deprecatedGatewayHelper;
+ }
+
+ /**
+ * Process a refund if supported
+ *
+ * @param WC_Order $wcOrder
+ * @param float $amount
+ * @param string $reason
+ *
+ * @return void
+ * @throws Exception
+ * @since WooCommerce 2.2
+ */
+ public function refundOrderPayment(WC_Order $wcOrder, $amount = null, $reason = ''): void
+ {
+ $order_id = $wcOrder->get_id();
+
+ // Check if there is a Mollie Payment Order object connected to this WooCommerce order
+ $payment_object_id = $this->deprecatedGatewayHelper->paymentObject()->getActiveMollieOrderId(
+ $order_id
+ );
+
+ // If there is no Mollie Payment Order object, try getting a Mollie Payment Payment object
+ if (!$payment_object_id) {
+ $payment_object_id = $this->deprecatedGatewayHelper->paymentObject()
+ ->getActiveMolliePaymentId($order_id);
+ }
+
+ // Mollie Payment object not found
+ if (!$payment_object_id) {
+ $error_message = __("Can\'t process refund. Could not find Mollie Payment object id for order %s.", 'mollie-payments-for-woocommerce');
+
+ $this->deprecatedGatewayHelper->getLogger()->debug(
+ __METHOD__ . ' - ' . sprintf($error_message, $order_id)
+ );
+
+ throw new Exception($error_message);
+ }
+
+ try {
+ $payment_object = $this->deprecatedGatewayHelper->getPaymentFactory()
+ ->getPaymentObject(
+ $payment_object_id,
+ $this->deprecatedGatewayHelper->paymentMethod()
+ );
+ } catch (ApiException $exception) {
+ $exceptionMessage = $exception->getMessage();
+ $this->deprecatedGatewayHelper->getLogger()->debug($exceptionMessage);
+ throw new Exception($exception->getMessage());
+ }
+
+ if (!$payment_object || !is_object($payment_object)) {
+ $error_message = __("Can\'t process refund. Could not find Mollie Payment object data for order %s.", 'mollie-payments-for-woocommerce');
+ $this->deprecatedGatewayHelper->getLogger()->debug(
+ __METHOD__ . ' - ' . sprintf($error_message, $order_id)
+ );
+
+ throw new Exception($error_message);
+ }
+
+ $payment_object->refund(
+ $wcOrder,
+ $order_id,
+ $payment_object,
+ $amount,
+ $reason
+ );
+ }
+}
diff --git a/src/Gateway/Voucher/MaybeDisableGateway.php b/src/Gateway/Voucher/MaybeDisableGateway.php
index 8fe1dfa58..e73972fa6 100644
--- a/src/Gateway/Voucher/MaybeDisableGateway.php
+++ b/src/Gateway/Voucher/MaybeDisableGateway.php
@@ -4,12 +4,56 @@
namespace Mollie\WooCommerce\Gateway\Voucher;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Inpsyde\PaymentGateway\PaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\Voucher;
class MaybeDisableGateway
{
+ /**
+ * Disable Bank Transfer Gateway
+ *
+ * @param ?array $gateways
+ * @return array
+ */
+ public function maybeDisableBankTransferGateway(?array $gateways): array
+ {
+ if (!is_array($gateways)) {
+ return [];
+ }
+ $isWcApiRequest = (bool)filter_input(INPUT_GET, 'wc-api', FILTER_SANITIZE_SPECIAL_CHARS);
+
+ $bankTransferSettings = get_option('mollie_wc_gateway_banktransfer_settings', false);
+ //If the setting is active is forced Payment API so we need to filter the gateway when order is in pay-page
+ // as it might have been created with Orders API
+ $isActiveExpiryDate = $bankTransferSettings
+ && isset($bankTransferSettings['activate_expiry_days_setting'])
+ && $bankTransferSettings['activate_expiry_days_setting'] === "yes"
+ && isset($bankTransferSettings['order_dueDate'])
+ && $bankTransferSettings['order_dueDate'] > 0;
+
+ /*
+ * There is only one case where we want to filter the gateway and it's when the
+ * pay-page render the available payments methods AND the setting is enabled
+ *
+ * For any other case we want to be sure bank transfer gateway is included.
+ */
+ if (
+ $isWcApiRequest ||
+ !$isActiveExpiryDate ||
+ is_checkout() && ! is_wc_endpoint_url('order-pay') ||
+ !wp_doing_ajax() && ! is_wc_endpoint_url('order-pay') ||
+ is_admin()
+ ) {
+ return $gateways;
+ }
+ $bankTransferGatewayClassName = 'mollie_wc_gateway_banktransfer';
+ unset($gateways[$bankTransferGatewayClassName]);
+
+ return $gateways;
+ }
+
/**
* Disable Voucher Gateway if no categories associated with any product
* in the cart
@@ -30,10 +74,12 @@ public function maybeDisableMealVoucherGateway(?array $gateways): array
'wc-api',
FILTER_SANITIZE_SPECIAL_CHARS
);
+ $isCheckoutPage = is_checkout();
+ $isOrderPayPage = is_wc_endpoint_url('order-pay');
// To exclude we are in Checkout or Order Pay page. These are the other options where gateways are required.
$notInCheckoutOrPayPage = $isWcApiRequest
|| !doing_action('woocommerce_payment_gateways')
- || (!wp_doing_ajax() && !is_wc_endpoint_url('order-pay'));
+ || (!wp_doing_ajax() && !$isOrderPayPage && !$isCheckoutPage);
$notHasBlocks = !has_block('woocommerce/checkout');
/*
* There are 3 cases where we want to filter the gateway and it's when the checkout
@@ -47,7 +93,7 @@ public function maybeDisableMealVoucherGateway(?array $gateways): array
}
$mealVoucherGatewayIndex = false;
foreach ($gateways as $key => $gateway) {
- if (!($gateway instanceof MolliePaymentGateway)) {
+ if (! mollieWooCommerceIsMollieGateway($gateway)) {
continue;
}
if ($gateway->id === 'mollie_wc_gateway_voucher') {
@@ -56,7 +102,7 @@ public function maybeDisableMealVoucherGateway(?array $gateways): array
}
$productsWithCategory = $this->numberProductsWithCategory();
- $paymentAPISetting = get_option('mollie-payments-for-woocommerce_api_switch') === PaymentService::PAYMENT_METHOD_TYPE_PAYMENT;
+ $paymentAPISetting = get_option('mollie-payments-for-woocommerce_api_switch') === PaymentProcessor::PAYMENT_METHOD_TYPE_PAYMENT;
if ($mealVoucherGatewayIndex !== false && ($productsWithCategory === 0 || $paymentAPISetting)) {
unset($gateways[$mealVoucherGatewayIndex]);
diff --git a/src/Gateway/Voucher/VoucherModule.php b/src/Gateway/Voucher/VoucherModule.php
index 4e1eb1f8d..89319569f 100644
--- a/src/Gateway/Voucher/VoucherModule.php
+++ b/src/Gateway/Voucher/VoucherModule.php
@@ -58,7 +58,7 @@ public function services(): array
*/
public function run(ContainerInterface $container): bool
{
- $gatewayInstances = $container->get('gateway.instances');
+ $gatewayInstances = $container->get('__deprecated.gateway_helpers');
$voucherGateway = $gatewayInstances['mollie_wc_gateway_voucher'] ?? false;
$voucher = $voucherGateway && $voucherGateway->enabled === 'yes';
diff --git a/src/Gateway/inc/extensions.php b/src/Gateway/inc/extensions.php
new file mode 100644
index 000000000..f65c532dc
--- /dev/null
+++ b/src/Gateway/inc/extensions.php
@@ -0,0 +1,26 @@
+
+ static function (array $gateways, ContainerInterface $container): array {
+ $paymentMethods = $container->get('gateway.getPaymentMethodsAfterFeatureFlag');
+ $paymentMethodsEnabledAtMollie = $container->get('gateway.paymentMethodsEnabledAtMollie');
+ foreach ($paymentMethods as $paymentMethod) {
+ if (! in_array($paymentMethod['id'], $paymentMethodsEnabledAtMollie)) {
+ continue;
+ }
+ $gatewayId = 'mollie_wc_gateway_' . $paymentMethod['id'];
+ $gateways[] = $gatewayId;
+ }
+
+ return $gateways;
+ },
+ ];
+};
diff --git a/src/Gateway/inc/services.php b/src/Gateway/inc/services.php
new file mode 100644
index 000000000..49d765308
--- /dev/null
+++ b/src/Gateway/inc/services.php
@@ -0,0 +1,510 @@
+ static function (): array {
+ return SharedDataDictionary::GATEWAY_CLASSNAMES;
+ },
+ '__deprecated.gateway_helpers' => static function (ContainerInterface $container): array {
+ $oldGatewayBuilder = new DeprecatedGatewayBuilder();
+ return $oldGatewayBuilder->instantiatePaymentMethodGateways($container);
+ },
+ 'gateway.paymentMethods' => static function (ContainerInterface $container): array {
+ return (new self())->instantiatePaymentMethods($container);
+ },
+ 'gateway.paymentMethodsEnabledAtMollie' => static function (ContainerInterface $container): array {
+ $dataHelper = $container->get('settings.data_helper');
+ assert($dataHelper instanceof Data);
+ $settings = $container->get('settings.settings_helper');
+ assert($settings instanceof Settings);
+ $apiKey = $settings->getApiKey();
+ $methods = $apiKey ? $dataHelper->getAllPaymentMethods($apiKey) : [];
+ $enabledMethods = [];
+ foreach ($methods as $method) {
+ $enabledMethods[] = $method['id'];
+ }
+ return $enabledMethods;
+ },
+ 'gateway.listAllMethodsAvailable' => static function (ContainerInterface $container): array {
+ $dataHelper = $container->get('settings.data_helper');
+ assert($dataHelper instanceof Data);
+ $settings = $container->get('settings.settings_helper');
+ assert($settings instanceof Settings);
+ $apiKey = $settings->getApiKey();
+ $methods = $apiKey ? $dataHelper->getAllAvailablePaymentMethods() : [];
+ $availableMethods = [];
+ $implementedMethods = $container->get('gateway.classnames');
+ foreach ($methods as $method) {
+ if (in_array('Mollie_WC_Gateway_' . ucfirst($method['id']), $implementedMethods, true)) {
+ $availableMethods[] = $method;
+ }
+ }
+ return $availableMethods;
+ },
+ 'gateway.getPaymentMethodsAfterFeatureFlag' => static function (ContainerInterface $container): array {
+ $availablePaymentMethods = $container->get('gateway.listAllMethodsAvailable');
+ $klarnaOneFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.klarna_one_enabled', true);
+ if (!$klarnaOneFlag) {
+ $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
+ return $method['id'] !== Constants::KLARNA;
+ });
+ }
+ $bancomatpayFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.bancomatpay_enabled', true);
+ if (!$bancomatpayFlag) {
+ $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
+ return $method['id'] !== Constants::BANCOMATPAY;
+ });
+ }
+ $almaFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.alma_enabled', true);
+ if (!$almaFlag) {
+ $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
+ return $method['id'] !== Constants::ALMA;
+ });
+ }
+ $swishFlag = (bool) apply_filters('inpsyde.feature-flags.mollie-woocommerce.swish_enabled', false);
+ if (!$swishFlag) {
+ $availablePaymentMethods = array_filter($availablePaymentMethods, static function ($method) {
+ return $method['id'] !== Constants::SWISH;
+ });
+ }
+ return $availablePaymentMethods;
+ },
+ 'gateway.isSDDGatewayEnabled' => static function (ContainerInterface $container): bool {
+ $enabledMethods = $container->get('gateway.paymentMethodsEnabledAtMollie');
+ return in_array(Constants::DIRECTDEBIT, $enabledMethods, true);
+ },
+
+ IconFactory::class => static function (ContainerInterface $container): IconFactory {
+ $pluginUrl = $container->get('shared.plugin_url');
+ $pluginPath = $container->get('shared.plugin_path');
+ return new IconFactory($pluginUrl, $pluginPath);
+ },
+ RefundLineItemsBuilder::class => static function (ContainerInterface $container): RefundLineItemsBuilder {
+ $data = $container->get('settings.data_helper');
+ return new RefundLineItemsBuilder($data);
+ },
+ OrderItemsRefunder::class => static function (ContainerInterface $container): OrderItemsRefunder {
+ $data = $container->get('settings.data_helper');
+ $refundLineItemsBuilder = $container->get(RefundLineItemsBuilder::class);
+ $apiHelper = $container->get('SDK.api_helper');
+ $apiKey = $container->get('settings.settings_helper')->getApiKey();
+ $orderEndpoint = $apiHelper->getApiClient($apiKey)->orders;
+
+ return new OrderItemsRefunder($refundLineItemsBuilder, $data, $orderEndpoint);
+ },
+ PaymentProcessor::class => static function (ContainerInterface $container): PaymentProcessor {
+ $logger = $container->get(Logger::class);
+ assert($logger instanceof Logger);
+ $notice = $container->get(AdminNotice::class);
+ assert($notice instanceof AdminNotice);
+ $paymentFactory = $container->get(PaymentFactory::class);
+ assert($paymentFactory instanceof PaymentFactory);
+ $data = $container->get('settings.data_helper');
+ assert($data instanceof Data);
+ $api = $container->get('SDK.api_helper');
+ assert($api instanceof Api);
+ $settings = $container->get('settings.settings_helper');
+ assert($settings instanceof Settings);
+ $pluginId = $container->get('shared.plugin_id');
+ $paymentCheckoutRedirectService = $container->get(PaymentCheckoutRedirectService::class);
+ assert($paymentCheckoutRedirectService instanceof PaymentCheckoutRedirectService);
+ $voucherDefaultCategory = $container->get('voucher.defaultCategory');
+ $deprecatedGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ return new PaymentProcessor($notice, $logger, $paymentFactory, $data, $api, $settings, $pluginId, $paymentCheckoutRedirectService, $voucherDefaultCategory, $deprecatedGatewayInstances);
+ },
+ OrderInstructionsManager::class => static function (): OrderInstructionsManager {
+ return new OrderInstructionsManager();
+ },
+ PaymentCheckoutRedirectService::class => static function (
+ ContainerInterface $container
+ ): PaymentCheckoutRedirectService {
+ $data = $container->get('settings.data_helper');
+ assert($data instanceof Data);
+ return new PaymentCheckoutRedirectService($data);
+ },
+ Surcharge::class => static function (ContainerInterface $container): Surcharge {
+ return new Surcharge();
+ },
+ MollieOrderService::class => static function (ContainerInterface $container): MollieOrderService {
+ $HttpResponseService = $container->get('SDK.HttpResponse');
+ assert($HttpResponseService instanceof HttpResponse);
+ $logger = $container->get(Logger::class);
+ assert($logger instanceof Logger);
+ $paymentFactory = $container->get(PaymentFactory::class);
+ assert($paymentFactory instanceof PaymentFactory);
+ $data = $container->get('settings.data_helper');
+ assert($data instanceof Data);
+ $pluginId = $container->get('shared.plugin_id');
+ return new MollieOrderService($HttpResponseService, $logger, $paymentFactory, $data, $pluginId, $container);
+ },
+ OrderMandatoryGatewayDisabler::class => static function (ContainerInterface $container): OrderMandatoryGatewayDisabler {
+ $settings = $container->get('settings.settings_helper');
+ assert($settings instanceof Settings);
+ $isSettingsOrderApi = $settings->isOrderApiSetting();
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ return new OrderMandatoryGatewayDisabler($isSettingsOrderApi, $paymentMethods);
+ },
+ ApplePayDirectHandler::class => static function (ContainerInterface $container) {
+ $appleGateway = isset($container->get('__deprecated.gateway_helpers')['mollie_wc_gateway_applepay']) ? $container->get(
+ '__deprecated.gateway_helpers'
+ )['mollie_wc_gateway_applepay'] : false;
+ if (!$appleGateway) {
+ return false;
+ }
+ $notice = $container->get(AdminNotice::class);
+ assert($notice instanceof AdminNotice);
+ $logger = $container->get(Logger::class);
+ assert($logger instanceof Logger);
+
+ $apiHelper = $container->get('SDK.api_helper');
+ assert($apiHelper instanceof Api);
+ $settingsHelper = $container->get('settings.settings_helper');
+ assert($settingsHelper instanceof Settings);
+
+ $responseTemplates = new ResponsesToApple($logger, $appleGateway);
+ $ajaxRequests = new AppleAjaxRequests($responseTemplates, $notice, $logger, $apiHelper, $settingsHelper);
+ return new ApplePayDirectHandler($notice, $ajaxRequests);
+ },
+ PayPalButtonHandler::class => static function (ContainerInterface $container) {
+ $notice = $container->get(AdminNotice::class);
+ assert($notice instanceof AdminNotice);
+ $logger = $container->get(Logger::class);
+ assert($logger instanceof Logger);
+ $paymentGateways = $container->get('payment_gateways');
+ $paypalGateway = isset($paymentGateways['mollie_wc_gateway_paypal']) ? $paymentGateways['mollie_wc_gateway_paypal'] : false;
+ if (!$paypalGateway) {
+ return false;
+ }
+ $pluginUrl = $container->get('shared.plugin_url');
+ $ajaxRequests = new PayPalAjaxRequests($paypalGateway, $notice, $logger);
+ $data = new DataToPayPal($pluginUrl);
+ return new PayPalButtonHandler($ajaxRequests, $data);
+ },
+ 'payment_gateway.getRefundProcessor' => static function (ContainerInterface $container): callable {
+ return static function (string $gatewayId) use ($container): RefundProcessor {
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+
+ if (!isset($oldGatewayInstances[$gatewayId])) {
+ return $container->get('payment_gateways.noop_refund_processor');
+ }
+
+ $gateway = $oldGatewayInstances[$gatewayId];
+ return new RefundProcessor($gateway);
+ };
+ },
+ 'gateway.isBillieEnabled' => static function (ContainerInterface $container): bool {
+ $settings = $container->get('settings.settings_helper');
+ assert($settings instanceof Settings);
+ $isSettingsOrderApi = $settings->isOrderApiSetting();
+ $billie = isset($container->get('gateway.paymentMethods')['billie']) ? $container->get('gateway.paymentMethods')['billie'] : null;
+ $isBillieEnabled = false;
+ if ($billie instanceof PaymentMethodI) {
+ $isBillieEnabled = $billie->getProperty('enabled') === 'yes';
+ }
+ return $isSettingsOrderApi && $isBillieEnabled;
+ },
+ 'payment_request_validators' => static function (ContainerInterface $container): callable {
+ return static function (string $gatewayId) use ($container): callable {
+ //todo this is default
+ return $container->get('payment_gateways.noop_payment_request_validator');
+ };
+ },
+ 'gateway.getMethodPropertyByGatewayId' => static function (ContainerInterface $container): callable {
+ return static function (string $gatewayId, string $property) use ($container) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+ return $paymentMethod->getProperty($property);
+ };
+ },
+ 'payment_gateway.getPaymentMethod' => static function (ContainerInterface $container): callable {
+ return static function (string $gatewayId) use ($container): PaymentMethodI {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ return $paymentMethods[$methodId];
+ };
+ },
+ 'gateway.subscriptionsSupports' => static function (): array {
+ return [
+ 'subscriptions',
+ 'subscription_cancellation',
+ 'subscription_suspension',
+ 'subscription_reactivation',
+ 'subscription_amount_changes',
+ 'subscription_date_changes',
+ 'multiple_subscriptions',
+ 'subscription_payment_method_change',
+ 'subscription_payment_method_change_admin',
+ 'subscription_payment_method_change_customer',
+ ];
+ },
+ 'gateway.hooks.thankyouPage' => static function (ContainerInterface $container) {
+ return static function (PaymentGateway $paymentGateway) use ($container) {
+ $instructionsManager = $container->get(OrderInstructionsManager::class);
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ $gatewayId = $paymentGateway->id;
+ $deprecatedGatewayHelper = $oldGatewayInstances[$gatewayId];
+ add_action(
+ 'woocommerce_thankyou_' . $paymentGateway->id,
+ static function ($order_id) use ($instructionsManager, $paymentGateway, $deprecatedGatewayHelper) {
+ $order = wc_get_order($order_id);
+
+ // Order not found
+ if (!$order) {
+ return;
+ }
+
+ // Empty cart
+ if (WC()->cart) {
+ WC()->cart->empty_cart();
+ }
+
+ // Same as email instructions, just run that
+ $instructionsManager->displayInstructions(
+ $paymentGateway,
+ $deprecatedGatewayHelper,
+ $order,
+ false,
+ false
+ );
+ }
+ );
+ };
+ },
+ 'gateway.hooks.displayInstructions' => static function (ContainerInterface $container) {
+ return static function (PaymentGateway $paymentGateway) use ($container) {
+ $instructionsManager = $container->get(OrderInstructionsManager::class);
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ $gatewayId = $paymentGateway->id;
+ $deprecatedGatewayHelper = $oldGatewayInstances[$gatewayId];
+ add_action(
+ 'woocommerce_email_after_order_table',
+ static function ($order, $sent_to_admin, $plain_text) use ($instructionsManager, $paymentGateway, $deprecatedGatewayHelper) {
+ $instructionsManager->displayInstructions(
+ $paymentGateway,
+ $deprecatedGatewayHelper,
+ $order,
+ $sent_to_admin,
+ $plain_text
+ );
+ },
+ 10,
+ 3
+ );
+
+ add_action(
+ 'woocommerce_email_order_meta',
+ static function ($order, $sent_to_admin, $plain_text) use ($instructionsManager, $paymentGateway, $deprecatedGatewayHelper) {
+ $instructionsManager->displayInstructions(
+ $paymentGateway,
+ $deprecatedGatewayHelper,
+ $order,
+ $sent_to_admin,
+ $plain_text
+ );
+ },
+ 10,
+ 3
+ );
+ };
+ },
+ 'gateway.hooks.isSubscriptionPayment' => static function (ContainerInterface $container) {
+ return static function (PaymentGateway $paymentGateway) use ($container) {
+ $pluginId = $container->get('shared.plugin_id');
+ $dataHelper = $container->get('settings.data_helper');
+ if ($paymentGateway->supports('subscriptions')) {
+ add_filter(
+ $pluginId . '_is_subscription_payment',
+ static function ($isSubscription, $orderId) use ($pluginId, $dataHelper) {
+ if ($dataHelper->isWcSubscription($orderId)) {
+ add_filter(
+ $pluginId . '_is_automatic_payment_disabled',
+ static function ($filteredOption) {
+ if (
+ 'yes' == get_option(
+ \WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments'
+ )
+ ) {
+ return true;
+ }
+ return $filteredOption;
+ }
+ );
+ return true;
+ }
+ return $isSubscription;
+ },
+ 10,
+ 2
+ );
+ }
+ };
+ },
+
+ ];
+ $paymentMethods = SharedDataDictionary::GATEWAY_CLASSNAMES;
+
+ $dynamicServices = [];
+ foreach ($paymentMethods as $paymentMethod) {
+ $gatewayId = strtolower($paymentMethod);
+
+ $dynamicServices["payment_gateway.$gatewayId.payment_request_validator"] = static function (ContainerInterface $container): PaymentRequestValidatorInterface {
+ return $container->get('payment_gateways.noop_payment_request_validator');
+ };
+ $dynamicServices["payment_gateway.$gatewayId.payment_processor"] = static function (ContainerInterface $container) use ($gatewayId): PaymentProcessor {
+ return $container->get(PaymentProcessor::class);
+ };
+ $dynamicServices["payment_gateway.$gatewayId.refund_processor"] = static function (ContainerInterface $container) use ($gatewayId): RefundProcessorInterface {
+ $getProperty = $container->get('gateway.getMethodPropertyByGatewayId');
+ $supports = $getProperty($gatewayId, 'supports');
+ $supportsRefunds = $supports && in_array('refunds', $supports, true);
+ if ($supportsRefunds) {
+ return $container->get('payment_gateway.getRefundProcessor')($gatewayId);
+ }
+ return $container->get('payment_gateways.noop_refund_processor');
+ };
+ $dynamicServices["payment_gateway.$gatewayId.has_fields"] = static function (ContainerInterface $container) use ($gatewayId): bool {
+ $getProperty = $container->get('gateway.getMethodPropertyByGatewayId');
+ if ($getProperty($gatewayId, 'paymentFields')) {
+ return true;
+ }
+
+ /* Override show issuers dropdown? */
+ $dropdownDisabled = $getProperty($gatewayId, 'issuers_dropdown_shown') === 'no';
+ if ($dropdownDisabled) {
+ return false;
+ }
+ return false;
+ };
+ $dynamicServices["payment_gateway.$gatewayId.gateway_icons_renderer"] = static function (ContainerInterface $container) use ($gatewayId) {
+ return new GatewayIconsRenderer($gatewayId, $container);
+ };
+ $dynamicServices["payment_gateway.$gatewayId.payment_fields_renderer"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ //not all payment methods have a gateway
+ if (!isset($oldGatewayInstances[$gatewayId])) {
+ return new NoopPaymentFieldsRenderer();
+ }
+ $gatewayDescription = $container->get('payment_gateway.' . $gatewayId . '.description');
+ $dataHelper = $container->get('settings.data_helper');
+ $deprecatedGatewayHelper = $oldGatewayInstances[$gatewayId];
+ if (!$paymentMethod->getProperty('paymentFields')) {
+ return new DefaultFieldsStrategy($deprecatedGatewayHelper, $gatewayDescription, $dataHelper);
+ } else {
+ $className = 'Mollie\\WooCommerce\\PaymentMethods\\PaymentFieldsStrategies\\' . ucfirst($paymentMethod->getProperty('id')) . 'FieldsStrategy';
+ return class_exists($className) ? new $className($deprecatedGatewayHelper, $gatewayDescription, $dataHelper) : new DefaultFieldsStrategy($deprecatedGatewayHelper, $gatewayDescription, $dataHelper);
+ }
+ };
+
+ $dynamicServices["payment_gateway.$gatewayId.title"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+
+ return $paymentMethod->title();
+ };
+ $dynamicServices["payment_gateway.$gatewayId.method_title"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+
+ return 'Mollie - ' . $paymentMethod->title();
+ };
+ $dynamicServices["payment_gateway.$gatewayId.method_description"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+
+ return $paymentMethod->getProperty('settingsDescription');
+ };
+ $dynamicServices["payment_gateway.$gatewayId.description"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+
+ $description = $paymentMethod->getProcessedDescription();
+ return empty($description) ? false : $description;
+ };
+ $dynamicServices["payment_gateway.$gatewayId.availability_callback"] = new Factory(
+ ['__deprecated.gateway_helpers'],
+ static function (array $gatewayInstances) use ($gatewayId): callable {
+ return static function ($gateway) use ($gatewayInstances, $gatewayId): bool {
+ return $gatewayInstances[$gatewayId]->is_available($gateway);
+ };
+ }
+ );
+ $dynamicServices["payment_gateway.$gatewayId.form_fields"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+ return $paymentMethod->getAllFormFields();
+ };
+ $dynamicServices["payment_gateway.$gatewayId.option_key"] = static function (ContainerInterface $container) use ($gatewayId) {
+ return $gatewayId . '_settings';
+ };
+ $dynamicServices["payment_gateway.$gatewayId.supports"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+ $supports = $paymentMethod->getProperty('supports');
+ $isSepa = $paymentMethod->getProperty('SEPA') === true;
+ $isSubscription = $paymentMethod->getProperty('Subscription') === true;
+ $subscriptionHooks = $container->get('gateway.subscriptionsSupports');
+ if ($isSepa || $isSubscription) {
+ $supports = array_merge($supports, $subscriptionHooks);
+ }
+ return $supports;
+ };
+ $dynamicServices["payment_gateway.$gatewayId.settings_field_renderer.multi_select_countries"] = static function (ContainerInterface $container) use ($gatewayId) {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+
+ return new MultiCountrySettingsField($paymentMethod);
+ };
+ }
+
+ return array_merge($services, $dynamicServices);
+};
diff --git a/src/Payment/MollieObject.php b/src/Payment/MollieObject.php
index 7d4c69681..b129d8b58 100644
--- a/src/Payment/MollieObject.php
+++ b/src/Payment/MollieObject.php
@@ -7,21 +7,17 @@
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Payment;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Payment\Request\RequestFactory;
use Mollie\WooCommerce\PaymentMethods\Voucher;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Settings\Settings;
+use Mollie\WooCommerce\Shared\SharedDataDictionary;
use WC_Order;
use WC_Payment_Gateway;
use Psr\Log\LoggerInterface as Logger;
-use stdClass;
class MollieObject
{
- public const MAXIMAL_LENGTH_ADDRESS = 100;
- public const MAXIMAL_LENGTH_POSTALCODE = 20;
- public const MAXIMAL_LENGTH_CITY = 200;
- public const MAXIMAL_LENGTH_REGION = 200;
protected $data;
/**
* @var string[]
@@ -49,9 +45,22 @@ class MollieObject
* @var string
*/
protected $pluginId;
+ /**
+ * @var null
+ */
+ private $paymentMethod;
+ protected RequestFactory $requestFactory;
+
+ public function __construct(
+ $data,
+ Logger $logger,
+ PaymentFactory $paymentFactory,
+ Api $apiHelper,
+ Settings $settingsHelper,
+ string $pluginId,
+ RequestFactory $requestFactory
+ ) {
- public function __construct($data, Logger $logger, PaymentFactory $paymentFactory, Api $apiHelper, Settings $settingsHelper, string $pluginId)
- {
$this->data = $data;
$this->logger = $logger;
$this->paymentFactory = $paymentFactory;
@@ -60,6 +69,8 @@ public function __construct($data, Logger $logger, PaymentFactory $paymentFactor
$this->pluginId = $pluginId;
$base_location = wc_get_base_location();
static::$shop_country = $base_location['country'];
+ $this->paymentMethod = null;
+ $this->requestFactory = $requestFactory;
}
public function data()
@@ -144,6 +155,42 @@ protected function getPaymentRequestData($order, $customerId, $voucherDefaultCat
{
}
+ /**
+ * @param \WC_Order $order
+ * @param string $new_status
+ * @param string $note
+ * @param bool $restore_stock
+ */
+ public function updateOrderStatus(\WC_Order $order, $new_status, $note = '', $restore_stock = true)
+ {
+ $order->update_status($new_status, $note);
+
+ switch ($new_status) {
+ case SharedDataDictionary::STATUS_ON_HOLD:
+ if ($restore_stock === true) {
+ if (!$order->get_meta('_order_stock_reduced', true)) {
+ // Reduce order stock
+ wc_reduce_stock_levels($order->get_id());
+
+ $this->logger->debug(__METHOD__ . ": Stock for order {$order->get_id()} reduced.");
+ }
+ }
+
+ break;
+
+ case SharedDataDictionary::STATUS_PENDING:
+ case SharedDataDictionary::STATUS_FAILED:
+ case SharedDataDictionary::STATUS_CANCELLED:
+ if ($order->get_meta('_order_stock_reduced', true)) {
+ // Restore order stock
+ $this->dataHelper->restoreOrderStock($order);
+
+ $this->logger->debug(__METHOD__ . " Stock for order {$order->get_id()} restored.");
+ }
+
+ break;
+ }
+ }
/**
* Save active Mollie payment id for order
*
@@ -603,24 +650,6 @@ protected function addMandateIdMetaToFirstPaymentSubscriptionOrder(
}
}
}
-
- protected function addSequenceTypeForSubscriptionsFirstPayments($orderId, $gateway, $paymentRequestData): array
- {
- if ($this->dataHelper->isSubscription($orderId) || $this->dataHelper->isWcSubscription($orderId)) {
- $disable_automatic_payments = apply_filters($this->pluginId . '_is_automatic_payment_disabled', false);
- $supports_subscriptions = $gateway->supports('subscriptions');
-
- if ($supports_subscriptions == true && $disable_automatic_payments == false) {
- $paymentRequestData = $this->addSequenceTypeFirst($paymentRequestData);
- }
- }
- return $paymentRequestData;
- }
-
- public function addSequenceTypeFirst($paymentRequestData)
- {
- }
-
/**
* @param $order
*/
@@ -672,8 +701,8 @@ protected function failedSubscriptionProcess(
function_exists('wcs_order_contains_renewal')
&& wcs_order_contains_renewal($orderId)
) {
- if ($gateway instanceof MolliePaymentGateway) {
- $gateway->paymentService()->updateOrderStatus(
+ if (mollieWooCommerceIsMollieGateway($gateway->id)) {
+ $this->updateOrderStatus(
$order,
$newOrderStatus,
sprintf(
@@ -704,8 +733,8 @@ function_exists('wcs_order_contains_renewal')
) {
$emails['WC_Email_Failed_Order']->trigger($orderId);
}
- } elseif ($gateway instanceof MolliePaymentGateway) {
- $gateway->paymentService()->updateOrderStatus(
+ } elseif (mollieWooCommerceIsMollieGateway($gateway->id)) {
+ $this->updateOrderStatus(
$order,
$newOrderStatus,
sprintf(
@@ -774,438 +803,4 @@ protected function addPaypalTransactionIdToOrder(
$order->save();
}
}
- /**
- * Get the url to return to on Mollie return
- * saves the return redirect and failed redirect, so we save the page language in case there is one set
- * For example 'http://mollie-wc.docker.myhost/wc-api/mollie_return/?order_id=89&key=wc_order_eFZyH8jki6fge'
- *
- * @param WC_Order $order The order processed
- *
- * @return string The url with order id and key as params
- */
- public function getReturnUrl($order, $returnUrl)
- {
- $returnUrl = untrailingslashit($returnUrl);
- $returnUrl = $this->asciiDomainName($returnUrl);
- $orderId = $order->get_id();
- $orderKey = $order->get_order_key();
-
- $onMollieReturn = 'onMollieReturn';
- $returnUrl = $this->appendOrderArgumentsToUrl(
- $orderId,
- $orderKey,
- $returnUrl,
- $onMollieReturn
- );
- $returnUrl = untrailingslashit($returnUrl);
- $this->logger->debug(" Order {$orderId} returnUrl: {$returnUrl}", [true]);
-
- return apply_filters($this->pluginId . '_return_url', $returnUrl, $order);
- }
- /**
- * Get the webhook url
- * For example 'http://mollie-wc.docker.myhost/wc-api/mollie_return/mollie_wc_gateway_bancontact/?order_id=89&key=wc_order_eFZyH8jki6fge'
- *
- * @param WC_Order $order The order processed
- *
- * @return string The url with gateway and order id and key as params
- */
- public function getWebhookUrl($order, $gatewayId)
- {
- $webhookUrl = WC()->api_request_url($gatewayId);
- $webhookUrl = untrailingslashit($webhookUrl);
- $webhookUrl = $this->asciiDomainName($webhookUrl);
- $orderId = $order->get_id();
- $orderKey = $order->get_order_key();
- $webhookUrl = $this->appendOrderArgumentsToUrl(
- $orderId,
- $orderKey,
- $webhookUrl
- );
- $webhookUrl = untrailingslashit($webhookUrl);
-
- $this->logger->debug(" Order {$orderId} webhookUrl: {$webhookUrl}", [true]);
-
- return apply_filters($this->pluginId . '_webhook_url', $webhookUrl, $order);
- }
- /**
- * @param $url
- *
- * @return string
- */
- protected function asciiDomainName($url): string
- {
- $parsed = wp_parse_url($url);
- $scheme = isset($parsed['scheme']) ? $parsed['scheme'] : '';
- $domain = isset($parsed['host']) ? $parsed['host'] : false;
- $query = isset($parsed['query']) ? $parsed['query'] : '';
- $path = isset($parsed['path']) ? $parsed['path'] : '';
- if (!$domain) {
- return $url;
- }
-
- if (function_exists('idn_to_ascii')) {
- $domain = $this->idnEncodeDomain($domain);
- $url = $scheme . "://" . $domain . $path . '?' . $query;
- }
-
- return $url;
- }
- /**
- * @param $order_id
- * @param $order_key
- * @param $webhook_url
- * @param string $filterFlag
- *
- * @return string
- */
- protected function appendOrderArgumentsToUrl($order_id, $order_key, $webhook_url, $filterFlag = '')
- {
- $webhook_url = add_query_arg(
- [
- 'order_id' => $order_id,
- 'key' => $order_key,
- 'filter_flag' => $filterFlag,
- ],
- $webhook_url
- );
- return $webhook_url;
- }
-
- /**
- * @param $domain
- * @return false|mixed|string
- */
- protected function idnEncodeDomain($domain)
- {
- if (
- defined('IDNA_NONTRANSITIONAL_TO_ASCII')
- && defined(
- 'INTL_IDNA_VARIANT_UTS46'
- )
- ) {
- $domain = idn_to_ascii(
- $domain,
- IDNA_NONTRANSITIONAL_TO_ASCII,
- INTL_IDNA_VARIANT_UTS46
- ) ? idn_to_ascii(
- $domain,
- IDNA_NONTRANSITIONAL_TO_ASCII,
- INTL_IDNA_VARIANT_UTS46
- ) : $domain;
- } else {
- $domain = idn_to_ascii($domain) ? idn_to_ascii($domain) : $domain;
- }
- return $domain;
- }
-
- protected function getPaymentDescription($order, $option)
- {
- $description = !$option ? '' : trim($option);
- $description = !$description ? '{orderNumber}' : $description;
-
- switch ($description) {
- // Support for old deprecated options.
- // TODO: remove when deprecated
- case '{orderNumber}':
- $description =
- /* translators: do not translate between {} */
- _x(
- 'Order {orderNumber}',
- 'Payment description for {orderNumber}',
- 'mollie-payments-for-woocommerce'
- );
- $description = $this->replaceTagsDescription($order, $description);
- break;
- case '{storeName}':
- $description =
- /* translators: do not translate between {} */
- _x(
- 'StoreName {storeName}',
- 'Payment description for {storeName}',
- 'mollie-payments-for-woocommerce'
- );
- $description = $this->replaceTagsDescription($order, $description);
- break;
- case '{customer.firstname}':
- $description =
- /* translators: do not translate between {} */
- _x(
- 'Customer Firstname {customer.firstname}',
- 'Payment description for {customer.firstname}',
- 'mollie-payments-for-woocommerce'
- );
- $description = $this->replaceTagsDescription($order, $description);
- break;
- case '{customer.lastname}':
- $description =
- /* translators: do not translate between {} */
- _x(
- 'Customer Lastname {customer.lastname}',
- 'Payment description for {customer.lastname}',
- 'mollie-payments-for-woocommerce'
- );
- $description = $this->replaceTagsDescription($order, $description);
- break;
- case '{customer.company}':
- $description =
- /* translators: do not translate between {} */
- _x(
- 'Customer Company {customer.company}',
- 'Payment description for {customer.company}',
- 'mollie-payments-for-woocommerce'
- );
- $description = $this->replaceTagsDescription($order, $description);
- break;
- // Support for custom string with interpolation.
- default:
- // Replace available description tags.
- $description = $this->replaceTagsDescription($order, $description);
- break;
- }
-
- // Fall back on default if description turns out empty.
- return !$description ? __('Order', 'woocommerce') . ' ' . $order->get_order_number() : $description;
- }
-
- /**
- * @param $order
- * @param $description
- * @return array|string|string[]
- */
- protected function replaceTagsDescription($order, $description)
- {
- $replacement_tags = [
- '{orderNumber}' => $order->get_order_number(),
- '{storeName}' => get_bloginfo('name'),
- '{customer.firstname}' => $order->get_billing_first_name(),
- '{customer.lastname}' => $order->get_billing_last_name(),
- '{customer.company}' => $order->get_billing_company(),
- ];
- foreach ($replacement_tags as $tag => $replacement) {
- $description = str_replace($tag, $replacement, $description);
- }
- return $description;
- }
-
- /**
- * @param $order
- * @return stdClass
- */
- protected function createBillingAddress($order)
- {
- // Setup billing and shipping objects
- $billingAddress = new stdClass();
-
- // Get user details
- $billingAddress->givenName = (ctype_space(
- $order->get_billing_first_name()
- )) ? null : $order->get_billing_first_name();
- $billingAddress->familyName = (ctype_space(
- $order->get_billing_last_name()
- )) ? null : $order->get_billing_last_name();
- $billingAddress->email = (ctype_space($order->get_billing_email()))
- ? null : $order->get_billing_email();
- // Create billingAddress object
- $billingAddress->streetAndNumber = (ctype_space(
- $order->get_billing_address_1()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_address_1(),
- self::MAXIMAL_LENGTH_ADDRESS
- );
- $billingAddress->streetAdditional = (ctype_space(
- $order->get_billing_address_2()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_address_2(),
- self::MAXIMAL_LENGTH_ADDRESS
- );
- $billingAddress->postalCode = (ctype_space(
- $order->get_billing_postcode()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_postcode(),
- self::MAXIMAL_LENGTH_POSTALCODE
- );
- $billingAddress->city = (ctype_space($order->get_billing_city()))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_city(),
- self::MAXIMAL_LENGTH_CITY
- );
- $billingAddress->region = (ctype_space($order->get_billing_state()))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_state(),
- self::MAXIMAL_LENGTH_REGION
- );
- $billingAddress->country = (ctype_space($order->get_billing_country()))
- ? null
- : $this->maximalFieldLengths(
- $order->get_billing_country(),
- self::MAXIMAL_LENGTH_REGION
- );
- $billingAddress->organizationName = $this->billingCompanyField($order);
- $phone = $this->getPhoneNumber($order);
- $billingAddress->phone = (ctype_space($phone))
- ? null
- : $this->getFormattedPhoneNumber($phone);
- return $billingAddress;
- }
-
- protected function getPhoneNumber($order)
- {
-
- $phone = !empty($order->get_billing_phone()) ? $order->get_billing_phone() : $order->get_shipping_phone();
- if (empty($phone)) {
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $phone = wc_clean(wp_unslash($_POST['billing_phone'] ?? ''));
- }
- return $phone;
- }
-
- protected function getFormattedPhoneNumber(string $phone)
- {
- //remove whitespaces and all non numerical characters except +
- $phone = preg_replace('/[^0-9+]+/', '', $phone);
- if (!is_string($phone)) {
- return null;
- }
- //check if phone starts with 06 and replace with +316
- $phone = transformPhoneToNLFormat($phone);
-
- //check that $phone is in E164 format or can be changed by api
- if (is_string($phone) && preg_match('/^\+[1-9]\d{10,13}$|^[1-9]\d{9,13}$/', $phone)) {
- return $phone;
- }
- return null;
- }
-
- /**
- * @param $order
- * @return string|null
- */
- public function billingCompanyField($order): ?string
- {
- if (!trim($order->get_billing_company())) {
- return $this->checkBillieCompanyField($order);
- }
- return $this->maximalFieldLengths(
- $order->get_billing_company(),
- self::MAXIMAL_LENGTH_ADDRESS
- );
- }
-
- private function checkBillieCompanyField($order)
- {
- $gateway = wc_get_payment_gateway_by_order($order);
- if (!$gateway || !$gateway->id) {
- return null;
- }
- $isBillieMethodId = $gateway->id === 'mollie_wc_gateway_billie';
- if ($isBillieMethodId) {
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $fieldPosted = wc_clean(wp_unslash($_POST["billing_company"] ?? ''));
- if ($fieldPosted === '' || !is_string($fieldPosted)) {
- return null;
- }
- return $this->maximalFieldLengths(
- $fieldPosted,
- self::MAXIMAL_LENGTH_ADDRESS
- );
- }
- return null;
- }
-
- /**
- * @param $order
- * @return stdClass
- */
- protected function createShippingAddress($order)
- {
- $shippingAddress = new stdClass();
- // Get user details
- $shippingAddress->givenName = (ctype_space(
- $order->get_shipping_first_name()
- )) ? null : $order->get_shipping_first_name();
- $shippingAddress->familyName = (ctype_space(
- $order->get_shipping_last_name()
- )) ? null : $order->get_shipping_last_name();
- $shippingAddress->email = (ctype_space($order->get_billing_email()))
- ? null
- : $order->get_billing_email(); // WooCommerce doesn't have a shipping email
-
-
- // Create shippingAddress object
- $shippingAddress->streetAndNumber = (ctype_space(
- $order->get_shipping_address_1()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_address_1(),
- self::MAXIMAL_LENGTH_ADDRESS
- );
- $shippingAddress->streetAdditional = (ctype_space(
- $order->get_shipping_address_2()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_address_2(),
- self::MAXIMAL_LENGTH_ADDRESS
- );
- $shippingAddress->postalCode = (ctype_space(
- $order->get_shipping_postcode()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_postcode(),
- self::MAXIMAL_LENGTH_POSTALCODE
- );
- $shippingAddress->city = (ctype_space($order->get_shipping_city()))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_city(),
- self::MAXIMAL_LENGTH_CITY
- );
- $shippingAddress->region = (ctype_space($order->get_shipping_state()))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_state(),
- self::MAXIMAL_LENGTH_REGION
- );
- $shippingAddress->country = (ctype_space(
- $order->get_shipping_country()
- ))
- ? null
- : $this->maximalFieldLengths(
- $order->get_shipping_country(),
- self::MAXIMAL_LENGTH_REGION
- );
- return $shippingAddress;
- }
-
- /**
- * Method that shortens the field to a certain length
- *
- * @param string $field
- * @param int $maximalLength
- *
- * @return null|string
- */
- protected function maximalFieldLengths($field, $maximalLength)
- {
- if (!is_string($field)) {
- return null;
- }
- if (is_int($maximalLength) && strlen($field) > $maximalLength) {
- $field = substr($field, 0, $maximalLength);
- $field = !$field ? null : $field;
- }
-
- return $field;
- }
}
diff --git a/src/Payment/MollieOrder.php b/src/Payment/MollieOrder.php
index 01564e48c..3bfee2898 100644
--- a/src/Payment/MollieOrder.php
+++ b/src/Payment/MollieOrder.php
@@ -5,14 +5,20 @@
namespace Mollie\WooCommerce\Payment;
use Exception;
+use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Payment;
use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Refund;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\Refund\OrderItemsRefunder;
+use Mollie\WooCommerce\Gateway\Refund\PartialRefundException;
+use Mollie\WooCommerce\Payment\Request\RequestFactory;
use Mollie\WooCommerce\PaymentMethods\Voucher;
use Mollie\WooCommerce\SDK\Api;
+use Mollie\WooCommerce\Settings\Settings;
+use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
+use Psr\Log\LoggerInterface as Logger;
use Psr\Log\LogLevel;
use WC_Order;
use WP_Error;
@@ -43,15 +49,26 @@ class MollieOrder extends MollieObject
* @param OrderItemsRefunder $orderItemsRefunder
* @param $data
*/
- public function __construct(OrderItemsRefunder $orderItemsRefunder, $data, $pluginId, Api $apiHelper, $settingsHelper, $dataHelper, $logger, OrderLines $orderLines)
- {
+ public function __construct(
+ OrderItemsRefunder $orderItemsRefunder,
+ $data,
+ string $pluginId,
+ Api $apiHelper,
+ Settings $settingsHelper,
+ Data $dataHelper,
+ Logger $logger,
+ OrderLines $orderLines,
+ RequestFactory $requestFactory
+ ) {
+
$this->data = $data;
$this->orderItemsRefunder = $orderItemsRefunder;
$this->pluginId = $pluginId;
$this->apiHelper = $apiHelper;
$this->settingsHelper = $settingsHelper;
- $this->dataHelper = $dataHelper;
$this->logger = $logger;
+ $this->requestFactory = $requestFactory;
+ $this->dataHelper = $dataHelper;
$this->orderLines = $orderLines;
}
@@ -78,92 +95,7 @@ public function getPaymentObject($paymentId, $testMode = false, $useCache = true
*/
public function getPaymentRequestData($order, $customerId, $voucherDefaultCategory = Voucher::NO_CATEGORY)
{
- $settingsHelper = $this->settingsHelper;
- $paymentLocale = $settingsHelper->getPaymentLocale();
- $storeCustomer = $settingsHelper->shouldStoreCustomer();
-
- $gateway = wc_get_payment_gateway_by_order($order);
-
- if (! $gateway || ! ( $gateway instanceof MolliePaymentGateway )) {
- return [ 'result' => 'failure' ];
- }
-
- $gatewayId = $gateway->id;
- $selectedIssuer = $gateway->getSelectedIssuer();
- $returnUrl = $gateway->get_return_url($order);
- $returnUrl = $this->getReturnUrl($order, $returnUrl);
- $webhookUrl = $this->getWebhookUrl($order, $gatewayId);
- $isPayPalExpressOrder = $order->get_meta('_mollie_payment_method_button') === 'PayPalButton';
- $billingAddress = null;
- if (!$isPayPalExpressOrder) {
- $billingAddress = $this->createBillingAddress($order);
- $shippingAddress = $this->createShippingAddress($order);
- }
-
- // Generate order lines for Mollie Orders
- $orderLinesHelper = $this->orderLines;
- $orderLines = $orderLinesHelper->order_lines($order, $voucherDefaultCategory);
-
- // Build the Mollie order data
- $paymentRequestData = [
- 'amount' => [
- 'currency' => $this->dataHelper->getOrderCurrency($order),
- 'value' => $this->dataHelper->formatCurrencyValue(
- $order->get_total(),
- $this->dataHelper->getOrderCurrency($order)
- ),
- ],
- 'redirectUrl' => $returnUrl,
- 'webhookUrl' => $webhookUrl,
- 'method' => $gateway->paymentMethod()->getProperty('id'),
- 'payment' => [
- 'issuer' => $selectedIssuer,
- ],
- 'locale' => $paymentLocale,
- 'billingAddress' => $billingAddress,
- 'metadata' => apply_filters(
- $this->pluginId . '_payment_object_metadata',
- [
- 'order_id' => $order->get_id(),
- 'order_number' => $order->get_order_number(),
- ]
- ),
- 'lines' => $orderLines['lines'],
- 'orderNumber' => $order->get_order_number(),
- ];
-
- $paymentRequestData = $this->addSequenceTypeForSubscriptionsFirstPayments($order->get_id(), $gateway, $paymentRequestData);
-
- // Only add shippingAddress if all required fields are set
- if (
- !empty($shippingAddress->streetAndNumber)
- && !empty($shippingAddress->postalCode)
- && !empty($shippingAddress->city)
- && !empty($shippingAddress->country)
- ) {
- $paymentRequestData['shippingAddress'] = $shippingAddress;
- }
-
- // Only store customer at Mollie if setting is enabled
- if ($storeCustomer) {
- $paymentRequestData['payment']['customerId'] = $customerId;
- }
-
- $cardToken = mollieWooCommerceCardToken();
- if ($cardToken && isset($paymentRequestData['payment'])) {
- $paymentRequestData['payment']['cardToken'] = $cardToken;
- }
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $applePayToken = wc_clean(wp_unslash($_POST["token"] ?? ''));
- if ($applePayToken && isset($paymentRequestData['payment'])) {
- $encodedApplePayToken = wp_json_encode($applePayToken);
- $paymentRequestData['payment']['applePayPaymentToken'] = $encodedApplePayToken;
- }
- $customerBirthdate = $this->getCustomerBirthdate($order);
- if ($customerBirthdate) {
- $paymentRequestData['consumerDateOfBirth'] = $customerBirthdate;
- }
- return $paymentRequestData;
+ return $this->requestFactory->createRequest('order', $order, $customerId);
}
public function setActiveMolliePayment($orderId)
@@ -223,7 +155,15 @@ public function getMollieCustomerIbanDetailsFromPaymentObject($payment = null)
$ibanDetails = [];
if (isset($payment->_embedded->payments[0]->id)) {
- $actualPayment = new MolliePayment($payment->_embedded->payments[0]->id, $this->pluginId, $this->apiHelper, $this->settingsHelper, $this->dataHelper, $this->logger);
+ $actualPayment = new MolliePayment(
+ $payment->_embedded->payments[0]->id,
+ $this->pluginId,
+ $this->apiHelper,
+ $this->settingsHelper,
+ $this->dataHelper,
+ $this->logger,
+ $this->requestFactory
+ );
$actualPayment = $actualPayment->getPaymentObject($actualPayment->data);
/**
* @var Payment $actualPayment
@@ -235,12 +175,6 @@ public function getMollieCustomerIbanDetailsFromPaymentObject($payment = null)
return $ibanDetails;
}
- public function addSequenceTypeFirst($paymentRequestData)
- {
- $paymentRequestData['payment']['sequenceType'] = 'first';
- return $paymentRequestData;
- }
-
/**
* @param WC_Order $order
* @param Order $payment
@@ -840,8 +774,8 @@ protected function maybeUpdateStatus(
) {
$gateway = wc_get_payment_gateway_by_order($order);
- if (!$this->isOrderPaymentStartedByOtherGateway($order) && is_a($gateway, MolliePaymentGateway::class)) {
- $gateway->paymentService()->updateOrderStatus($order, $newOrderStatus);
+ if (!$this->isOrderPaymentStartedByOtherGateway($order) && is_a($gateway, PaymentGateway::class)) {
+ $this->updateOrderStatus($order, $newOrderStatus);
} else {
$this->informNotUpdatingStatus($gateway->id, $order);
}
@@ -993,30 +927,8 @@ protected function processOrderItemsRefund(
unset($items[$item->get_id()]);
}
- protected function getCustomerBirthdate($order)
+ public function setOrder($data)
{
- $gateway = wc_get_payment_gateway_by_order($order);
- if (!$gateway || !isset($gateway->id)) {
- return null;
- }
- if (strpos($gateway->id, 'mollie_wc_gateway_') === false) {
- return null;
- }
- $additionalFields = $gateway->paymentMethod()->getProperty('additionalFields');
- $methodId = $additionalFields && in_array('birthdate', $additionalFields, true);
- if ($methodId) {
- $optionName = 'billing_birthdate_' . $gateway->paymentMethod()->getProperty('id');
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $fieldPosted = wc_clean(wp_unslash($_POST[$optionName] ?? ''));
- if ($fieldPosted === '' || !is_string($fieldPosted)) {
- return null;
- }
-
- $order->update_meta_data($optionName, $fieldPosted);
- $order->save();
- $format = "Y-m-d";
- return gmdate($format, (int) strtotime($fieldPosted));
- }
- return null;
+ $this->data = $data;
}
}
diff --git a/src/Payment/MollieOrderService.php b/src/Payment/MollieOrderService.php
index 369dae463..65a74f373 100644
--- a/src/Payment/MollieOrderService.php
+++ b/src/Payment/MollieOrderService.php
@@ -4,14 +4,16 @@
namespace Mollie\WooCommerce\Payment;
+use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Payment;
use Mollie\WooCommerce\Gateway\AbstractGateway;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
+use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface as Logger;
use Psr\Log\LogLevel;
use WC_Order;
@@ -36,16 +38,18 @@ class MollieOrderService
*/
protected $data;
protected $pluginId;
+ private ContainerInterface $container;
/**
- * PaymentService constructor.
+ * MollieOrderService constructor.
*/
public function __construct(
HttpResponse $httpResponse,
Logger $logger,
PaymentFactory $paymentFactory,
Data $data,
- string $pluginId
+ string $pluginId,
+ ContainerInterface $container
) {
$this->httpResponse = $httpResponse;
@@ -53,6 +57,7 @@ public function __construct(
$this->paymentFactory = $paymentFactory;
$this->data = $data;
$this->pluginId = $pluginId;
+ $this->container = $container;
}
public function setGateway($gateway)
@@ -92,7 +97,7 @@ public function onWebhookAction()
return;
}
$gateway = wc_get_payment_gateway_by_order($order);
- if (!$gateway instanceof MolliePaymentGateway) {
+ if (!mollieWooCommerceIsMollieGateway($gateway->id)) {
return;
}
$this->setGateway($gateway);
@@ -144,7 +149,7 @@ public function onWebhookAction()
if (! $this->orderNeedsPayment($order)) {
// TODO David: move to payment object?
// Add a debug message that order was already paid for
- $this->gateway->handlePaidOrderWebhook($order, $payment);
+ $this->handlePaidOrderWebhook($order, $payment);
// Check and process a possible refund or chargeback
$this->processRefunds($order, $payment);
@@ -182,6 +187,26 @@ public function onWebhookAction()
do_action($this->pluginId . '_after_webhook_action', $payment, $order);
// Status 200
}
+
+ /**
+ * @param $order
+ * @param $payment
+ */
+ public function handlePaidOrderWebhook($order, $payment)
+ {
+ // Duplicate webhook call
+ $this->httpResponse->setHttpResponseCode(204);
+
+ $order = wc_get_order($order);
+ $order_id = $order->get_id();
+
+ $this->logger->debug(
+ __METHOD__ . ' - ' . $this->id
+ . ": Order $order_id does not need a payment by Mollie (payment {$payment->id}).",
+ [true]
+ );
+ }
+
/**
* @param WC_Order $order
*
@@ -190,34 +215,36 @@ public function onWebhookAction()
public function orderNeedsPayment(WC_Order $order)
{
$order_id = $order->get_id();
+ $gateway = wc_get_payment_gateway_by_order($order);
+ $paymentMethod = $this->container->get('payment_gateway.getPaymentMethod')($gateway->id);
// Check whether the order is processed and paid via another gateway
if ($this->isOrderPaidByOtherGateway($order)) {
- $this->logger->debug(__METHOD__ . ' ' . $this->gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: no, previously processed by other (non-Mollie) gateway.', [true]);
+ $this->logger->debug(__METHOD__ . ' ' . $gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: no, previously processed by other (non-Mollie) gateway.', [true]);
return false;
}
// Check whether the order is processed and paid via Mollie
if (! $this->isOrderPaidAndProcessed($order)) {
- $this->logger->debug(__METHOD__ . ' ' . $this->gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, order not previously processed by Mollie gateway.', [true]);
+ $this->logger->debug(__METHOD__ . ' ' . $gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, order not previously processed by Mollie gateway.', [true]);
return true;
}
if ($order->needs_payment()) {
- $this->logger->debug(__METHOD__ . ' ' . $this->gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, WooCommerce thinks order needs payment.', [true]);
+ $this->logger->debug(__METHOD__ . ' ' . $gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, WooCommerce thinks order needs payment.', [true]);
return true;
}
// Has initial order status 'on-hold'
if (
- $this->gateway->paymentMethod()->getInitialOrderStatus() === SharedDataDictionary::STATUS_ON_HOLD
+ $paymentMethod->getInitialOrderStatus() === SharedDataDictionary::STATUS_ON_HOLD
&& $order->has_status(SharedDataDictionary::STATUS_ON_HOLD)
) {
$this->logger->debug(
- __METHOD__ . ' ' . $this->gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, has status On-Hold. ',
+ __METHOD__ . ' ' . $gateway->id . ': Order ' . $order_id . ' orderNeedsPayment check: yes, has status On-Hold. ',
[true]
);
return true;
@@ -734,10 +761,8 @@ protected function paymentTestModeNote($payment)
protected function getPaymentMethodTitle($payment)
{
$payment_method_title = '';
- if (!($this->gateway instanceof MolliePaymentGateway)) {
- return $payment_method_title;
- }
- if ($payment->method === $this->gateway->paymentMethod()->getProperty('id')) {
+
+ if ($payment->method === $this->gateway->id) {
$payment_method_title = $this->gateway->method_title;
}
return $payment_method_title;
diff --git a/src/Payment/MolliePayment.php b/src/Payment/MolliePayment.php
index f4dfbab5e..456d2bc10 100644
--- a/src/Payment/MolliePayment.php
+++ b/src/Payment/MolliePayment.php
@@ -4,18 +4,19 @@
namespace Mollie\WooCommerce\Payment;
+use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\Api\Exceptions\ApiException;
-use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Payment;
use Mollie\Api\Resources\Refund;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
-use Mollie\WooCommerce\Gateway\MolliePaymentGatewayI;
+use Mollie\WooCommerce\Payment\Request\RequestFactory;
use Mollie\WooCommerce\PaymentMethods\Voucher;
use Mollie\WooCommerce\SDK\Api;
+use Mollie\WooCommerce\Settings\Settings;
+use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
+use Psr\Log\LoggerInterface as Logger;
use Psr\Log\LogLevel;
use WC_Order;
-use WC_Payment_Gateway;
use WC_Subscriptions_Manager;
use WP_Error;
@@ -24,14 +25,23 @@ class MolliePayment extends MollieObject
public const ACTION_AFTER_REFUND_PAYMENT_CREATED = 'mollie-payments-for-woocommerce' . '_refund_payment_created';
protected $pluginId;
- public function __construct($data, $pluginId, Api $apiHelper, $settingsHelper, $dataHelper, $logger)
- {
+ public function __construct(
+ $data,
+ string $pluginId,
+ Api $apiHelper,
+ Settings $settingsHelper,
+ Data $dataHelper,
+ Logger $logger,
+ RequestFactory $requestFactory
+ ) {
+
$this->data = $data;
$this->pluginId = $pluginId;
$this->apiHelper = $apiHelper;
$this->settingsHelper = $settingsHelper;
- $this->dataHelper = $dataHelper;
$this->logger = $logger;
+ $this->requestFactory = $requestFactory;
+ $this->dataHelper = $dataHelper;
}
public function getPaymentObject($paymentId, $testMode = false, $useCache = true)
@@ -61,76 +71,7 @@ public function getPaymentObject($paymentId, $testMode = false, $useCache = true
*/
public function getPaymentRequestData($order, $customerId, $voucherDefaultCategory = Voucher::NO_CATEGORY)
{
- $settingsHelper = $this->settingsHelper;
- $optionName = $this->pluginId . '_' . 'api_payment_description';
- $option = get_option($optionName);
- $paymentDescription = $this->getPaymentDescription($order, $option);
- $paymentLocale = $settingsHelper->getPaymentLocale();
- $storeCustomer = $settingsHelper->shouldStoreCustomer();
-
- $gateway = wc_get_payment_gateway_by_order($order);
-
- if (!$gateway || !($gateway instanceof MolliePaymentGateway)) {
- return ['result' => 'failure'];
- }
-
- $gatewayId = $gateway->id;
- $selectedIssuer = $gateway->getSelectedIssuer();
- $returnUrl = $gateway->get_return_url($order);
- $returnUrl = $this->getReturnUrl($order, $returnUrl);
- $webhookUrl = $this->getWebhookUrl($order, $gatewayId);
- $orderId = $order->get_id();
-
- $paymentRequestData = [
- 'amount' => [
- 'currency' => $this->dataHelper
- ->getOrderCurrency($order),
- 'value' => $this->dataHelper
- ->formatCurrencyValue(
- $order->get_total(),
- $this->dataHelper->getOrderCurrency(
- $order
- )
- ),
- ],
- 'description' => $paymentDescription,
- 'redirectUrl' => $returnUrl,
- 'webhookUrl' => $webhookUrl,
- 'method' => $gateway->paymentMethod()->getProperty('id'),
- 'issuer' => $selectedIssuer,
- 'locale' => $paymentLocale,
- 'metadata' => apply_filters(
- $this->pluginId . '_payment_object_metadata',
- [
- 'order_id' => $order->get_id(),
- ]
- ),
- ];
-
- $paymentRequestData = $this->addSequenceTypeForSubscriptionsFirstPayments($order->get_id(), $gateway, $paymentRequestData);
-
- if ($storeCustomer) {
- $paymentRequestData['customerId'] = $customerId;
- }
-
- $cardToken = mollieWooCommerceCardToken();
- if ($cardToken) {
- $paymentRequestData['cardToken'] = $cardToken;
- }
- //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $applePayToken = wc_clean(wp_unslash($_POST["token"] ?? ''));
- if ($applePayToken) {
- $encodedApplePayToken = wp_json_encode($applePayToken);
- $paymentRequestData['applePayPaymentToken'] = $encodedApplePayToken;
- }
- $paymentRequestData = $this->addCustomRequestFields($order, $paymentRequestData, $gateway);
- return $paymentRequestData;
- }
-
- public function addSequenceTypeFirst($paymentRequestData)
- {
- $paymentRequestData['sequenceType'] = 'first';
- return $paymentRequestData;
+ return $this->requestFactory->createRequest('payment', $order, $customerId);
}
/**
@@ -515,7 +456,7 @@ public function refund(\WC_Order $order, $orderId, $paymentObject, $amount = nul
/**
* @param WC_Order $order
- * @param MolliePaymentGatewayI $gateway
+ * @param PaymentGateway $gateway
* @param $newOrderStatus
* @param $orderId
*/
@@ -525,27 +466,15 @@ protected function maybeUpdateStatus(
$newOrderStatus
) {
- if ($this->isOrderPaymentStartedByOtherGateway($order) || ! is_a($gateway, MolliePaymentGateway::class)) {
+ if ($this->isOrderPaymentStartedByOtherGateway($order) || ! is_a($gateway, PaymentGateway::class)) {
$this->informNotUpdatingStatus($gateway->id, $order);
return;
}
- $gateway->paymentService()->updateOrderStatus($order, $newOrderStatus);
+ $this->updateOrderStatus($order, $newOrderStatus);
}
- protected function addCustomRequestFields($order, array $paymentRequestData, MolliePaymentGateway $gateway)
+ public function setPayment($data)
{
- if ($gateway->paymentMethod()->hasProperty('paymentAPIfields')) {
- $paymentAPIfields = $gateway->paymentMethod()->getProperty('paymentAPIfields');
- foreach ($paymentAPIfields as $field) {
- if (!method_exists($this, 'create' . ucfirst($field))) {
- continue;
- }
- $value = $this->{'create' . ucfirst($field)}($order);
- if ($value) {
- $paymentRequestData[$field] = $value;
- }
- }
- }
- return $paymentRequestData;
+ $this->data = $data;
}
}
diff --git a/src/Payment/MollieSubscription.php b/src/Payment/MollieSubscription.php
index 1754bb619..8d9707afc 100644
--- a/src/Payment/MollieSubscription.php
+++ b/src/Payment/MollieSubscription.php
@@ -3,25 +3,33 @@
namespace Mollie\WooCommerce\Payment;
use Mollie\Api\Types\SequenceType;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Payment\Request\Middleware\MiddlewareHandler;
+use Mollie\WooCommerce\Payment\Request\Middleware\PaymentDescriptionMiddleware;
use Mollie\WooCommerce\SDK\Api;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
+use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
class MollieSubscription extends MollieObject
{
protected $pluginId;
+ /**
+ * @var mixed
+ */
+ private $paymentMethod;
+ protected MiddlewareHandler $middleware;
/**
* Molliesubscription constructor.
*
*/
- public function __construct($pluginId, Api $apiHelper, $settingsHelper, $dataHelper, $logger)
+ public function __construct($pluginId, Api $apiHelper, $settingsHelper, $dataHelper, $logger, $paymentMethod, $middlewareHandler)
{
$this->pluginId = $pluginId;
$this->apiHelper = $apiHelper;
$this->settingsHelper = $settingsHelper;
$this->dataHelper = $dataHelper;
$this->logger = $logger;
+ $this->paymentMethod = $paymentMethod;
+ $this->middleware = $middlewareHandler;
}
/**
* @param $order
@@ -33,19 +41,17 @@ public function getRecurringPaymentRequestData($order, $customerId, $initialPaym
$paymentLocale = $this->settingsHelper->getPaymentLocale();
$gateway = wc_get_payment_gateway_by_order($order);
- if (! $gateway || ! ( $gateway instanceof MolliePaymentGateway )) {
+ if (! $gateway || ! ( mollieWooCommerceIsMollieGateway($gateway->id) )) {
return [ 'result' => 'failure' ];
}
$gatewayId = $gateway->id;
+ $methodId = substr($gatewayId, strrpos($gatewayId, '_') + 1);
$optionName = $this->pluginId . '_api_payment_description';
$option = get_option($optionName);
$paymentDescription = $this->getRecurringPaymentDescription($order, $option, $initialPaymentUsedOrderAPI);
- $selectedIssuer = $gateway->getSelectedIssuer();
- $returnUrl = $gateway->get_return_url($order);
- $returnUrl = $this->getReturnUrl($order, $returnUrl);
- $webhookUrl = $this->getWebhookUrl($order, $gatewayId);
+ $selectedIssuer = $this->paymentMethod->getSelectedIssuer();
- return array_filter([
+ $requestData = array_filter([
'amount' => [
'currency' => $this->dataHelper->getOrderCurrency($order),
'value' => $this->dataHelper->formatCurrencyValue(
@@ -54,9 +60,7 @@ public function getRecurringPaymentRequestData($order, $customerId, $initialPaym
),
],
'description' => $paymentDescription,
- 'redirectUrl' => $returnUrl,
- 'webhookUrl' => $webhookUrl,
- 'method' => $gateway->paymentMethod()->getProperty('id'),
+ 'method' => $methodId,
'issuer' => $selectedIssuer,
'locale' => $paymentLocale,
'metadata' => [
@@ -65,6 +69,8 @@ public function getRecurringPaymentRequestData($order, $customerId, $initialPaym
'sequenceType' => 'recurring',
'customerId' => $customerId,
]);
+ $context = 'payment';
+ return $this->middleware->handle($requestData, $order, $context);
}
protected function getRecurringPaymentDescription($order, $option, $initialPaymentUsedOrderAPI)
@@ -84,34 +90,40 @@ protected function getRecurringPaymentDescription($order, $option, $initialPayme
);
return $description;
}
- return $this->getPaymentDescription($order, $option);
+ $middleware = new PaymentDescriptionMiddleware($this->dataHelper);
+ $requestData = [];
+ $context = 'payment';
+ $result = $middleware->__invoke($requestData, $order, $context, static function ($requestData) {
+ return $requestData;
+ });
+ return $result['description'];
}
/**
* Validate in the checkout if the gateway is available for subscriptions
*
* @param bool $status
- * @param MollieSubscriptionGateway $subscriptionGateway
+ * @param MollieSubscriptionGatewayHandler $deprecatedSubscriptionHelper
* @return bool
*/
- public function isAvailableForSubscriptions(bool $status, MollieSubscriptionGateway $subscriptionGateway, $orderTotal): bool
+ public function isAvailableForSubscriptions(bool $status, MollieSubscriptionGatewayHandler $deprecatedSubscriptionHelper, $orderTotal, $gateway): bool
{
$subscriptionPluginActive = class_exists('WC_Subscriptions') && class_exists('WC_Subscriptions_Admin');
if (!$subscriptionPluginActive) {
return $status;
}
- $currency = $subscriptionGateway->getCurrencyFromOrder();
- $billingCountry = $subscriptionGateway->getBillingCountry();
- $paymentLocale = $subscriptionGateway->dataService()->getPaymentLocale();
+ $currency = $deprecatedSubscriptionHelper->getCurrencyFromOrder();
+ $billingCountry = $deprecatedSubscriptionHelper->getBillingCountry();
+ $paymentLocale = $deprecatedSubscriptionHelper->dataService()->getPaymentLocale();
// Check recurring totals against recurring payment methods for future renewal payments
- $recurringTotal = $subscriptionGateway->get_recurring_total();
+ $recurringTotal = $deprecatedSubscriptionHelper->get_recurring_total();
// See get_available_payment_gateways() in woocommerce-subscriptions/includes/gateways/class-wc-subscriptions-payment-gateways.php
$acceptManualRenewals = 'yes' === get_option(
\WC_Subscriptions_Admin::$option_prefix
. '_accept_manual_renewals',
'no'
);
- $supportsSubscriptions = $subscriptionGateway->supports('subscriptions');
+ $supportsSubscriptions = $gateway->supports('subscriptions');
if ($acceptManualRenewals === true || !$supportsSubscriptions || empty($recurringTotal)) {
return $status;
}
@@ -124,11 +136,11 @@ public function isAvailableForSubscriptions(bool $status, MollieSubscriptionGate
SequenceType::SEQUENCETYPE_RECURRING,
$paymentLocale
);
- $status = $subscriptionGateway->isAvailableMethodInCheckout($filters);
+ $status = $deprecatedSubscriptionHelper->isAvailableMethodInCheckout($filters);
}
// Check available first payment methods with today's order total, but ignore SSD gateway (not shown in checkout)
- if ($subscriptionGateway->paymentMethod()->getProperty('id') === 'mollie_wc_gateway_directdebit') {
+ if ($deprecatedSubscriptionHelper->paymentMethod()->getProperty('id') === 'mollie_wc_gateway_directdebit') {
return $status;
}
$filters = $this->buildFilters(
@@ -138,7 +150,7 @@ public function isAvailableForSubscriptions(bool $status, MollieSubscriptionGate
SequenceType::SEQUENCETYPE_FIRST,
$paymentLocale
);
- return $subscriptionGateway->isAvailableMethodInCheckout($filters);
+ return $deprecatedSubscriptionHelper->isAvailableMethodInCheckout($filters);
}
/**
diff --git a/src/Payment/OrderInstructionsService.php b/src/Payment/OrderInstructionsService.php
deleted file mode 100644
index bac70c4a4..000000000
--- a/src/Payment/OrderInstructionsService.php
+++ /dev/null
@@ -1,32 +0,0 @@
-paymentMethod()->getProperty('instructions')) {
- $this->strategy = new DefaultInstructionStrategy();
- } else {
- $className = 'Mollie\\WooCommerce\\PaymentMethods\\InstructionStrategies\\' . ucfirst($gateway->paymentMethod()->getProperty('id')) . 'InstructionStrategy';
- $this->strategy = class_exists($className) ? new $className() : new DefaultInstructionStrategy();
- }
- }
-
- public function executeStrategy(
- MolliePaymentGatewayI $gateway,
- $payment,
- $order = null,
- $admin_instructions = false
- ) {
-
- return $this->strategy->execute($gateway, $payment, $order, $admin_instructions);
- }
-}
diff --git a/src/Payment/PaymentCheckoutRedirectService.php b/src/Payment/PaymentCheckoutRedirectService.php
index a73127480..68c1d3e0e 100644
--- a/src/Payment/PaymentCheckoutRedirectService.php
+++ b/src/Payment/PaymentCheckoutRedirectService.php
@@ -21,7 +21,7 @@ class PaymentCheckoutRedirectService
protected $dataHelper;
/**
- * PaymentService constructor.
+ * PaymentCheckoutRedirectService constructor.
*/
public function __construct($dataHelper)
{
diff --git a/src/Payment/PaymentFactory.php b/src/Payment/PaymentFactory.php
index 051348158..2a88ab2fb 100644
--- a/src/Payment/PaymentFactory.php
+++ b/src/Payment/PaymentFactory.php
@@ -12,36 +12,16 @@
class PaymentFactory
{
- /**
- * @var Data
- */
- protected $dataHelper;
- /**
- * @var Api
- */
- protected $apiHelper;
- protected $settingsHelper;
- /**
- * @var string
- */
- protected $pluginId;
- protected $logger;
- /**
- * @var OrderLines
- */
- protected $orderLines;
+ private $mollieOrderFactory;
+ private $molliePaymentFactory;
/**
* PaymentFactory constructor.
*/
- public function __construct(Data $dataHelper, Api $apiHelper, Settings $settingsHelper, string $pluginId, $logger, OrderLines $orderLines)
+ public function __construct(callable $mollieOrderFactory, callable $molliePaymentFactory)
{
- $this->dataHelper = $dataHelper;
- $this->apiHelper = $apiHelper;
- $this->settingsHelper = $settingsHelper;
- $this->pluginId = $pluginId;
- $this->logger = $logger;
- $this->orderLines = $orderLines;
+ $this->mollieOrderFactory = $mollieOrderFactory;
+ $this->molliePaymentFactory = $molliePaymentFactory;
}
/**
@@ -57,24 +37,9 @@ public function getPaymentObject($data)
|| (is_string($data) && strpos($data, 'ord_') !== false)
|| (is_object($data) && $data->resource === 'order')
) {
- $refundLineItemsBuilder = new RefundLineItemsBuilder($this->dataHelper);
- $apiKey = $this->settingsHelper->getApiKey();
- $orderItemsRefunded = new OrderItemsRefunder(
- $refundLineItemsBuilder,
- $this->dataHelper,
- $this->apiHelper->getApiClient($apiKey)->orders
- );
-
- return new MollieOrder(
- $orderItemsRefunded,
- $data,
- $this->pluginId,
- $this->apiHelper,
- $this->settingsHelper,
- $this->dataHelper,
- $this->logger,
- $this->orderLines
- );
+ $mollieOrder = ($this->mollieOrderFactory)();
+ $mollieOrder->setOrder($data);
+ return $mollieOrder;
}
if (
@@ -82,14 +47,9 @@ public function getPaymentObject($data)
|| (!is_object($data) && strpos($data, 'tr_') !== false)
|| (is_object($data) && $data->resource === 'payment')
) {
- return new MolliePayment(
- $data,
- $this->pluginId,
- $this->apiHelper,
- $this->settingsHelper,
- $this->dataHelper,
- $this->logger
- );
+ $molliePayment = ($this->molliePaymentFactory)();
+ $molliePayment->setPayment($data);
+ return $molliePayment;
}
return false;
diff --git a/src/Payment/PaymentFieldsService.php b/src/Payment/PaymentFieldsService.php
deleted file mode 100644
index c5eaebc3b..000000000
--- a/src/Payment/PaymentFieldsService.php
+++ /dev/null
@@ -1,51 +0,0 @@
-dataHelper = $dataHelper;
- }
-
- public function setStrategy($paymentMethod)
- {
- if (!$paymentMethod->getProperty('paymentFields')) {
- $this->strategy = new DefaultFieldsStrategy();
- } else {
- $className = 'Mollie\\WooCommerce\\PaymentMethods\\PaymentFieldsStrategies\\' . ucfirst($paymentMethod->getProperty('id')) . 'FieldsStrategy';
- $this->strategy = class_exists($className) ? new $className() : new DefaultFieldsStrategy();
- }
- }
-
- public function executeStrategy($gateway)
- {
- return $this->strategy->execute($gateway, $this->dataHelper);
- }
-
- public function getStrategyMarkup($gateway)
- {
- return $this->strategy->getFieldMarkup($gateway, $this->dataHelper);
- }
-}
diff --git a/src/Payment/PaymentModule.php b/src/Payment/PaymentModule.php
index 798640775..ba6e406ee 100644
--- a/src/Payment/PaymentModule.php
+++ b/src/Payment/PaymentModule.php
@@ -11,16 +11,14 @@
use Inpsyde\Modularity\Module\ServiceModule;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Refund;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
-use Mollie\WooCommerce\Gateway\MolliePaymentGatewayI;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
+use Mollie\WooCommerce\Gateway\Refund\OrderItemsRefunder;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\Settings\Settings;
-use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
use RuntimeException;
use WC_Order;
@@ -49,40 +47,13 @@ class PaymentModule implements ServiceModule, ExecutableModule
public function services(): array
{
- return [
- OrderLines::class => static function (ContainerInterface $container): OrderLines {
- $data = $container->get('settings.data_helper');
- $pluginId = $container->get('shared.plugin_id');
- return new OrderLines($data, $pluginId);
- },
- PaymentFactory::class => static function (ContainerInterface $container): PaymentFactory {
- $settingsHelper = $container->get('settings.settings_helper');
- assert($settingsHelper instanceof Settings);
- $apiHelper = $container->get('SDK.api_helper');
- assert($apiHelper instanceof Api);
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- $pluginId = $container->get('shared.plugin_id');
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $orderLines = $container->get(OrderLines::class);
- return new PaymentFactory($data, $apiHelper, $settingsHelper, $pluginId, $logger, $orderLines);
- },
- MollieObject::class => static function (ContainerInterface $container): MollieObject {
- $logger = $container->get(Logger::class);
- assert($logger instanceof Logger);
- $data = $container->get('settings.data_helper');
- assert($data instanceof Data);
- $apiHelper = $container->get('SDK.api_helper');
- assert($apiHelper instanceof Api);
- $pluginId = $container->get('shared.plugin_id');
- $paymentFactory = $container->get(PaymentFactory::class);
- assert($paymentFactory instanceof PaymentFactory);
- $settingsHelper = $container->get('settings.settings_helper');
- assert($settingsHelper instanceof Settings);
- return new MollieObject($data, $logger, $paymentFactory, $apiHelper, $settingsHelper, $pluginId);
- },
- ];
+ static $services;
+
+ if ($services === null) {
+ $services = require_once __DIR__ . '/inc/services.php';
+ }
+
+ return $services();
}
public function run(ContainerInterface $container): bool
@@ -99,11 +70,17 @@ public function run(ContainerInterface $container): bool
$this->gatewayClassnames = $container->get('gateway.classnames');
// Listen to return URL call
- add_action('woocommerce_api_mollie_return', [ $this, 'onMollieReturn' ]);
- add_action('template_redirect', [ $this, 'mollieReturnRedirect' ]);
+ add_action('woocommerce_api_mollie_return', function () use ($container) {
+ $this->onMollieReturn($container);
+ }, 10, 1);
+ add_action('template_redirect', function () use ($container) {
+ $this->mollieReturnRedirect($container);
+ });
// Show Mollie instructions on order details page
- add_action('woocommerce_order_details_after_order_table', [ $this, 'onOrderDetails' ], 10, 1);
+ add_action('woocommerce_order_details_after_order_table', function (WC_Order $order) use ($container) {
+ $this->onOrderDetails($order, $container);
+ }, 10, 1);
// Cancel order at Mollie (for Orders API/Klarna)
add_action('woocommerce_order_status_cancelled', [ $this, 'cancelOrderAtMollie' ]);
@@ -252,7 +229,7 @@ public function addOrderNoteForCancelledLineItems(array $data, WC_Order $order)
* Old Payment return url callback
*
*/
- public function onMollieReturn()
+ public function onMollieReturn($container)
{
try {
$order = self::orderByRequest();
@@ -264,6 +241,8 @@ public function onMollieReturn()
$gateway = wc_get_payment_gateway_by_order($order);
$orderId = $order->get_id();
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ $mollieGatewayHelper = $oldGatewayInstances[$gateway->id];
if (!$gateway) {
$gatewayName = $order->get_payment_method();
@@ -275,13 +254,14 @@ public function onMollieReturn()
return;
}
- if (!($gateway instanceof MolliePaymentGateway)) {
+ if (!(mollieWooCommerceIsMollieGateway($gateway->id))) {
$this->httpResponse->setHttpResponseCode(400);
- $this->logger->debug(__METHOD__ . ": Invalid gateway {get_class($gateway)} for this plugin. Order {$orderId}.");
+ $gatewayClass = get_class($gateway);
+ $this->logger->debug(__METHOD__ . ": Invalid gateway {$gatewayClass} for this plugin. Order {$orderId}.");
return;
}
- $redirect_url = $gateway->getReturnRedirectUrlForOrder($order);
+ $redirect_url = $mollieGatewayHelper->getReturnRedirectUrlForOrder($order);
// Add utm_nooverride query string
$redirect_url = add_query_arg(['utm_nooverride' => 1], $redirect_url);
@@ -296,12 +276,12 @@ public function onMollieReturn()
* New Payment return url callback
*
*/
- public function mollieReturnRedirect()
+ public function mollieReturnRedirect($container)
{
if (isset($_GET['filter_flag'])) {
$filterFlag = sanitize_text_field(wp_unslash($_GET['filter_flag']));
if ($filterFlag === 'onMollieReturn') {
- self::onMollieReturn();
+ self::onMollieReturn($container);
}
}
}
@@ -309,27 +289,27 @@ public function mollieReturnRedirect()
/**
* @param WC_Order $order
*/
- public function onOrderDetails(WC_Order $order)
+ public function onOrderDetails(WC_Order $order, ContainerInterface $container)
{
if (is_order_received_page()) {
/**
* Do not show instruction again below details on order received page
* Instructions already displayed on top of order received page by $gateway->thankyou_page()
*
- * @see MolliePaymentGateway::thankyou_page
+ * @see MolliePaymentGatewayHandler::thankyou_page
*/
return;
}
$gateway = wc_get_payment_gateway_by_order($order);
- if (!$gateway || !($gateway instanceof MolliePaymentGateway)) {
+ if (!$gateway || !(mollieWooCommerceIsMollieGateway($gateway->id))) {
return;
}
- /** @var MolliePaymentGatewayI $gateway */
-
- $gateway->displayInstructions($order);
+ $oldGatewayInstances = $container->get('__deprecated.gateway_helpers');
+ $mollieGatewayHelper = $oldGatewayInstances[$gateway->id];
+ $mollieGatewayHelper->displayInstructions($order);
}
/**
* Ship all order lines and capture an order at Mollie.
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentProcessor.php
similarity index 96%
rename from src/Payment/PaymentService.php
rename to src/Payment/PaymentProcessor.php
index 87794c8c7..db09eff06 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentProcessor.php
@@ -4,11 +4,10 @@
namespace Mollie\WooCommerce\Payment;
+use Inpsyde\PaymentGateway\PaymentGateway;
+use Inpsyde\PaymentGateway\PaymentProcessorInterface;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Payment;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
-use Mollie\WooCommerce\Gateway\MolliePaymentGatewayI;
-use Mollie\WooCommerce\Gateway\Surcharge;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
@@ -17,18 +16,17 @@
use Mollie\WooCommerce\Shared\SharedDataDictionary;
use Mollie\WooCommerce\PaymentMethods\Constants;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
use WC_Order;
-class PaymentService
+class PaymentProcessor implements PaymentProcessorInterface
{
public const PAYMENT_METHOD_TYPE_ORDER = 'order';
public const PAYMENT_METHOD_TYPE_PAYMENT = 'payment';
/**
- * @var MolliePaymentGatewayI
+ * @var
*/
- protected $gateway;
+ protected $deprecatedGatewayHelper;
/**
* @var NoticeInterface
*/
@@ -56,9 +54,11 @@ class PaymentService
* @var string
*/
protected $voucherDefaultCategory;
+ private PaymentGateway $gateway;
+ private array $deprecatedGatewayInstances;
/**
- * PaymentService constructor.
+ * PaymentProcessor constructor.
*/
public function __construct(
NoticeInterface $notice,
@@ -69,7 +69,8 @@ public function __construct(
Settings $settingsHelper,
string $pluginId,
PaymentCheckoutRedirectService $paymentCheckoutRedirectService,
- string $voucherDefaultCategory
+ string $voucherDefaultCategory,
+ array $deprecatedGatewayInstances
) {
$this->notice = $notice;
@@ -81,15 +82,30 @@ public function __construct(
$this->pluginId = $pluginId;
$this->paymentCheckoutRedirectService = $paymentCheckoutRedirectService;
$this->voucherDefaultCategory = $voucherDefaultCategory;
+ $this->deprecatedGatewayInstances = $deprecatedGatewayInstances;
}
- public function setGateway($gateway)
+ public function setGatewayHelper(string $paymentGatewayId)
+ {
+ $this->deprecatedGatewayHelper = $this->deprecatedGatewayInstances[$paymentGatewayId] ?? false;
+ }
+
+ public function setGateway(PaymentGateway $gateway)
{
$this->gateway = $gateway;
}
- public function processPayment($orderId, $order, $paymentMethod, $redirectUrl)
+ public function processPayment($order, $paymentGateway): array
{
+ $orderId = $order->get_id();
+ $this->setGateway($paymentGateway);
+ $this->setGatewayHelper($paymentGateway->id);
+ if ($this->deprecatedGatewayHelper === false) {
+ return ['result' => 'failure'];
+ }
+
+ $redirectUrl = $paymentGateway->get_return_url($order);
+ $paymentMethod = $this->deprecatedGatewayHelper->paymentMethod();
$this->logger->debug(
"{$paymentMethod->getProperty('id')}: Start process_payment for order {$orderId}",
[true]
@@ -123,7 +139,6 @@ public function processPayment($orderId, $order, $paymentMethod, $redirectUrl)
$customerId,
$apiKey
);
-
$this->saveMollieInfo($order, $paymentObject);
$this->saveSubscriptionMandateData($orderId, $apiKey, $customerId, $paymentObject, $order);
do_action($this->pluginId . '_payment_created', $paymentObject, $order);
@@ -332,7 +347,7 @@ protected function processAsMollieOrder(
$paymentRequestData = $paymentObject->getPaymentRequestData(
$order,
$customer_id,
- $this->voucherDefaultCategory
+ $this->voucherDefaultCategory,
);
$data = array_filter($paymentRequestData);
@@ -532,6 +547,7 @@ protected function processPaymentForMollie(
if ($molliePaymentType === self::PAYMENT_METHOD_TYPE_ORDER) {
// if the capture is set to manual, and this is a credit card payment, we need to create a payment instead of an order
$captureType = get_option('mollie-payments-for-woocommerce_place_payment_onhold');
+
if ($captureType === 'later_capture' && $this->gateway->id === 'mollie_wc_gateway_creditcard') {
$this->logger->debug(
"{$this->gateway->id}: Create payment for order {$orderId} capture set to manual",
@@ -588,7 +604,6 @@ protected function saveMollieInfo($order, $payment)
// Set active Mollie payment
$payment_object->setActiveMolliePayment($order->get_id());
-
// Get Mollie Customer ID
$mollie_customer_id = $payment_object->getMollieCustomerIdFromPaymentObject($payment_object->data()->id);
diff --git a/src/Payment/Request/Middleware/AddCustomRequestFieldsMiddleware.php b/src/Payment/Request/Middleware/AddCustomRequestFieldsMiddleware.php
new file mode 100644
index 000000000..5cab99f3e
--- /dev/null
+++ b/src/Payment/Request/Middleware/AddCustomRequestFieldsMiddleware.php
@@ -0,0 +1,62 @@
+paymentMethods = $paymentMethods;
+ $this->container = $container;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data to be modified.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param mixed $context Additional context for the middleware.
+ * @param callable $next The next middleware to be called.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, $next): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ $methodId = substr($gateway->id, strrpos($gateway->id, '_') + 1);
+ $paymentMethod = $this->paymentMethods[$methodId];
+ if (property_exists($paymentMethod, 'paymentAPIfields')) {
+ $paymentAPIfields = $paymentMethod->paymentAPIfields;
+ foreach ($paymentAPIfields as $field) {
+ $middlewareClass = 'Mollie\\WooCommerce\\Payment\\Request\\Middleware' . $field;
+ if (class_exists($middlewareClass)) {
+ $middleware = $this->container->get($middlewareClass);
+ if ($middleware instanceof RequestMiddlewareInterface) {
+ $requestData = $middleware->__invoke($requestData, $order, $context, $next);
+ }
+ }
+ }
+ }
+ return $next($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php b/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php
new file mode 100644
index 000000000..7713b4d99
--- /dev/null
+++ b/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php
@@ -0,0 +1,93 @@
+dataHelper = $dataHelper;
+ $this->pluginId = $pluginId;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context The context of the request.
+ * @param callable $next The next middleware to call.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, callable $next): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ if ($gateway) {
+ $requestData = $this->addSequenceTypeForSubscriptionsFirstPayments($order->get_id(), $gateway, $requestData, $context);
+ }
+ return $next($requestData, $order, $context);
+ }
+
+ /**
+ * Add sequence type for the first payments of subscriptions.
+ *
+ * @param int $orderId The order ID.
+ * @param WC_Payment_Gateway $gateway The payment gateway.
+ * @param array $requestData The request data.
+ * @param string $context The context of the request.
+ * @return array The modified request data.
+ */
+ private function addSequenceTypeForSubscriptionsFirstPayments($orderId, $gateway, $requestData, $context): array
+ {
+ if ($this->dataHelper->isSubscription($orderId) || $this->dataHelper->isWcSubscription($orderId)) {
+ $disable_automatic_payments = apply_filters($this->pluginId . '_is_automatic_payment_disabled', false);
+ $supports_subscriptions = $gateway->supports('subscriptions');
+
+ if ($supports_subscriptions == true && $disable_automatic_payments == false) {
+ $requestData = $this->addSequenceTypeFirst($requestData, $context);
+ }
+ }
+ return $requestData;
+ }
+
+ /**
+ * Add the sequence type 'first' to the request data.
+ *
+ * @param array $requestData The request data.
+ * @param string $context The context of the request.
+ * @return array The modified request data.
+ */
+ private function addSequenceTypeFirst($requestData, $context)
+ {
+ if ($context === 'order') {
+ $requestData['payment']['sequenceType'] = 'first';
+ } elseif ($context === 'payment') {
+ $requestData['sequenceType'] = 'first';
+ }
+ return $requestData;
+ }
+}
diff --git a/src/Payment/Request/Middleware/AddressMiddleware.php b/src/Payment/Request/Middleware/AddressMiddleware.php
new file mode 100644
index 000000000..a9e1498f3
--- /dev/null
+++ b/src/Payment/Request/Middleware/AddressMiddleware.php
@@ -0,0 +1,295 @@
+ $requestData The request data to be modified.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param mixed $context Additional context for the middleware.
+ * @param callable $next The next middleware to be called.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, callable $next): array
+ {
+ $isPayPalExpressOrder = $order->get_meta('_mollie_payment_method_button') === 'PayPalButton';
+ $billingAddress = null;
+ if (!$isPayPalExpressOrder) {
+ $billingAddress = $this->createBillingAddress($order);
+ $shippingAddress = $this->createShippingAddress($order);
+ }
+ $requestData['billingAddress'] = $billingAddress;
+ // Only add shippingAddress if all required fields are set
+ if (
+ !empty($shippingAddress->streetAndNumber)
+ && !empty($shippingAddress->postalCode)
+ && !empty($shippingAddress->city)
+ && !empty($shippingAddress->country)
+ ) {
+ $requestData['shippingAddress'] = $shippingAddress;
+ }
+ return $next($requestData, $order, $context);
+ }
+
+ /**
+ * Create the billing address object.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @return stdClass The billing address object.
+ */
+ private function createBillingAddress(WC_Order $order): stdClass
+ {
+ // Setup billing and shipping objects
+ $billingAddress = new stdClass();
+
+ // Get user details
+ $billingAddress->givenName = (ctype_space(
+ $order->get_billing_first_name()
+ )) ? null : $order->get_billing_first_name();
+ $billingAddress->familyName = (ctype_space(
+ $order->get_billing_last_name()
+ )) ? null : $order->get_billing_last_name();
+ $billingAddress->email = (ctype_space($order->get_billing_email()))
+ ? null : $order->get_billing_email();
+ // Create billingAddress object
+ $billingAddress->streetAndNumber = (ctype_space(
+ $order->get_billing_address_1()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_address_1(),
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ $billingAddress->streetAdditional = (ctype_space(
+ $order->get_billing_address_2()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_address_2(),
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ $billingAddress->postalCode = (ctype_space(
+ $order->get_billing_postcode()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_postcode(),
+ self::MAXIMAL_LENGTH_POSTALCODE
+ );
+ $billingAddress->city = (ctype_space($order->get_billing_city()))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_city(),
+ self::MAXIMAL_LENGTH_CITY
+ );
+ $billingAddress->region = (ctype_space($order->get_billing_state()))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_state(),
+ self::MAXIMAL_LENGTH_REGION
+ );
+ $billingAddress->country = (ctype_space($order->get_billing_country()))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_billing_country(),
+ self::MAXIMAL_LENGTH_REGION
+ );
+ $billingAddress->organizationName = $this->billingCompanyField($order);
+ $phone = $this->getPhoneNumber($order);
+ $billingAddress->phone = (ctype_space($phone))
+ ? null
+ : $this->getFormatedPhoneNumber($phone);
+ return $billingAddress;
+ }
+
+ /**
+ * Create the shipping address object.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @return stdClass The shipping address object.
+ */
+ private function createShippingAddress(WC_Order $order): stdClass
+ {
+ $shippingAddress = new stdClass();
+ // Get user details
+ $shippingAddress->givenName = (ctype_space(
+ $order->get_shipping_first_name()
+ )) ? null : $order->get_shipping_first_name();
+ $shippingAddress->familyName = (ctype_space(
+ $order->get_shipping_last_name()
+ )) ? null : $order->get_shipping_last_name();
+ $shippingAddress->email = (ctype_space($order->get_billing_email()))
+ ? null
+ : $order->get_billing_email(); // WooCommerce doesn't have a shipping email
+
+ // Create shippingAddress object
+ $shippingAddress->streetAndNumber = (ctype_space(
+ $order->get_shipping_address_1()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_address_1(),
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ $shippingAddress->streetAdditional = (ctype_space(
+ $order->get_shipping_address_2()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_address_2(),
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ $shippingAddress->postalCode = (ctype_space(
+ $order->get_shipping_postcode()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_postcode(),
+ self::MAXIMAL_LENGTH_POSTALCODE
+ );
+ $shippingAddress->city = (ctype_space($order->get_shipping_city()))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_city(),
+ self::MAXIMAL_LENGTH_CITY
+ );
+ $shippingAddress->region = (ctype_space($order->get_shipping_state()))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_state(),
+ self::MAXIMAL_LENGTH_REGION
+ );
+ $shippingAddress->country = (ctype_space(
+ $order->get_shipping_country()
+ ))
+ ? null
+ : $this->maximalFieldLengths(
+ $order->get_shipping_country(),
+ self::MAXIMAL_LENGTH_REGION
+ );
+ return $shippingAddress;
+ }
+
+ /**
+ * Get the phone number from the order.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @return string|null The phone number.
+ */
+ protected function getPhoneNumber($order): ?string
+ {
+ $phone = !empty($order->get_billing_phone()) ? $order->get_billing_phone() : $order->get_shipping_phone();
+ if (empty($phone)) {
+ //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $phone = wc_clean(wp_unslash($_POST['billing_phone'] ?? ''));
+ }
+ return $phone;
+ }
+
+ /**
+ * Format the phone number.
+ *
+ * @param string $phone The phone number.
+ * @return string|null The formatted phone number.
+ */
+ protected function getFormatedPhoneNumber(string $phone): ?string
+ {
+ //remove whitespaces and all non numerical characters except +
+ $phone = preg_replace('/[^0-9+]+/', '', $phone);
+ if (!is_string($phone)) {
+ return null;
+ }
+ //check if phone starts with 06 and replace with +316
+ $phone = transformPhoneToNLFormat($phone);
+
+ //check that $phone is in E164 format or can be changed by api
+ if (is_string($phone) && preg_match('/^\+[1-9]\d{10,13}$|^[1-9]\d{9,13}$/', $phone)) {
+ return $phone;
+ }
+ return null;
+ }
+
+ /**
+ * Get the billing company field.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @return string|null The billing company field.
+ */
+ public function billingCompanyField($order): ?string
+ {
+ if (!trim($order->get_billing_company())) {
+ return $this->checkBillieCompanyField($order);
+ }
+ return $this->maximalFieldLengths(
+ $order->get_billing_company(),
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ }
+
+ /**
+ * Check the Billie company field.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @return string|null The Billie company field.
+ */
+ private function checkBillieCompanyField($order): ?string
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ if (!$gateway || !$gateway->id) {
+ return null;
+ }
+ $isBillieMethodId = $gateway->id === 'mollie_wc_gateway_billie';
+ if ($isBillieMethodId) {
+ //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $fieldPosted = wc_clean(wp_unslash($_POST["billing_company"] ?? ''));
+ if ($fieldPosted === '' || !is_string($fieldPosted)) {
+ return null;
+ }
+ return $this->maximalFieldLengths(
+ $fieldPosted,
+ self::MAXIMAL_LENGTH_ADDRESS
+ );
+ }
+ return null;
+ }
+
+ /**
+ * Method that shortens the field to a certain length.
+ *
+ * @param string $field The field to be shortened.
+ * @param int $maximalLength The maximal length of the field.
+ * @return string|null The shortened field.
+ */
+ protected function maximalFieldLengths($field, $maximalLength): ?string
+ {
+ if (!is_string($field)) {
+ return null;
+ }
+ if (is_int($maximalLength) && strlen($field) > $maximalLength) {
+ $field = substr($field, 0, $maximalLength);
+ $field = !$field ? null : $field;
+ }
+
+ return $field;
+ }
+}
diff --git a/src/Payment/Request/Middleware/ApplePayTokenMiddleware.php b/src/Payment/Request/Middleware/ApplePayTokenMiddleware.php
new file mode 100644
index 000000000..312f1dd31
--- /dev/null
+++ b/src/Payment/Request/Middleware/ApplePayTokenMiddleware.php
@@ -0,0 +1,38 @@
+paymentMethods = $paymentMethods;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context The context of the request.
+ * @param callable $next The next middleware to call.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, $next): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ if (!$gateway || !isset($gateway->id)) {
+ return $requestData;
+ }
+ if (strpos($gateway->id, 'mollie_wc_gateway_') === false) {
+ return $requestData;
+ }
+ $paymentMethodId = substr($gateway->id, strrpos($gateway->id, '_') + 1);
+ $paymentMethod = $this->paymentMethods[$paymentMethodId];
+ $additionalFields = $paymentMethod->getProperty('additionalFields');
+ $methodId = $additionalFields && in_array('birthdate', $additionalFields, true);
+ if ($methodId) {
+ $optionName = 'billing_birthdate_' . $paymentMethod->getProperty('id');
+ // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $fieldPosted = wc_clean(wp_unslash($_POST[$optionName] ?? ''));
+ if ($fieldPosted === '' || !is_string($fieldPosted)) {
+ return $requestData;
+ }
+
+ $order->update_meta_data($optionName, $fieldPosted);
+ $order->save();
+ $format = "Y-m-d";
+ $requestData['consumerDateOfBirth'] = gmdate($format, (int) strtotime($fieldPosted));
+ }
+ return $next($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Middleware/MiddlewareHandler.php b/src/Payment/Request/Middleware/MiddlewareHandler.php
new file mode 100644
index 000000000..61aae0862
--- /dev/null
+++ b/src/Payment/Request/Middleware/MiddlewareHandler.php
@@ -0,0 +1,67 @@
+middlewares = $middlewares;
+ }
+
+ /**
+ * Handle the request data through the middleware chain.
+ *
+ * @param array $requestData The request data.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context The context of the request.
+ * @return array The modified request data.
+ */
+ public function handle(array $requestData, WC_Order $order, $context): array
+ {
+ $middlewareChain = $this->createMiddlewareChain($this->middlewares);
+
+ return $middlewareChain($requestData, $order, $context);
+ }
+
+ /**
+ * Create a chain of middleware.
+ *
+ * @param array $middlewares The list of middleware.
+ * @return callable The middleware chain.
+ */
+ private function createMiddlewareChain(array $middlewares): callable
+ {
+ return array_reduce(
+ array_reverse($middlewares),
+ static function ($next, $middleware) {
+ return static function ($requestData, $order, $context) use ($middleware, $next) {
+ return $middleware($requestData, $order, $context, $next);
+ };
+ },
+ static function ($requestData) {
+ return $requestData;
+ }
+ );
+ }
+}
diff --git a/src/Payment/Request/Middleware/OrderLinesMiddleware.php b/src/Payment/Request/Middleware/OrderLinesMiddleware.php
new file mode 100644
index 000000000..33539e1ed
--- /dev/null
+++ b/src/Payment/Request/Middleware/OrderLinesMiddleware.php
@@ -0,0 +1,56 @@
+orderLines = $orderLines;
+ $this->voucherDefaultCategory = $voucherDefaultCategory;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context The context of the request.
+ * @param callable $next The next middleware to call.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, $next): array
+ {
+ $orderLines = $this->orderLines->order_lines($order, $this->voucherDefaultCategory);
+ $requestData['lines'] = $orderLines['lines'];
+ return $next($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Middleware/PaymentDescriptionMiddleware.php b/src/Payment/Request/Middleware/PaymentDescriptionMiddleware.php
new file mode 100644
index 000000000..1b4491579
--- /dev/null
+++ b/src/Payment/Request/Middleware/PaymentDescriptionMiddleware.php
@@ -0,0 +1,134 @@
+dataHelper = $dataHelper;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context The context of the request.
+ * @param callable $next The next middleware to call.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, string $context, $next): array
+ {
+ $optionName = $this->dataHelper->getPluginId() . '_' . 'api_payment_description';
+ $option = get_option($optionName);
+ $paymentDescription = $this->getPaymentDescription($order, $option);
+
+ $requestData['description'] = $paymentDescription;
+ return $next($requestData, $order, $context);
+ }
+
+ /**
+ * Get the payment description.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @param mixed $option The option value.
+ * @return string The payment description.
+ */
+ private function getPaymentDescription(WC_Order $order, $option): string
+ {
+ $description = !$option ? '' : trim($option);
+ $description = !$description ? '{orderNumber}' : $description;
+
+ switch ($description) {
+ case '{orderNumber}':
+ $description = _x(
+ 'Order {orderNumber}',
+ 'Payment description for {orderNumber}',
+ 'mollie-payments-for-woocommerce'
+ );
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ case '{storeName}':
+ $description = _x(
+ 'StoreName {storeName}',
+ 'Payment description for {storeName}',
+ 'mollie-payments-for-woocommerce'
+ );
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ case '{customer.firstname}':
+ $description = _x(
+ 'Customer Firstname {customer.firstname}',
+ 'Payment description for {customer.firstname}',
+ 'mollie-payments-for-woocommerce'
+ );
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ case '{customer.lastname}':
+ $description = _x(
+ 'Customer Lastname {customer.lastname}',
+ 'Payment description for {customer.lastname}',
+ 'mollie-payments-for-woocommerce'
+ );
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ case '{customer.company}':
+ $description = _x(
+ 'Customer Company {customer.company}',
+ 'Payment description for {customer.company}',
+ 'mollie-payments-for-woocommerce'
+ );
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ default:
+ $description = $this->replaceTagsDescription($order, $description);
+ break;
+ }
+
+ return !$description ? __('Order', 'woocommerce') . ' ' . $order->get_order_number() : $description;
+ }
+
+ /**
+ * Replace tags in the description with actual values.
+ *
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $description The description with tags.
+ * @return string The description with tags replaced.
+ */
+ private function replaceTagsDescription(WC_Order $order, string $description): string
+ {
+ $replacement_tags = [
+ '{orderNumber}' => $order->get_order_number(),
+ '{storeName}' => get_bloginfo('name'),
+ '{customer.firstname}' => $order->get_billing_first_name(),
+ '{customer.lastname}' => $order->get_billing_last_name(),
+ '{customer.company}' => $order->get_billing_company(),
+ ];
+ foreach ($replacement_tags as $tag => $replacement) {
+ $description = str_replace($tag, $replacement, $description);
+ }
+ return $description;
+ }
+}
diff --git a/src/Payment/Request/Middleware/RequestMiddlewareInterface.php b/src/Payment/Request/Middleware/RequestMiddlewareInterface.php
new file mode 100644
index 000000000..4916d9d4a
--- /dev/null
+++ b/src/Payment/Request/Middleware/RequestMiddlewareInterface.php
@@ -0,0 +1,19 @@
+pluginId = $pluginId;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data to be modified.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context Additional context for the middleware.
+ * @param callable $next The next middleware to be called.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, string $context, callable $next): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ if (!$gateway) {
+ return $next($requestData, $order, $context);
+ }
+
+ $gatewayId = $gateway->id;
+ $selectedIssuer = $this->getSelectedIssuer($gatewayId);
+ if (empty($selectedIssuer)) {
+ return $next($requestData, $order, $context);
+ }
+
+ if ($context === 'order') {
+ $requestData['payment']['issuer'] = $selectedIssuer;
+ } elseif ($context === 'payment') {
+ $requestData['issuer'] = $selectedIssuer;
+ }
+
+ return $next($requestData, $order, $context);
+ }
+
+ /**
+ * Get the selected issuer.
+ *
+ * @param string $gatewayId The payment gateway ID.
+ * @return string The selected issuer.
+ */
+ private function getSelectedIssuer(string $gatewayId): string
+ {
+ $issuer_id = $this->pluginId . '_issuer_' . $gatewayId;
+ // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $postedIssuer = wc_clean(wp_unslash($_POST[$issuer_id] ?? ''));
+ return !empty($postedIssuer) ? $postedIssuer : '';
+ }
+}
diff --git a/src/Payment/Request/Middleware/StoreCustomerMiddleware.php b/src/Payment/Request/Middleware/StoreCustomerMiddleware.php
new file mode 100644
index 000000000..45e24cef8
--- /dev/null
+++ b/src/Payment/Request/Middleware/StoreCustomerMiddleware.php
@@ -0,0 +1,55 @@
+settingsHelper = $settingsHelper;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data to be modified.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context Additional context for the middleware.
+ * @param callable $next The next middleware to be called.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, string $context, callable $next): array
+ {
+ $storeCustomer = $this->settingsHelper->shouldStoreCustomer();
+ if (!$storeCustomer) {
+ if ($context === 'order') {
+ unset($requestData['payment']['customerId']);
+ } elseif ($context === 'payment') {
+ unset($requestData['customerId']);
+ }
+ }
+ return $next($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Middleware/UrlMiddleware.php b/src/Payment/Request/Middleware/UrlMiddleware.php
new file mode 100644
index 000000000..464b92859
--- /dev/null
+++ b/src/Payment/Request/Middleware/UrlMiddleware.php
@@ -0,0 +1,192 @@
+pluginId = $pluginId;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Invoke the middleware.
+ *
+ * @param array $requestData The request data to be modified.
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string $context Additional context for the middleware.
+ * @param callable $next The next middleware to be called.
+ * @return array The modified request data.
+ */
+ public function __invoke(array $requestData, WC_Order $order, $context, $next): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+ if ($gateway) {
+ $returnUrl = $gateway->get_return_url($order);
+ $returnUrl = $this->getReturnUrl($order, $returnUrl);
+ $webhookUrl = $this->getWebhookUrl($order, $gateway->id);
+
+ $requestData['redirectUrl'] = $returnUrl;
+ $requestData['webhookUrl'] = $webhookUrl;
+ }
+ return $next($requestData, $order, $context);
+ }
+
+ /**
+ * Get the URL to return to on Mollie return.
+ * Saves the return redirect and failed redirect, so we save the page language in case there is one set.
+ * For example 'http://mollie-wc.docker.myhost/wc-api/mollie_return/?order_id=89&key=wc_order_eFZyH8jki6fge'.
+ *
+ * @param WC_Order $order The order processed.
+ * @param string $returnUrl The base return URL.
+ * @return string The URL with order ID and key as params.
+ */
+ private function getReturnUrl(WC_Order $order, string $returnUrl): string
+ {
+ $returnUrl = untrailingslashit($returnUrl);
+ $returnUrl = $this->asciiDomainName($returnUrl);
+ $orderId = $order->get_id();
+ $orderKey = $order->get_order_key();
+
+ $onMollieReturn = 'onMollieReturn';
+ $returnUrl = $this->appendOrderArgumentsToUrl(
+ $orderId,
+ $orderKey,
+ $returnUrl,
+ $onMollieReturn
+ );
+ $returnUrl = untrailingslashit($returnUrl);
+ $this->logger->debug(" Order {$orderId} returnUrl: {$returnUrl}", [true]);
+
+ return apply_filters($this->pluginId . '_return_url', $returnUrl, $order);
+ }
+
+ /**
+ * Get the webhook URL.
+ * For example 'http://mollie-wc.docker.myhost/wc-api/mollie_return/mollie_wc_gateway_bancontact/?order_id=89&key=wc_order_eFZyH8jki6fge'.
+ *
+ * @param WC_Order $order The order processed.
+ * @param string $gatewayId The payment gateway ID.
+ * @return string The URL with gateway and order ID and key as params.
+ */
+ public function getWebhookUrl(WC_Order $order, string $gatewayId): string
+ {
+ $webhookUrl = WC()->api_request_url($gatewayId);
+ $webhookUrl = untrailingslashit($webhookUrl);
+ $webhookUrl = $this->asciiDomainName($webhookUrl);
+ $orderId = $order->get_id();
+ $orderKey = $order->get_order_key();
+ $webhookUrl = $this->appendOrderArgumentsToUrl(
+ $orderId,
+ $orderKey,
+ $webhookUrl
+ );
+ $webhookUrl = untrailingslashit($webhookUrl);
+
+ $this->logger->debug(" Order {$orderId} webhookUrl: {$webhookUrl}", [true]);
+
+ return apply_filters($this->pluginId . '_webhook_url', $webhookUrl, $order);
+ }
+
+ /**
+ * Convert the domain name in a URL to ASCII.
+ *
+ * @param string $url The URL to convert.
+ * @return string The URL with the domain name in ASCII.
+ */
+ protected function asciiDomainName(string $url): string
+ {
+ $parsed = wp_parse_url($url);
+ $scheme = isset($parsed['scheme']) ? $parsed['scheme'] : '';
+ $domain = isset($parsed['host']) ? $parsed['host'] : false;
+ $query = isset($parsed['query']) ? $parsed['query'] : '';
+ $path = isset($parsed['path']) ? $parsed['path'] : '';
+ if (!$domain) {
+ return $url;
+ }
+
+ if (function_exists('idn_to_ascii')) {
+ $domain = $this->idnEncodeDomain($domain);
+ $url = $scheme . "://" . $domain . $path . '?' . $query;
+ }
+
+ return $url;
+ }
+
+ /**
+ * Append order arguments to a URL.
+ *
+ * @param int $order_id The order ID.
+ * @param string $order_key The order key.
+ * @param string $webhook_url The base webhook URL.
+ * @param string $filterFlag An optional filter flag.
+ * @return string The URL with appended order arguments.
+ */
+ protected function appendOrderArgumentsToUrl(int $order_id, string $order_key, string $webhook_url, string $filterFlag = ''): string
+ {
+ $webhook_url = add_query_arg(
+ [
+ 'order_id' => $order_id,
+ 'key' => $order_key,
+ 'filter_flag' => $filterFlag,
+ ],
+ $webhook_url
+ );
+ return $webhook_url;
+ }
+
+ /**
+ * Encode a domain name to ASCII.
+ *
+ * @param string $domain The domain name to encode.
+ * @return string The encoded domain name.
+ */
+ protected function idnEncodeDomain(string $domain): string
+ {
+ if (
+ defined('IDNA_NONTRANSITIONAL_TO_ASCII')
+ && defined('INTL_IDNA_VARIANT_UTS46')
+ ) {
+ $domain = idn_to_ascii(
+ $domain,
+ IDNA_NONTRANSITIONAL_TO_ASCII,
+ INTL_IDNA_VARIANT_UTS46
+ ) ? idn_to_ascii(
+ $domain,
+ IDNA_NONTRANSITIONAL_TO_ASCII,
+ INTL_IDNA_VARIANT_UTS46
+ ) : $domain;
+ } else {
+ $domain = idn_to_ascii($domain) ? idn_to_ascii($domain) : $domain;
+ }
+ return $domain;
+ }
+}
diff --git a/src/Payment/Request/RequestFactory.php b/src/Payment/Request/RequestFactory.php
new file mode 100644
index 000000000..1f67f4ce7
--- /dev/null
+++ b/src/Payment/Request/RequestFactory.php
@@ -0,0 +1,54 @@
+container = $container;
+ }
+
+ /**
+ * Create a request based on the type.
+ *
+ * @param string $type The type of request ('order' or 'payment').
+ * @param WC_Order $order The WooCommerce order object.
+ * @param string|null $customerId The customer ID for the request.
+ * @return array The generated request data.
+ * @throws \InvalidArgumentException If the strategy for the given type is invalid.
+ */
+ public function createRequest(string $type, WC_Order $order, $customerId): array
+ {
+ // Use the container to fetch the appropriate strategy.
+ $serviceName = "request.strategy.{$type}";
+ $strategy = $this->container->get($serviceName);
+
+ if (!$strategy instanceof RequestStrategyInterface) {
+ throw new \InvalidArgumentException("Invalid strategy for type: {$type}");
+ }
+
+ return $strategy->createRequest($order, $customerId);
+ }
+}
diff --git a/src/Payment/Request/Strategies/OrderRequestStrategy.php b/src/Payment/Request/Strategies/OrderRequestStrategy.php
new file mode 100644
index 000000000..390c0fc55
--- /dev/null
+++ b/src/Payment/Request/Strategies/OrderRequestStrategy.php
@@ -0,0 +1,93 @@
+dataHelper = $dataHelper;
+ $this->settingsHelper = $settingsHelper;
+ $this->middlewareHandler = $middlewareHandler;
+ }
+
+ /**
+ * Create a payment request for the given order.
+ *
+ * @param WC_Order $order The order to create a request for.
+ * @param string $customerId The customer ID.
+ * @return array The request data.
+ */
+ public function createRequest(WC_Order $order, $customerId): array
+ {
+ $settingsHelper = $this->settingsHelper;
+
+ $gateway = wc_get_payment_gateway_by_order($order);
+
+ if (! $gateway || ! ( mollieWooCommerceIsMollieGateway($gateway->id) )) {
+ return [ 'result' => 'failure' ];
+ }
+
+ $methodId = substr($gateway->id, strrpos($gateway->id, '_') + 1);
+ $paymentLocale = $settingsHelper->getPaymentLocale();
+ $requestData = [
+ 'amount' => [
+ 'currency' => $this->dataHelper->getOrderCurrency($order),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ $order->get_total(),
+ $this->dataHelper->getOrderCurrency($order)
+ ),
+ ],
+ 'method' => $methodId,
+ 'locale' => $paymentLocale,
+ 'metadata' => apply_filters(
+ $this->dataHelper->getPluginId() . '_payment_object_metadata',
+ [
+ 'order_id' => $order->get_id(),
+ 'order_number' => $order->get_order_number(),
+ ]
+ ),
+ 'orderNumber' => $order->get_order_number(),
+ 'payment' => [
+ 'customerId' => $customerId,
+ ],
+ ];
+
+ $context = 'order';
+ return $this->middlewareHandler->handle($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Strategies/PaymentRequestStrategy.php b/src/Payment/Request/Strategies/PaymentRequestStrategy.php
new file mode 100644
index 000000000..749923e21
--- /dev/null
+++ b/src/Payment/Request/Strategies/PaymentRequestStrategy.php
@@ -0,0 +1,90 @@
+dataHelper = $dataHelper;
+ $this->settingsHelper = $settingsHelper;
+ $this->middlewareHandler = $middlewareHandler;
+ }
+
+ /**
+ * Create a payment request for the given order.
+ *
+ * @param WC_Order $order The order to create a request for.
+ * @param string $customerId The customer ID.
+ * @return array The request data.
+ */
+ public function createRequest(WC_Order $order, $customerId): array
+ {
+ $gateway = wc_get_payment_gateway_by_order($order);
+
+ if (!$gateway || !(mollieWooCommerceIsMollieGateway($gateway->id))) {
+ return ['result' => 'failure'];
+ }
+
+ $settingsHelper = $this->settingsHelper;
+ $methodId = substr($gateway->id, strrpos($gateway->id, '_') + 1);
+ $paymentLocale = $settingsHelper->getPaymentLocale();
+
+ $requestData = [
+ 'amount' => [
+ 'currency' => $this->dataHelper->getOrderCurrency($order),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ $order->get_total(),
+ $this->dataHelper->getOrderCurrency($order)
+ ),
+ ],
+ 'method' => $methodId,
+ 'locale' => $paymentLocale,
+ 'metadata' => apply_filters(
+ $this->dataHelper->getPluginId() . '_payment_object_metadata',
+ [
+ 'order_id' => $order->get_id(),
+ ]
+ ),
+ 'customerId' => $customerId,
+ ];
+
+ $context = 'payment';
+ return $this->middlewareHandler->handle($requestData, $order, $context);
+ }
+}
diff --git a/src/Payment/Request/Strategies/RequestStrategyInterface.php b/src/Payment/Request/Strategies/RequestStrategyInterface.php
new file mode 100644
index 000000000..631ecb75c
--- /dev/null
+++ b/src/Payment/Request/Strategies/RequestStrategyInterface.php
@@ -0,0 +1,24 @@
+ static function (ContainerInterface $container): MollieObject {
+ $logger = $container->get(Logger::class);
+ assert($logger instanceof Logger);
+ $data = $container->get('settings.data_helper');
+ assert($data instanceof Data);
+ $apiHelper = $container->get('SDK.api_helper');
+ assert($apiHelper instanceof Api);
+ $pluginId = $container->get('shared.plugin_id');
+ $paymentFactory = $container->get(PaymentFactory::class);
+ //assert($paymentFactory instanceof PaymentFactory);
+ $settingsHelper = $container->get('settings.settings_helper');
+ assert($settingsHelper instanceof Settings);
+ $requestFactory = $container->get(RequestFactory::class);
+ return new MollieObject($data, $logger, $paymentFactory, $apiHelper, $settingsHelper, $pluginId, $requestFactory);
+ },
+ OrderLines::class => static function (ContainerInterface $container): OrderLines {
+ $data = $container->get('settings.data_helper');
+ $pluginId = $container->get('shared.plugin_id');
+ return new OrderLines($data, $pluginId);
+ },
+
+ PaymentFactory::class => static function (ContainerInterface $container): PaymentFactory {
+ return new PaymentFactory(
+ static function () use ($container) {
+ return new MollieOrder(
+ $container->get(OrderItemsRefunder::class),
+ 'order',
+ $container->get('shared.plugin_id'),
+ $container->get('SDK.api_helper'),
+ $container->get('settings.settings_helper'),
+ $container->get('settings.data_helper'),
+ $container->get(Logger::class),
+ $container->get(OrderLines::class),
+ $container->get(RequestFactory::class)
+ );
+ },
+ static function () use ($container) {
+ return new MolliePayment(
+ 'payment',
+ $container->get('shared.plugin_id'),
+ $container->get('SDK.api_helper'),
+ $container->get('settings.settings_helper'),
+ $container->get('settings.data_helper'),
+ $container->get(Logger::class),
+ $container->get(RequestFactory::class)
+ );
+ }
+ );
+ },
+ RequestFactory::class => static function (ContainerInterface $container): RequestFactory {
+ return new RequestFactory($container);
+ },
+ CustomerBirthdateMiddleware::class => static function (ContainerInterface $container): CustomerBirthdateMiddleware {
+ return new CustomerBirthdateMiddleware($container->get('gateway.paymentMethods'));
+ },
+ ApplePayTokenMiddleware::class => static function (): ApplePayTokenMiddleware {
+ return new ApplePayTokenMiddleware();
+ },
+ CardTokenMiddleware::class => static function (): CardTokenMiddleware {
+ return new CardTokenMiddleware();
+ },
+ StoreCustomerMiddleware::class => static function (ContainerInterface $container): StoreCustomerMiddleware {
+ return new StoreCustomerMiddleware($container->get('settings.settings_helper'));
+ },
+ AddSequenceTypeForSubscriptionsMiddleware::class => static function (ContainerInterface $container): AddSequenceTypeForSubscriptionsMiddleware {
+ $dataHelper = $container->get('settings.data_helper');
+ $pluginId = $container->get('shared.plugin_id');
+ return new AddSequenceTypeForSubscriptionsMiddleware($dataHelper, $pluginId);
+ },
+ OrderLinesMiddleware::class => static function (ContainerInterface $container): OrderLinesMiddleware {
+ $orderLines = $container->get(OrderLines::class);
+ $voucherDefaultCategory = $container->get('voucher.defaultCategory');
+ return new OrderLinesMiddleware($orderLines, $voucherDefaultCategory);
+ },
+ AddressMiddleware::class => static function (): AddressMiddleware {
+ return new AddressMiddleware();
+ },
+ UrlMiddleware::class => static function (ContainerInterface $container): UrlMiddleware {
+ return new UrlMiddleware(
+ $container->get('shared.plugin_id'),
+ $container->get(Logger::class),
+ );
+ },
+ SelectedIssuerMiddleware::class => static function (ContainerInterface $container): SelectedIssuerMiddleware {
+ $pluginId = $container->get('shared.plugin_id');
+ return new SelectedIssuerMiddleware($pluginId);
+ },
+ PaymentDescriptionMiddleware::class => static function (ContainerInterface $container): PaymentDescriptionMiddleware {
+ $dataHelper = $container->get('settings.data_helper');
+ return new PaymentDescriptionMiddleware($dataHelper);
+ },
+ AddCustomRequestFieldsMiddleware::class => static function (ContainerInterface $container): AddCustomRequestFieldsMiddleware {
+ $paymentMethods = $container->get('gateway.paymentMethods');
+ return new AddCustomRequestFieldsMiddleware($paymentMethods, $container);
+ },
+ 'request.strategy.order' => static function (ContainerInterface $container): RequestStrategyInterface {
+ $dataHelper = $container->get('settings.data_helper');
+ $settingsHelper = $container->get('settings.settings_helper');
+ $middlewares = [
+ $container->get(CustomerBirthdateMiddleware::class),
+ $container->get(ApplePayTokenMiddleware::class),
+ $container->get(CardTokenMiddleware::class),
+ $container->get(StoreCustomerMiddleware::class),
+ $container->get(AddSequenceTypeForSubscriptionsMiddleware::class),
+ $container->get(OrderLinesMiddleware::class),
+ $container->get(AddressMiddleware::class),
+ $container->get(UrlMiddleware::class),
+ $container->get(SelectedIssuerMiddleware::class),
+ ];
+ $middlewareHandler = new MiddlewareHandler($middlewares);
+
+ return new OrderRequestStrategy(
+ $dataHelper,
+ $settingsHelper,
+ $middlewareHandler
+ );
+ },
+ 'request.strategy.payment' => static function (ContainerInterface $container): RequestStrategyInterface {
+ $dataHelper = $container->get('settings.data_helper');
+ $settingsHelper = $container->get('settings.settings_helper');
+ $issuer = $container->get(SelectedIssuerMiddleware::class);
+ $url = $container->get(UrlMiddleware::class);
+ $sequenceType = $container->get(AddSequenceTypeForSubscriptionsMiddleware::class);
+ $cardToken = $container->get(CardTokenMiddleware::class);
+ $applePayToken = $container->get(ApplePayTokenMiddleware::class);
+ $storeCustomer = $container->get(StoreCustomerMiddleware::class);
+ $paymentDescription = $container->get(PaymentDescriptionMiddleware::class);
+ $addCustomRequestFields = $container->get(AddCustomRequestFieldsMiddleware::class);
+ $middlewares = [
+ $issuer,
+ $url,
+ $sequenceType,
+ $cardToken,
+ $applePayToken,
+ $storeCustomer,
+ $paymentDescription,
+ $addCustomRequestFields,
+ ];
+ $middlewareHandler = new MiddlewareHandler($middlewares);
+
+ return new PaymentRequestStrategy(
+ $dataHelper,
+ $settingsHelper,
+ $middlewareHandler
+ );
+ },
+ ];
+};
diff --git a/src/PaymentMethods/AbstractPaymentMethod.php b/src/PaymentMethods/AbstractPaymentMethod.php
index a83cee26f..dc5da178b 100644
--- a/src/PaymentMethods/AbstractPaymentMethod.php
+++ b/src/PaymentMethods/AbstractPaymentMethod.php
@@ -4,9 +4,7 @@
namespace Mollie\WooCommerce\PaymentMethods;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
use Mollie\WooCommerce\Gateway\Surcharge;
-use Mollie\WooCommerce\Payment\PaymentFieldsService;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
@@ -32,10 +30,7 @@ abstract class AbstractPaymentMethod implements PaymentMethodI
* @var Settings
*/
protected $settingsHelper;
- /**
- * @var PaymentFieldsService
- */
- protected $paymentFieldsService;
+
/**
* @var Surcharge
*/
@@ -48,7 +43,6 @@ abstract class AbstractPaymentMethod implements PaymentMethodI
public function __construct(
IconFactory $iconFactory,
Settings $settingsHelper,
- PaymentFieldsService $paymentFieldsService,
Surcharge $surcharge,
array $apiPaymentMethod
) {
@@ -56,7 +50,6 @@ public function __construct(
$this->id = $this->getIdFromConfig();
$this->iconFactory = $iconFactory;
$this->settingsHelper = $settingsHelper;
- $this->paymentFieldsService = $paymentFieldsService;
$this->surcharge = $surcharge;
$this->config = $this->getConfig();
$this->settings = $this->getSettings();
@@ -177,25 +170,6 @@ public function getAllFormFields()
return $this->getFormFields($this->getSharedFormFields());
}
- /**
- * Sets the gateway's payment fields strategy based on payment method
- * @param $gateway
- * @return void
- */
- public function paymentFieldsStrategy($gateway)
- {
- $this->paymentFieldsService->setStrategy($this);
- $this->paymentFieldsService->executeStrategy($gateway);
- }
-
- /**
- * @return PaymentFieldsService
- */
- public function paymentFieldsService(): PaymentFieldsService
- {
- return $this->paymentFieldsService;
- }
-
/**
* Access the payment method processed description, surcharge included
* @return mixed|string
@@ -340,4 +314,15 @@ protected function titleIsDefault(): bool
return $savedTitle === $this->config['defaultTitle'];
}
+
+ /**
+ * @return string|NULL
+ */
+ public function getSelectedIssuer(): ?string
+ {
+ $issuer_id = $this->settingsHelper->getPluginId() . '_issuer_' . $this->id;
+ //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $postedIssuer = wc_clean(wp_unslash($_POST[$issuer_id] ?? ''));
+ return !empty($postedIssuer) ? $postedIssuer : null;
+ }
}
diff --git a/src/PaymentMethods/Alma.php b/src/PaymentMethods/Alma.php
index d127a9864..9139eb17e 100644
--- a/src/PaymentMethods/Alma.php
+++ b/src/PaymentMethods/Alma.php
@@ -23,8 +23,7 @@ protected function getConfig(): array
'confirmationDelayed' => false,
'SEPA' => false,
'paymentAPIfields' => [
- 'billingAddress',
- 'shippingAddress',
+ 'AddressMiddleware',
],
'docs' => 'https://www.mollie.com/gb/payments/alma',
];
diff --git a/src/PaymentMethods/Icon/GatewayIconsRenderer.php b/src/PaymentMethods/Icon/GatewayIconsRenderer.php
new file mode 100644
index 000000000..bd5df4c5f
--- /dev/null
+++ b/src/PaymentMethods/Icon/GatewayIconsRenderer.php
@@ -0,0 +1,34 @@
+gatewayId = $gatewayId;
+ $this->container = $container;
+ }
+ /**
+ * @inheritDoc
+ */
+ public function renderIcons(): string
+ {
+ $paymentMethods = $this->container->get('gateway.paymentMethods');
+ $methodId = substr($this->gatewayId, strrpos($this->gatewayId, '_') + 1);
+ $paymentMethod = $paymentMethods[$methodId];
+ if ($paymentMethod->shouldDisplayIcon()) {
+ $defaultIcon = $paymentMethod->getIconUrl();
+ return apply_filters(
+ $this->gatewayId . '_icon_url',
+ $defaultIcon
+ );
+ }
+ return '';
+ }
+}
diff --git a/src/PaymentMethods/InstructionStrategies/OrderInstructionsManager.php b/src/PaymentMethods/InstructionStrategies/OrderInstructionsManager.php
new file mode 100644
index 000000000..e8f39fb59
--- /dev/null
+++ b/src/PaymentMethods/InstructionStrategies/OrderInstructionsManager.php
@@ -0,0 +1,107 @@
+paymentMethod()->getProperty('instructions')) {
+ $this->strategy = new DefaultInstructionStrategy();
+ } else {
+ $className = 'Mollie\\WooCommerce\\PaymentMethods\\InstructionStrategies\\' . ucfirst($deprecatedGatewayHelper->paymentMethod()->getProperty('id')) . 'InstructionStrategy';
+ $this->strategy = class_exists($className) ? new $className() : new DefaultInstructionStrategy();
+ }
+ }
+
+ public function executeStrategy(
+ $paymentGateway,
+ $payment,
+ $order = null,
+ $admin_instructions = false
+ ) {
+
+ return $this->strategy->execute($paymentGateway, $payment, $order, $admin_instructions);
+ }
+
+ /**
+ * Add content to the WC emails.
+ *
+ * @param WC_Order $order
+ * @param bool $admin_instructions (default: false)
+ * @param bool $plain_text (default: false)
+ *
+ * @return void
+ */
+ public function displayInstructions(
+ $paymentGateway,
+ $deprecatedGatewayHelper,
+ WC_Order $order,
+ $admin_instructions = false,
+ $plain_text = false
+ ) {
+
+ if (
+ ($admin_instructions && !self::$alreadyDisplayedAdminInstructions)
+ || (!$admin_instructions && !self::$alreadyDisplayedCustomerInstructions)
+ ) {
+ $order_payment_method = $order->get_payment_method();
+
+ // Invalid gateway
+ if ($paymentGateway->id !== $order_payment_method) {
+ return;
+ }
+
+ $payment = $deprecatedGatewayHelper->paymentObject()->getActiveMolliePayment(
+ $order->get_id()
+ );
+ $methodId = str_replace('mollie_wc_gateway_', '', $paymentGateway->id);
+ // Mollie payment not found or invalid gateway
+ if (
+ !$payment
+ || $payment->method !== $methodId
+ ) {
+ return;
+ }
+ $this->setStrategy($deprecatedGatewayHelper);
+ $instructions = $this->executeStrategy(
+ $paymentGateway,
+ $payment,
+ $order,
+ $admin_instructions
+ );
+
+ if (!empty($instructions)) {
+ $instructions = wptexturize($instructions);
+ //save instructions in order meta
+ $order->update_meta_data(
+ '_mollie_payment_instructions',
+ $instructions
+ );
+ $order->save();
+
+ if ($plain_text) {
+ echo esc_html($instructions) . PHP_EOL;
+ } else {
+ echo '';
+ echo wp_kses(wpautop($instructions), ['p' => [], 'strong' => [], 'br' => []]) . PHP_EOL;
+ echo '';
+ }
+ }
+ }
+ if ($admin_instructions && !self::$alreadyDisplayedAdminInstructions) {
+ self::$alreadyDisplayedAdminInstructions = true;
+ }
+ if (!$admin_instructions && !self::$alreadyDisplayedCustomerInstructions) {
+ self::$alreadyDisplayedCustomerInstructions = true;
+ }
+ }
+}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php b/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php
new file mode 100644
index 000000000..d2389b774
--- /dev/null
+++ b/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php
@@ -0,0 +1,36 @@
+deprecatedHelperGateway = $deprecatedHelperGateway;
+ $this->gatewayDescription = $gateway;
+ $this->dataHelper = $dataHelper;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function renderFields(): string
+ {
+ return '';
+ }
+}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php
index 77b2704a2..c1c30f4fa 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php
@@ -4,11 +4,13 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class BancomatpayFieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class BancomatpayFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
const FIELD_PHONE = "billing_phone_bancomatpay";
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
$showPhoneField = false;
$isPhoneRequired = get_option('mollie_wc_is_phone_required_flag');
@@ -25,8 +27,9 @@ public function execute($gateway, $dataHelper)
}
if ($showPhoneField) {
- $this->phoneNumber($phoneValue);
+ return $this->phoneNumber($phoneValue);
}
+ return "";
}
protected function getOrderIdOnPayForOrderPage()
@@ -39,18 +42,22 @@ protected function getOrderIdOnPayForOrderPage()
protected function phoneNumber($phoneValue)
{
$phoneValue = $phoneValue ?: '';
- ?>
-
-
-
-
-
-
-
+
+
+
+
+
';
}
public function getFieldMarkup($gateway, $dataHelper)
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/BillieFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/BillieFieldsStrategy.php
index 3b8ac4bf3..adda4a403 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/BillieFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/BillieFieldsStrategy.php
@@ -4,12 +4,15 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class BillieFieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class BillieFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
const FIELD_COMPANY = "billing_company";
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
+
$showCompanyField = false;
if (is_checkout_pay_page()) {
@@ -22,8 +25,9 @@ public function execute($gateway, $dataHelper)
}
if ($showCompanyField) {
- $this->company();
+ return $this->company();
}
+ return "";
}
protected function getOrderIdOnPayForOrderPage()
@@ -35,18 +39,22 @@ protected function getOrderIdOnPayForOrderPage()
protected function company()
{
- ?>
-
-
-
-
+ return '
+
+
+
+
-
- ';
}
public function getFieldMarkup($gateway, $dataHelper)
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/CreditcardFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/CreditcardFieldsStrategy.php
index df6828595..aaa586562 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/CreditcardFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/CreditcardFieldsStrategy.php
@@ -4,34 +4,31 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
-class CreditcardFieldsStrategy implements PaymentFieldsStrategyI
+class CreditcardFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
- if (!$this->isMollieComponentsEnabled($gateway->paymentMethod())) {
- return;
+ if (!$this->isMollieComponentsEnabled($this->deprecatedHelperGateway->paymentMethod())) {
+ return '';
}
- $gateway->has_fields = true;
- $allowedHtml = $this->svgAllowedHtml()
+ $allowedHtml = $this->svgAllowedHtml();
+
+ $output = '';
+ $output .= '';
+ $output .= sprintf(
+ esc_html__(
+ '%1$s Secure payments provided by %2$s',
+ 'mollie-payments-for-woocommerce'
+ ),
+ wp_kses($this->lockIcon($this->dataHelper), $allowedHtml),
+ wp_kses($this->mollieLogo($this->dataHelper), $allowedHtml)
+ );
+ $output .= '
';
- ?>
-
-
- lockIcon($dataHelper), $allowedHtml),
- wp_kses($this->mollieLogo($dataHelper), $allowedHtml)
- );
- ?>
-
- gatewayDescription;
}
public function getFieldMarkup($gateway, $dataHelper)
{
+ return "";
}
}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/GiftcardFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/GiftcardFieldsStrategy.php
index 97c0f0e48..dc42a783d 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/GiftcardFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/GiftcardFieldsStrategy.php
@@ -4,21 +4,23 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class GiftcardFieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class GiftcardFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
use IssuersDropdownBehavior;
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
- if (!$this->dropDownEnabled($gateway)) {
- return;
+ if (!$this->dropDownEnabled($this->deprecatedHelperGateway)) {
+ return $this->gatewayDescription;
}
- $issuers = $this->getIssuers($gateway, $dataHelper);
+ $issuers = $this->getIssuers($this->deprecatedHelperGateway, $this->dataHelper);
if (empty($issuers)) {
- return;
+ return $this->gatewayDescription;
}
- $selectedIssuer = $gateway->getSelectedIssuer();
+ $selectedIssuer = $this->deprecatedHelperGateway->paymentMethod()->getSelectedIssuer();
$html = '';
@@ -32,12 +34,10 @@ public function execute($gateway, $dataHelper)
$html .= '' . $issuerName;
}
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
- echo wpautop(wptexturize($html));
-
- return;
+ return wpautop(wptexturize($html));
}
- $this->renderIssuers($gateway, $issuers, $selectedIssuer);
+ return $this->renderIssuers($this->deprecatedHelperGateway, $issuers, $selectedIssuer);
}
public function getFieldMarkup($gateway, $dataHelper)
@@ -46,7 +46,7 @@ public function getFieldMarkup($gateway, $dataHelper)
return "";
}
$issuers = $this->getIssuers($gateway, $dataHelper);
- $selectedIssuer = $gateway->getSelectedIssuer();
+ $selectedIssuer = $gateway->paymentMethod()->getSelectedIssuer();
$markup = $this->dropdownOptions($gateway, $issuers, $selectedIssuer);
return $markup;
}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php
index 9d0483a5e..137411da3 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php
@@ -4,21 +4,23 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class In3FieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class In3FieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
use PaymentFieldsStrategiesTrait;
const FIELD_BIRTHDATE = "billing_birthdate_in3";
const FIELD_PHONE = "billing_phone_in3";
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
$showBirthdateField = false;
$showPhoneField = false;
$isPhoneRequired = get_option('mollie_wc_is_phone_required_flag');
$phoneValue = false;
$birthValue = false;
-
+ $html = '';
if (is_checkout_pay_page()) {
$showBirthdateField = true;
$showPhoneField = true;
@@ -35,28 +37,29 @@ public function execute($gateway, $dataHelper)
}
if ($showPhoneField) {
- $this->phoneNumber($phoneValue);
+ $html .= $this->phoneNumber($phoneValue);
}
if ($showBirthdateField) {
- $this->dateOfBirth($birthValue);
+ $html .= $this->dateOfBirth($birthValue);
}
+ return $html;
}
protected function phoneNumber($phoneValue)
{
$phoneValue = $phoneValue ?: '';
- ?>
-
-
-
-
-
-
- ';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+ $html .= '
';
+ return $html;
}
public function getFieldMarkup($gateway, $dataHelper)
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php b/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
index 3ccbd4564..e50ed0db5 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
@@ -35,7 +35,7 @@ public function renderIssuers($gateway, $issuers, $selectedIssuer)
$issuers,
$selectedIssuer
);
- echo wp_kses($html, [
+ return wp_kses($html, [
'select' => [
'name' => [],
'id' => [],
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/KbcFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/KbcFieldsStrategy.php
index 2b0a1d083..479b157ac 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/KbcFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/KbcFieldsStrategy.php
@@ -4,21 +4,23 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class KbcFieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class KbcFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
use IssuersDropdownBehavior;
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
- if (!$this->dropDownEnabled($gateway)) {
- return;
+ if (!$this->dropDownEnabled($this->deprecatedHelperGateway)) {
+ return '';
}
- $issuers = $this->getIssuers($gateway, $dataHelper);
+ $issuers = $this->getIssuers($this->deprecatedHelperGateway, $this->dataHelper);
- $selectedIssuer = $gateway->getSelectedIssuer();
+ $selectedIssuer = $this->deprecatedHelperGateway->paymentMethod()->getSelectedIssuer();
- $this->renderIssuers($gateway, $issuers, $selectedIssuer);
+ return $this->renderIssuers($this->deprecatedHelperGateway, $issuers, $selectedIssuer);
}
public function getFieldMarkup($gateway, $dataHelper)
@@ -27,7 +29,7 @@ public function getFieldMarkup($gateway, $dataHelper)
return "";
}
$issuers = $this->getIssuers($gateway, $dataHelper);
- $selectedIssuer = $gateway->getSelectedIssuer();
+ $selectedIssuer = $gateway->paymentMethod()->getSelectedIssuer();
$markup = $this->dropdownOptions($gateway, $issuers, $selectedIssuer);
return $markup;
}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/NoopPaymentFieldsRenderer.php b/src/PaymentMethods/PaymentFieldsStrategies/NoopPaymentFieldsRenderer.php
new file mode 100644
index 000000000..0e08599a6
--- /dev/null
+++ b/src/PaymentMethods/PaymentFieldsStrategies/NoopPaymentFieldsRenderer.php
@@ -0,0 +1,16 @@
+
-
-
-
-
-
- ';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+ return $html;
}
}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/PaymentFieldsStrategyI.php b/src/PaymentMethods/PaymentFieldsStrategies/PaymentFieldsStrategyI.php
index c0b54bd71..81e60c264 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/PaymentFieldsStrategyI.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/PaymentFieldsStrategyI.php
@@ -6,5 +6,5 @@
interface PaymentFieldsStrategyI
{
- public function execute($gateway, $dataHelper);
+ public function execute($deprecatedHelperDeprecatedHelperGateway, $gatewayDescription, $dataHelper): string;
}
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/RivertyFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/RivertyFieldsStrategy.php
index b98f536a7..ddfb46583 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/RivertyFieldsStrategy.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/RivertyFieldsStrategy.php
@@ -4,21 +4,23 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentFieldsStrategies;
-class RivertyFieldsStrategy implements PaymentFieldsStrategyI
+use Inpsyde\PaymentGateway\PaymentFieldsRendererInterface;
+
+class RivertyFieldsStrategy extends AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
{
use PaymentFieldsStrategiesTrait;
const FIELD_BIRTHDATE = "billing_birthdate_riverty";
const FIELD_PHONE = "billing_phone_riverty";
- public function execute($gateway, $dataHelper)
+ public function renderFields(): string
{
$showBirthdateField = false;
$showPhoneField = false;
$isPhoneRequired = get_option('mollie_wc_is_phone_required_flag');
$phoneValue = false;
$birthValue = false;
-
+ $html = '';
if (is_checkout_pay_page()) {
$showBirthdateField = true;
$showPhoneField = true;
@@ -35,12 +37,14 @@ public function execute($gateway, $dataHelper)
}
if ($showPhoneField) {
- $this->phoneNumber($phoneValue);
+ $html .= $this->phoneNumber($phoneValue);
}
if ($showBirthdateField) {
- $this->dateOfBirth($birthValue);
+ $html .= $this->dateOfBirth($birthValue);
}
+
+ return $html;
}
protected function phoneNumber($phoneValue)
@@ -48,23 +52,20 @@ protected function phoneNumber($phoneValue)
$phoneValue = $phoneValue ?: '';
$country = WC()->customer->get_billing_country();
$countryCodes = [
- 'BE' => '+32xxxxxxxxx',
- 'NL' => '+316xxxxxxxx',
- 'DE' => '+49xxxxxxxxx',
- 'AT' => '+43xxxxxxxxx',
+ 'BE' => '+32xxxxxxxxx',
+ 'NL' => '+316xxxxxxxx',
+ 'DE' => '+49xxxxxxxxx',
+ 'AT' => '+43xxxxxxxxx',
];
$placeholder = in_array($country, array_keys($countryCodes)) ? $countryCodes[$country] : $countryCodes['NL'];
- ?>
-
-
-
-
-
-
- ';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+ $html .= '';
+
+ return $html;
}
public function getFieldMarkup($gateway, $dataHelper)
diff --git a/src/PaymentMethods/PaymentMethodI.php b/src/PaymentMethods/PaymentMethodI.php
index cd40adbf4..3f6a0d9e9 100644
--- a/src/PaymentMethods/PaymentMethodI.php
+++ b/src/PaymentMethods/PaymentMethodI.php
@@ -4,8 +4,6 @@
namespace Mollie\WooCommerce\PaymentMethods;
-use Mollie\WooCommerce\Payment\PaymentFieldsService;
-
interface PaymentMethodI
{
public function getProperty(string $propertyName);
@@ -13,6 +11,5 @@ public function hasProperty(string $propertyName): bool;
public function title(): string;
public function hasPaymentFields(): bool;
public function getProcessedDescriptionForBlock(): string;
- public function paymentFieldsService(): PaymentFieldsService;
public function hasSurcharge(): bool;
}
diff --git a/src/Settings/General/MollieGeneralSettings.php b/src/Settings/General/MollieGeneralSettings.php
index e6ef54571..49c359717 100644
--- a/src/Settings/General/MollieGeneralSettings.php
+++ b/src/Settings/General/MollieGeneralSettings.php
@@ -2,7 +2,7 @@
namespace Mollie\WooCommerce\Settings\General;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Gateway\Surcharge;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
diff --git a/src/Settings/General/MultiCountrySettingsField.php b/src/Settings/General/MultiCountrySettingsField.php
new file mode 100644
index 000000000..fcc723f57
--- /dev/null
+++ b/src/Settings/General/MultiCountrySettingsField.php
@@ -0,0 +1,58 @@
+paymentMethod = $paymentMethod;
+ }
+
+ public function render(string $fieldId, array $fieldConfig, PaymentGateway $gateway): string
+ {
+ return $this->multiSelectCountry($this->paymentMethod);
+ }
+
+ public function multiSelectCountry($paymentMethod)
+ {
+ $selections = (array)$paymentMethod->getProperty('allowed_countries', []);
+ $gatewayId = $paymentMethod->getProperty('id');
+ $id = 'mollie_wc_gateway_' . $gatewayId . '_allowed_countries';
+ $title = __('Sell to specific countries', 'mollie-payments-for-woocommerce');
+ $countries = WC()->countries->countries;
+ asort($countries);
+ ob_start();
+ ?>
+
+
+
+ |
+
+
+
+ |
+
+ 'select',
'options' => [
- PaymentService::PAYMENT_METHOD_TYPE_ORDER => ucfirst(
- PaymentService::PAYMENT_METHOD_TYPE_ORDER
+ PaymentProcessor::PAYMENT_METHOD_TYPE_ORDER => ucfirst(
+ PaymentProcessor::PAYMENT_METHOD_TYPE_ORDER
) . ' (' . __('default', 'mollie-payments-for-woocommerce')
. ')',
- PaymentService::PAYMENT_METHOD_TYPE_PAYMENT => ucfirst(
- PaymentService::PAYMENT_METHOD_TYPE_PAYMENT
+ PaymentProcessor::PAYMENT_METHOD_TYPE_PAYMENT => ucfirst(
+ PaymentProcessor::PAYMENT_METHOD_TYPE_PAYMENT
),
],
- 'default' => PaymentService::PAYMENT_METHOD_TYPE_ORDER,
+ 'default' => PaymentProcessor::PAYMENT_METHOD_TYPE_ORDER,
'desc' => sprintf(
/* translators: Placeholder 1: opening link tag, placeholder 2: closing link tag */
__(
diff --git a/src/Settings/Settings.php b/src/Settings/Settings.php
index 2d03aa453..306ec85a6 100644
--- a/src/Settings/Settings.php
+++ b/src/Settings/Settings.php
@@ -9,7 +9,7 @@
use Mollie\Api\Exceptions\ApiException;
use Mollie\WooCommerce\Gateway\Surcharge;
use Mollie\WooCommerce\Notice\AdminNotice;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\Settings\General\MollieGeneralSettings;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
use WC_Payment_Gateway;
@@ -230,7 +230,7 @@ public function isTestModeEnabled()
public function isOrderApiSetting()
{
$orderApiSetting = get_option($this->getSettingId('api_switch'));
- return !$orderApiSetting || is_string($orderApiSetting) && trim($orderApiSetting) === PaymentService::PAYMENT_METHOD_TYPE_ORDER;
+ return !$orderApiSetting || is_string($orderApiSetting) && trim($orderApiSetting) === PaymentProcessor::PAYMENT_METHOD_TYPE_ORDER;
}
/**
* @param bool $overrideTestMode
diff --git a/src/Settings/SettingsModule.php b/src/Settings/SettingsModule.php
index 61ecb6632..b554b34b8 100644
--- a/src/Settings/SettingsModule.php
+++ b/src/Settings/SettingsModule.php
@@ -146,7 +146,7 @@ function () use ($optionName, $defaultAdvancedOptions, $defaultComponentsOptions
$this->maybeTestModeNotice();
});
- $gateways = $container->get('gateway.instances');
+ $gateways = $container->get('__deprecated.gateway_helpers');
$isSDDGatewayEnabled = $container->get('gateway.isSDDGatewayEnabled');
$this->initMollieSettingsPage($isSDDGatewayEnabled, $gateways, $pluginPath, $pluginUrl, $paymentMethods);
add_action(
diff --git a/src/Subscription/MaybeFixSubscription.php b/src/Subscription/MaybeFixSubscription.php
deleted file mode 100644
index 9d5ae1ca8..000000000
--- a/src/Subscription/MaybeFixSubscription.php
+++ /dev/null
@@ -1,51 +0,0 @@
- '-1',
- 'meta_query' => [
- [
- 'key' => '_mollie_customer_id',
- 'value' => '',
- 'compare' => 'NOT EXISTS',
- ],
- ],
- ]
- );
- foreach ($subscriptions as $subscription) {
- $customer = $subscription->get_meta('_mollie_customer_id');
- //cst_*
- if (strlen($customer) < 5) {
- $parent = $subscription->get_parent();
- if ($parent) {
- $subscription->update_meta_data('_mollie_customer_id', $parent->get_meta('_mollie_customer_id'));
- $subscription->update_meta_data('_mollie_order_id', $parent->get_meta('_mollie_order_id'));
- $subscription->update_meta_data('_mollie_payment_id', $parent->get_meta('_mollie_payment_id'));
- $subscription->update_meta_data('_mollie_payment_mode', $parent->get_meta('_mollie_payment_mode'));
- $subscription->save();
- }
- }
- }
- update_option('mollie_wc_fix_subscriptions2', true);
- }
-}
diff --git a/src/Subscription/MollieSepaRecurringGateway.php b/src/Subscription/MollieSepaRecurringGatewayHandler.php
similarity index 83%
rename from src/Subscription/MollieSepaRecurringGateway.php
rename to src/Subscription/MollieSepaRecurringGatewayHandler.php
index 86f856446..497560e72 100644
--- a/src/Subscription/MollieSepaRecurringGateway.php
+++ b/src/Subscription/MollieSepaRecurringGatewayHandler.php
@@ -7,24 +7,23 @@
use DateInterval;
use DateTime;
use Mollie\Api\Exceptions\ApiException;
+use Mollie\Api\Resources\Payment;
use Mollie\Api\Types\SequenceType;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\MollieOrderService;
-use Mollie\WooCommerce\Payment\OrderInstructionsService;
-use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
+use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
-class MollieSepaRecurringGateway extends MollieSubscriptionGateway
+class MollieSepaRecurringGatewayHandler extends MollieSubscriptionGatewayHandler
{
const WAITING_CONFIRMATION_PERIOD_DAYS = '21';
@@ -37,8 +36,7 @@ class MollieSepaRecurringGateway extends MollieSubscriptionGateway
public function __construct(
PaymentMethodI $directDebitPaymentMethod,
PaymentMethodI $paymentMethod,
- PaymentService $paymentService,
- OrderInstructionsService $orderInstructionsService,
+ OrderInstructionsManager $orderInstructionsService,
MollieOrderService $mollieOrderService,
Data $dataService,
Logger $logger,
@@ -53,7 +51,6 @@ public function __construct(
parent::__construct(
$paymentMethod,
- $paymentService,
$orderInstructionsService,
$mollieOrderService,
$dataService,
@@ -66,22 +63,9 @@ public function __construct(
$pluginId,
$apiHelper
);
- $directDebit = new MolliePaymentGateway(
- $directDebitPaymentMethod,
- $paymentService,
- $orderInstructionsService,
- $mollieOrderService,
- $dataService,
- $logger,
- $notice,
- $httpResponse,
- $mollieObject,
- $paymentFactory,
- $pluginId
- );
- if ($directDebit->enabled === 'yes') {
- $this->initSubscriptionSupport();
- $this->recurringMollieMethod = $directDebit;
+ $directDebitSettings = get_option('mollie_wc_gateway_directdebit_settings');
+ if ($directDebitSettings['enabled'] === 'yes') {
+ $this->recurringMollieMethod = $directDebitPaymentMethod;
}
return $this;
}
@@ -93,7 +77,7 @@ protected function getRecurringMollieMethodId()
{
$result = null;
if ($this->recurringMollieMethod) {
- $result = $this->recurringMollieMethod->paymentMethod()->getProperty('id');
+ $result = $this->recurringMollieMethod->getProperty('id');
}
return $result;
@@ -106,7 +90,7 @@ protected function getRecurringMollieMethodTitle()
{
$result = null;
if ($this->recurringMollieMethod) {
- $result = $this->recurringMollieMethod->paymentMethod()->getProperty('title');
+ $result = $this->recurringMollieMethod->getProperty('title');
}
return $result;
@@ -168,7 +152,7 @@ protected function addPendingPaymentOrder($renewal_order)
}
/**
- * @param null $payment
+ * @param Payment $payment
* @return string
*/
protected function getPaymentMethodTitle($payment)
diff --git a/src/Subscription/MollieSubscriptionGateway.php b/src/Subscription/MollieSubscriptionGatewayHandler.php
similarity index 83%
rename from src/Subscription/MollieSubscriptionGateway.php
rename to src/Subscription/MollieSubscriptionGatewayHandler.php
index ec3d17fa9..a13ddd710 100644
--- a/src/Subscription/MollieSubscriptionGateway.php
+++ b/src/Subscription/MollieSubscriptionGatewayHandler.php
@@ -6,15 +6,16 @@
use Exception;
use Mollie\Api\Exceptions\ApiException;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\MollieSubscription;
-use Mollie\WooCommerce\Payment\OrderInstructionsService;
-use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Payment\MollieOrderService;
+use Mollie\WooCommerce\Payment\Request\Middleware\MiddlewareHandler;
+use Mollie\WooCommerce\Payment\Request\Middleware\UrlMiddleware;
+use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\SDK\HttpResponse;
@@ -22,11 +23,10 @@
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
use Mollie\WooCommerce\PaymentMethods\Constants;
use WC_Order;
-class MollieSubscriptionGateway extends MolliePaymentGateway
+class MollieSubscriptionGatewayHandler extends MolliePaymentGatewayHandler
{
protected const PAYMENT_TEST_MODE = 'test';
protected const METHODS_NEEDING_UPDATE = ['mollie_wc_gateway_bancontact',
@@ -39,7 +39,6 @@ class MollieSubscriptionGateway extends MolliePaymentGateway
'mollie_wc_gateway_sofort', ];
protected const DIRECTDEBIT = Constants::DIRECTDEBIT;
- protected $isSubscriptionPayment = false;
protected $apiHelper;
protected $settingsHelper;
/**
@@ -52,8 +51,7 @@ class MollieSubscriptionGateway extends MolliePaymentGateway
*/
public function __construct(
PaymentMethodI $paymentMethod,
- PaymentService $paymentService,
- OrderInstructionsService $orderInstructionsService,
+ OrderInstructionsManager $orderInstructionsProcessor,
MollieOrderService $mollieOrderService,
Data $dataService,
Logger $logger,
@@ -68,8 +66,7 @@ public function __construct(
parent::__construct(
$paymentMethod,
- $paymentService,
- $orderInstructionsService,
+ $orderInstructionsProcessor,
$mollieOrderService,
$dataService,
$logger,
@@ -81,65 +78,61 @@ public function __construct(
);
$this->apiHelper = $apiHelper;
+ $middlewares = [
+ new UrlMiddleware($pluginId, $logger),
+ ];
+ $middlewareHandler = new MiddlewareHandler($middlewares);
$this->subscriptionObject = new MollieSubscription(
$pluginId,
$apiHelper,
$settingsHelper,
$dataService,
- $logger
+ $logger,
+ $paymentMethod,
+ $middlewareHandler
);
+ }
+
+ public function addSubscriptionFilters($gateway)
+ {
if (class_exists('WC_Subscriptions_Order')) {
- add_action('woocommerce_scheduled_subscription_payment_' . $this->id, [ $this, 'scheduled_subscription_payment' ], 10, 2);
+ add_action(
+ 'woocommerce_scheduled_subscription_payment_' . $gateway->id,
+ function ($renewal_total, WC_Order $renewal_order) use ($gateway) {
+ $this->scheduled_subscription_payment($renewal_total, $renewal_order, $gateway);
+ },
+ 10,
+ 3
+ );
// A resubscribe order to record a customer resubscribing to an expired or cancelled subscription.
add_action('wcs_resubscribe_order_created', [ $this, 'delete_resubscribe_meta' ], 10);
// After creating a renewal order to record a scheduled subscription payment with the same post meta, order items etc.
- add_action('wcs_renewal_order_created', [ $this, 'delete_renewal_meta' ], 10);
+ add_action('wcs_renewal_order_created', [ $this, 'delete_renewal_meta' ], 10);
add_action('woocommerce_subscription_failing_payment_method_updated_mollie', [ $this, 'update_failing_payment_method' ], 10, 2);
- add_filter('woocommerce_subscription_payment_meta', [ $this, 'add_subscription_payment_meta' ], 10, 2);
- add_action('woocommerce_subscription_validate_payment_meta', [ $this, 'validate_subscription_payment_meta' ], 10, 2);
- }
- if ($this->paymentMethod->getProperty('Subscription')) {
- $this->initSubscriptionSupport();
+ add_filter(
+ 'woocommerce_subscription_payment_meta',
+ function ($payment_meta, $subscription) use ($gateway) {
+ return $this->add_subscription_payment_meta($payment_meta, $subscription, $gateway);
+ },
+ 10,
+ 3
+ );
+ add_action(
+ 'woocommerce_subscription_validate_payment_meta',
+ function ($payment_method_id, $payment_meta) use ($gateway) {
+ $this->validate_subscription_payment_meta($payment_method_id, $payment_meta, $gateway);
+ },
+ 10,
+ 2
+ );
}
}
- /**
- *
- */
- protected function initSubscriptionSupport()
- {
- $supportSubscriptions = [
- 'subscriptions',
- 'subscription_cancellation',
- 'subscription_suspension',
- 'subscription_reactivation',
- 'subscription_amount_changes',
- 'subscription_date_changes',
- 'multiple_subscriptions',
- 'subscription_payment_method_change',
- 'subscription_payment_method_change_admin',
- 'subscription_payment_method_change_customer',
- ];
-
- $this->supports = array_merge($this->supports, $supportSubscriptions);
- }
-
- /**
- * @param $order_id
- * @return array
- * @throws InvalidApiKey
- */
- public function process_subscription_payment($order_id)
- {
- $this->isSubscriptionPayment = true;
- return parent::process_payment($order_id);
- }
-
/**
* @param $renewal_order
*
@@ -206,7 +199,7 @@ public function update_subscription_status_for_direct_debit($renewal_order)
* @return array
* @throws InvalidApiKey
*/
- public function scheduled_subscription_payment($renewal_total, WC_Order $renewal_order)
+ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal_order, $gateway)
{
if (! $renewal_order) {
$this->logger->debug($this->id . ': Could not load renewal order or process renewal payment.');
@@ -219,15 +212,15 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
// Allow developers to hook into the subscription renewal payment before it processed
do_action($this->pluginId . '_before_renewal_payment_created', $renewal_order);
- $this->logger->debug($this->id . ': Try to create renewal payment for renewal order ' . $renewal_order_id);
- $this->paymentService->setGateway($this);
+ $this->logger->debug($gateway->id . ': Try to create renewal payment for renewal order ' . $renewal_order_id);
+ //$this->paymentProcessor->setGatewayHelper($gateway->id);
$initial_order_status = $this->paymentMethod->getInitialOrderStatus();
// Overwrite plugin-wide
$initial_order_status = apply_filters($this->pluginId . '_initial_order_status', $initial_order_status);
// Overwrite gateway-wide
- $initial_order_status = apply_filters($this->pluginId . '_initial_order_status_' . $this->id, $initial_order_status);
+ $initial_order_status = apply_filters($this->pluginId . '_initial_order_status_' . $gateway->id, $initial_order_status);
// Get Mollie customer ID
$customer_id = $this->getOrderMollieCustomerId($renewal_order);
@@ -247,7 +240,7 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
$data = $this->subscriptionObject->getRecurringPaymentRequestData($renewal_order, $customer_id, $initialPaymentUsedOrderAPI);
// Allow filtering the renewal payment data
- $data = apply_filters('woocommerce_' . $this->id . '_args', $data, $renewal_order);
+ $data = apply_filters('woocommerce_' . $gateway->id . '_args', $data, $renewal_order);
// Create a renewal payment
try {
@@ -268,7 +261,8 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
$mandateId,
$isRenewalMethodDirectDebit,
$data,
- $validMandate
+ $validMandate,
+ $gateway
);
}
if (!$validMandate) {
@@ -278,7 +272,8 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
$mollieApiClient,
$validMandate,
$data,
- $renewalOrderMethod
+ $renewalOrderMethod,
+ $gateway
);
}
} catch (ApiException $e) {
@@ -312,7 +307,7 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
&& $payment->mandateId !== $mandateId
&& !empty($subscriptionParentOrder)
) {
- $this->logger->debug("{$this->id}: updating to mandate {$payment->mandateId}");
+ $this->logger->debug("{$gateway->id}: updating to mandate {$payment->mandateId}");
$subscriptionParentOrder->update_meta_data(
'_mollie_mandate_id',
$payment->mandateId
@@ -340,7 +335,7 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
$this->updateFirstPaymentMethodToRecurringPaymentMethod($renewal_order, $renewal_order_id, $payment);
// Log successful creation of payment
- $this->logger->debug($this->id . ': Renewal payment ' . $payment->id . ' (' . $payment->mode . ') created for order ' . $renewal_order_id . ' payment json response: ' . wp_json_encode($payment));
+ $this->logger->debug($gateway->id . ': Renewal payment ' . $payment->id . ' (' . $payment->mode . ') created for order ' . $renewal_order_id . ' payment json response: ' . wp_json_encode($payment));
// Unset & set active Mollie payment
// Get correct Mollie Payment Object
@@ -367,9 +362,9 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
'result' => 'success',
];
} catch (ApiException $e) {
- $this->logger->debug("{$this->id} : Failed to create payment for order {$renewal_order_id}, with customer {$customer_id} and mandate {$mandateId}. New status failed. API error: {$e->getMessage()}");
+ $this->logger->debug("{$gateway->id} : Failed to create payment for order {$renewal_order_id}, with customer {$customer_id} and mandate {$mandateId}. New status failed. API error: {$e->getMessage()}");
/* translators: Placeholder 1: Payment method title */
- $message = sprintf(__('Could not create %s renewal payment.', 'mollie-payments-for-woocommerce'), $this->title);
+ $message = sprintf(__('Could not create %s renewal payment.', 'mollie-payments-for-woocommerce'), $gateway->title);
$message .= ' ' . $e->getMessage();
$renewal_order->update_status('failed', $message);
}
@@ -504,13 +499,22 @@ public function delete_renewal_meta($renewal_order)
* @return mixed
* @throws \Mollie\Api\Exceptions\ApiException
*/
- public function add_subscription_payment_meta($payment_meta, $subscription)
+ public function add_subscription_payment_meta($payment_meta, $subscription, $gateway)
{
+ if ($gateway->id !== $subscription->get_payment_method()) {
+ return $payment_meta;
+ }
+ $parent = $subscription->get_parent();
+ $subscription->update_meta_data('_mollie_customer_id', $parent->get_meta('_mollie_customer_id'));
+ $subscription->update_meta_data('_mollie_order_id', $parent->get_meta('_mollie_order_id'));
+ $subscription->update_meta_data('_mollie_payment_id', $parent->get_meta('_mollie_payment_id'));
+ $subscription->update_meta_data('_mollie_payment_mode', $parent->get_meta('_mollie_payment_mode'));
+ $subscription->save();
$mollie_payment_id = $subscription->get_meta('_mollie_payment_id', true);
$mollie_payment_mode = $subscription->get_meta('_mollie_payment_mode', true);
$mollie_customer_id = $subscription->get_meta('_mollie_customer_id', true);
- $payment_meta[ $this->id ] = [
+ $payment_meta[ $gateway->id ] = [
'post_meta' => [
'_mollie_payment_id' => [
'value' => $mollie_payment_id,
@@ -535,9 +539,9 @@ public function add_subscription_payment_meta($payment_meta, $subscription)
* @param $payment_meta
* @throws Exception
*/
- public function validate_subscription_payment_meta($payment_method_id, $payment_meta)
+ public function validate_subscription_payment_meta($payment_method_id, $payment_meta, $gateway)
{
- if ($this->id === $payment_method_id) {
+ if ($gateway->id === $payment_method_id) {
// Check that a Mollie Customer ID is entered
if (! isset($payment_meta['post_meta']['_mollie_customer_id']['value']) || empty($payment_meta['post_meta']['_mollie_customer_id']['value'])) {
throw new Exception('A "_mollie_customer_id" value is required.');
@@ -557,54 +561,6 @@ public function update_failing_payment_method($subscription, $renewal_order)
$subscription->save();
}
- /**
- * @param int $order_id
- *
- * @return array
- * @throws \Mollie\Api\Exceptions\ApiException
- * @throws InvalidApiKey
- */
- public function process_payment($order_id)
- {
- $this->addWcSubscriptionsFiltersForPayment();
- $isSubscription = $this->dataService->isSubscription($order_id);
- if ($isSubscription) {
- $this->paymentService->setGateway($this);
- $result = $this->process_subscription_payment($order_id);
- return $result;
- }
-
- return parent::process_payment($order_id);
- }
-
- protected function addWcSubscriptionsFiltersForPayment(): void
- {
- add_filter(
- $this->pluginId . '_is_subscription_payment',
- function ($isSubscription, $orderId) {
- if ($this->dataService->isWcSubscription($orderId)) {
- add_filter(
- $this->pluginId . '_is_automatic_payment_disabled',
- static function ($filteredOption) {
- if (
- 'yes' == get_option(
- \WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments'
- )
- ) {
- return true;
- }
- return $filteredOption;
- }
- );
- return true;
- }
- return $isSubscription;
- },
- 10,
- 2
- );
- }
-
/**
* @param $mollie_customer_id
* @param $mollie_payment_id
@@ -648,13 +604,13 @@ public function restore_mollie_customer_id_and_mandate($mollie_customer_id, $mol
// Get the WooCommerce payment gateway for this subscription
$gateway = wc_get_payment_gateway_by_order($subscription);
- if (! $gateway || ! ( $gateway instanceof MolliePaymentGateway )) {
+ if (! $gateway || ! mollieWooCommerceIsMollieGateway($gateway)) {
$this->logger->debug(__METHOD__ . ' - Subscription ' . $subscription_id . ' renewal payment: stopped processing, not a Mollie payment gateway, could not restore customer ID.');
return $mollie_customer_id;
}
-
- $mollie_method = $gateway->paymentMethod->getProperty('id');
+ $gatewayId = $gateway->id;
+ $mollie_method = substr($gatewayId, strrpos($gatewayId, '_') + 1);
// Check that first payment method is related to SEPA Direct Debit and update
$methods_needing_update = [
@@ -721,22 +677,23 @@ public function restore_mollie_customer_id_and_mandate($mollie_customer_id, $mol
}
/**
+ * TODO this is still used in the service callback
* Check if the gateway is available in checkout
*
* @return bool
*/
- public function is_available(): bool
+ public function is_available($gateway): bool
{
- if (!$this->checkEnabledNorDirectDebit()) {
+ if (!$this->checkEnabledNorDirectDebit($gateway)) {
return false;
}
if (!$this->cartAmountAvailable()) {
return true;
}
- $status = parent::is_available();
+ $status = parent::is_available($gateway);
// Do extra checks if WooCommerce Subscriptions is installed
- $orderTotal = $this->get_order_total();
- return $this->subscriptionObject->isAvailableForSubscriptions($status, $this, $orderTotal);
+ $orderTotal = WC()->cart && WC()->cart->get_total('edit');
+ return $this->subscriptionObject->isAvailableForSubscriptions($status, $this, $orderTotal, $gateway);
}
/**
@@ -750,7 +707,7 @@ protected function initialPaymentUsedOrderAPI($subscriptionParentOrder): bool
}
$orderIdMeta = $subscriptionParentOrder->get_meta('_mollie_order_id');
- $parentOrderMeta = $orderIdMeta ?: PaymentService::PAYMENT_METHOD_TYPE_PAYMENT;
+ $parentOrderMeta = $orderIdMeta ?: PaymentProcessor::PAYMENT_METHOD_TYPE_PAYMENT;
return strpos($parentOrderMeta, 'ord_') !== false;
}
@@ -773,11 +730,12 @@ protected function usePreviousMandate(
$mandateId,
bool $isRenewalMethodDirectDebit,
$data,
- bool $validMandate
+ bool $validMandate,
+ $gateway
): array {
$this->logger->debug(
- $this->id . ': Found mandate ID for renewal order ' . $renewal_order_id . ' with customer ID ' . $customer_id
+ $gateway->id . ': Found mandate ID for renewal order ' . $renewal_order_id . ' with customer ID ' . $customer_id
);
$mandate = $mollieApiClient->customers->get($customer_id)->getMandate($mandateId);
@@ -805,11 +763,12 @@ protected function useAnyValidMandate(
\Mollie\Api\MollieApiClient $mollieApiClient,
bool $validMandate,
$data,
- $renewalOrderMethod
+ $renewalOrderMethod,
+ $gateway
): array {
// Get all mandates for the customer ID
$this->logger->debug(
- $this->id . ': Try to get all mandates for renewal order ' . $renewal_order_id . ' with customer ID ' . $customer_id
+ $gateway->id . ': Try to get all mandates for renewal order ' . $renewal_order_id . ' with customer ID ' . $customer_id
);
$mandates = $mollieApiClient->customers->get($customer_id)->mandates();
foreach ($mandates as $mandate) {
diff --git a/src/Subscription/SubscriptionModule.php b/src/Subscription/SubscriptionModule.php
index a6ca51ffb..4398765cf 100644
--- a/src/Subscription/SubscriptionModule.php
+++ b/src/Subscription/SubscriptionModule.php
@@ -9,7 +9,7 @@
use DateTime;
use Inpsyde\Modularity\Module\ExecutableModule;
use Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
@@ -42,20 +42,10 @@ public function run(ContainerInterface $container): bool
assert($this->dataHelper instanceof Data);
$this->settingsHelper = $container->get('settings.settings_helper');
assert($this->settingsHelper instanceof Settings);
- $this->maybeFixSubscriptions();
$this->schedulePendingPaymentOrdersExpirationCheck();
return true;
}
- /**
- * See MOL-322, MOL-405
- */
- public function maybeFixSubscriptions()
- {
- $fixer = new MaybeFixSubscription();
- $fixer->maybeFix();
- }
-
/**
* WCSubscription related.
*/
diff --git a/tests/php/Stubs/enqueue_scripts.php b/tests/overrides/enqueue_scripts.php
similarity index 100%
rename from tests/php/Stubs/enqueue_scripts.php
rename to tests/overrides/enqueue_scripts.php
diff --git a/tests/php/Stubs/woocommerce.php b/tests/overrides/woocommerce.php
similarity index 100%
rename from tests/php/Stubs/woocommerce.php
rename to tests/overrides/woocommerce.php
diff --git a/tests/php/Functional/ApplePayButton/AjaxRequestsTest.php b/tests/php/Functional/ApplePayButton/AjaxRequestsTest.php
index fff43d732..40ace5d45 100644
--- a/tests/php/Functional/ApplePayButton/AjaxRequestsTest.php
+++ b/tests/php/Functional/ApplePayButton/AjaxRequestsTest.php
@@ -8,10 +8,8 @@
use Mollie\WooCommerce\Buttons\ApplePayButton\AppleAjaxRequests;
use Mollie\WooCommerce\Buttons\ApplePayButton\ApplePayDataObjectHttp;
use Mollie\WooCommerce\Buttons\ApplePayButton\ResponsesToApple;
-use Mollie\WooCommerce\Gateway\Surcharge;
-use Mollie\WooCommerce\Payment\RefundLineItemsBuilder;
+use Mollie\WooCommerce\Gateway\Refund\RefundLineItemsBuilder;
use Mollie\WooCommerce\Shared\Data;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\Stubs\postDTOTestsStubs;
use Mollie\WooCommerceTests\Stubs\WooCommerceMocks;
diff --git a/tests/php/Functional/ApplePayButton/DataToAppleButtonScriptsTest.php b/tests/php/Functional/ApplePayButton/ApplePayDirectHandlerTest.php
similarity index 100%
rename from tests/php/Functional/ApplePayButton/DataToAppleButtonScriptsTest.php
rename to tests/php/Functional/ApplePayButton/ApplePayDirectHandlerTest.php
diff --git a/tests/php/Functional/ApplePayButton/ResponsesToAppleTest.php b/tests/php/Functional/ApplePayButton/ResponsesToAppleTest.php
index 59908b6b0..29498e3a5 100644
--- a/tests/php/Functional/ApplePayButton/ResponsesToAppleTest.php
+++ b/tests/php/Functional/ApplePayButton/ResponsesToAppleTest.php
@@ -6,7 +6,7 @@
use Faker\Generator;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use Mollie\WooCommerce\Buttons\ApplePayButton\ResponsesToApple;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
+use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\TestCase;
diff --git a/tests/php/Functional/Gateway/MollieGatewayTest.php b/tests/php/Functional/Gateway/MollieGatewayTest.php
deleted file mode 100644
index 37faf16d2..000000000
--- a/tests/php/Functional/Gateway/MollieGatewayTest.php
+++ /dev/null
@@ -1,161 +0,0 @@
-helperMocks = new HelperMocks();
- $this->wooCommerceMocks = new WooCommerceMocks();
- }
-
- /**
- * WHEN gateway setting 'enabled' !== 'yes'
- * THEN is_available returns false
- * @test
- */
- public function gatewayNOTEnabledIsNOTAvailable()
- {
- $testee = $this->buildTestee(['enabled'=>'no']);
-
- $expectedResult = false;
- $result = $testee->is_available();
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * WHEN gateway setting 'enabled' !== 'yes'
- * THEN is_available returns true
- * @test
- */
- public function gatewayEnabledIsAvailable()
- {
- $testee = $this->buildTestee(['enabled'=>'yes']);
- $total = 10.00;
- $WC = $this->wooCommerceMocks->wooCommerce(10.00, 0, $total, 0);
- expect('WC')->andReturn($WC);
- $testee->expects($this->atLeast(2))->method('get_order_total')->willReturn($total);
- expect('get_woocommerce_currency')->andReturn('EUR');
- expect('get_transient')->andReturn([['id'=>'ideal']]);
- expect('wc_get_base_location')->andReturn(['country'=>'ES']);
-
- $expectedResult = true;
- $result = $testee->is_available();
- $this->assertEquals($expectedResult, $result);
- }
-
- /**
- * WHEN gateway setting 'enabled' !== 'yes'
- * AND the customer has no country set
- * THEN we fallback to the shop country and is_available returns true
- * @test
- */
- public function gatewayAvailableWhenNoCountrySelected()
- {
- $testee = $this->buildTestee(['enabled'=>'yes']);
- $total = 10.00;
- $WC = $this->wooCommerceMocks->wooCommerce(10.00, 0, $total, 0, '');
- expect('WC')->andReturn($WC);
- $testee->expects($this->atLeast(2))->method('get_order_total')->willReturn($total);
- expect('get_woocommerce_currency')->andReturn('EUR');
- expect('get_transient')->andReturn([['id'=>'ideal']]);
- expect('wc_get_base_location')->andReturn(['country'=>'ES']);
-
- $expectedResult = true;
- $result = $testee->is_available();
- $this->assertEquals($expectedResult, $result);
- }
-
- private function buildTestee($settings){
- return $this->helperMocks->mollieGatewayBuilder('Ideal', false, false, $settings);
- }
-
- private function wcOrder($id = 1, $meta = false, $parentOrder = false, $status = 'processing')
- {
- $item = $this->createConfiguredMock(
- 'WC_Order',
- [
- 'get_id' => $id,
- 'get_order_key' => 'wc_order_hxZniP1zDcnM8',
- 'get_total' => '20',
- 'get_items' => [$this->wcOrderItem()],
- 'get_billing_first_name' => 'billingggivenName',
- 'get_billing_last_name' => 'billingfamilyName',
- 'get_billing_email' => 'billingemail',
- 'get_shipping_first_name' => 'shippinggivenName',
- 'get_shipping_last_name' => 'shippingfamilyName',
- 'get_billing_address_1' => 'shippingstreetAndNumber',
- 'get_billing_address_2' => 'billingstreetAdditional',
- 'get_billing_postcode' => 'billingpostalCode',
- 'get_billing_city' => 'billingcity',
- 'get_billing_state' => 'billingregion',
- 'get_billing_country' => 'billingcountry',
- 'get_shipping_address_1' => 'shippingstreetAndNumber',
- 'get_shipping_address_2' => 'shippingstreetAdditional',
- 'get_shipping_postcode' => 'shippingpostalCode',
- 'get_shipping_city' => 'shippingcity',
- 'get_shipping_state' => 'shippingregion',
- 'get_shipping_country' => 'shippingcountry',
- 'get_shipping_methods' => false,
- 'get_order_number' => 1,
- 'get_payment_method' => 'mollie_wc_gateway_ideal',
- 'get_currency' => 'EUR',
- 'get_meta' => $meta,
- 'get_parent' => $parentOrder,
- 'update_status'=>$status
- ]
- );
-
- return $item;
- }
- private function wcOrderItem()
- {
- $item = new \WC_Order_Item_Product();
-
- $item['quantity'] = 1;
- $item['variation_id'] = null;
- $item['product_id'] = 1;
- $item['line_subtotal_tax']= 0;
- $item['line_total']= 20;
- $item['line_subtotal']= 20;
- $item['line_tax']= 0;
- $item['tax_status']= '';
- $item['total']= 20;
- $item['name']= 'productName';
-
- return $item;
- }
-
-}
-
-
-
diff --git a/tests/php/Functional/HelperMocks.php b/tests/php/Functional/HelperMocks.php
index bb264c1d1..be2ee804d 100644
--- a/tests/php/Functional/HelperMocks.php
+++ b/tests/php/Functional/HelperMocks.php
@@ -4,17 +4,20 @@
namespace Mollie\WooCommerceTests\Functional;
+use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\Api\MollieApiClient;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Notice\AdminNotice;
use Mollie\WooCommerce\Payment\MollieOrder;
use Mollie\WooCommerce\Payment\MollieOrderService;
-use Mollie\WooCommerce\Payment\OrderInstructionsService;
-use Mollie\WooCommerce\Payment\OrderItemsRefunder;
+use Mollie\WooCommerce\Payment\MolliePayment;
+use Mollie\WooCommerce\Payment\Request\RequestFactory;
+use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
+use Mollie\WooCommerce\Gateway\Refund\OrderItemsRefunder;
use Mollie\WooCommerce\Payment\OrderLines;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\Ideal;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\SDK\HttpResponse;
@@ -50,14 +53,24 @@ public function statusHelper()
return new Status();
}
- public function paymentFactory($apiClientMock){
+ public function genericPaymentGatewayMock()
+ {
+ $mock = $this->getMockBuilder(PaymentGateway::class)
+ ->addMethods(['supports'])
+ ->onlyMethods(['get_return_url'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ return $mock;
+ }
+
+ public function paymentFactory(){
return new PaymentFactory(
- $this->dataHelper($apiClientMock),
- $this->apiHelper($apiClientMock),
- $this->settingsHelper(),
- $this->pluginId(),
- $this->loggerMock(),
- $this->orderLines($apiClientMock)
+ function(){
+ return $this->mollieOrderMock();
+ },
+ function(){
+ return $this->molliePaymentMock();
+ }
);
}
@@ -67,6 +80,12 @@ public function mollieOrderMock()
->disableOriginalConstructor()
->getMock();
}
+ public function molliePaymentMock()
+ {
+ return $this->getMockBuilder(MolliePayment::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
public function noticeMock()
{
return $this->getMockBuilder(AdminNotice::class)
@@ -77,7 +96,7 @@ public function noticeMock()
public function paymentService()
{
return $this->createConfiguredMock(
- PaymentService::class,
+ PaymentProcessor::class,
[
]
@@ -86,7 +105,7 @@ public function paymentService()
public function orderInstructionsService()
{
return $this->createConfiguredMock(
- OrderInstructionsService::class,
+ OrderInstructionsManager::class,
[
]
@@ -239,9 +258,8 @@ public function paymentMethodBuilder($paymentMethodName, $isSepa = false, $isSub
return $paymentMethod;
}
- public function mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscription, $settings, $paymentService = null) {
+ public function mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscription, $settings) {
$paymentMethod = $this->paymentMethodBuilder($paymentMethodName, $isSepa, $isSubscription, $settings);
- $paymentService = $paymentService ?? $this->paymentService();
$orderInstructionsService = $this->orderInstructionsService();
$mollieOrderService = $this->mollieOrderService();
$data = $this->dataHelper();
@@ -251,16 +269,14 @@ public function mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscriptio
$mollieObject = $this->getMockBuilder(MollieObject::class)
->disableOriginalConstructor()
->getMock();
- $apiClientMock = $this->apiClient();
- $paymentFactory = $this->paymentFactory($apiClientMock);
+ $paymentFactory = $this->paymentFactory();
$pluginId = $this->pluginId();
return $this->buildTesteeMock(
- MolliePaymentGateway::class,
+ MolliePaymentGatewayHandler::class,
[
$paymentMethod,
- $paymentService,
$orderInstructionsService,
$mollieOrderService,
$data,
@@ -281,6 +297,13 @@ public function mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscriptio
]
)->getMock();
}
+
+ public function requestFactory()
+ {
+ return $this->getMockBuilder(RequestFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
}
class emptyLogger implements LoggerInterface{
diff --git a/tests/php/Functional/PayPalButton/AjaxRequestsTest.php b/tests/php/Functional/PayPalButton/AjaxRequestsTest.php
index 17b6bd79f..79f7c2103 100644
--- a/tests/php/Functional/PayPalButton/AjaxRequestsTest.php
+++ b/tests/php/Functional/PayPalButton/AjaxRequestsTest.php
@@ -8,7 +8,7 @@
use Mollie\WooCommerce\Buttons\PayPalButton\PayPalAjaxRequests;
use Mollie\WooCommerce\Buttons\PayPalButton\PayPalDataObjectHttp;
use Mollie\WooCommerce\Gateway\Surcharge;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
+use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\Stubs\postDTOTestsStubs;
use Mollie\WooCommerceTests\TestCase;
@@ -75,7 +75,7 @@ public function testcreateWcOrderSuccess()
]
);
$logger = $this->helperMocks->loggerMock();
- $paypalGateway = $this->mollieGateway('paypal', false, true);
+ $paypalGateway = $this->helperMocks->genericPaymentGatewayMock();
expect('wp_verify_nonce')
->andReturn(true);
$dataObject = new PayPalDataObjectHttp($logger);
diff --git a/tests/php/Functional/Payment/OrderItemsRefunderTest.php b/tests/php/Functional/Payment/OrderItemsRefunderTest.php
index 15e04b900..c0ca7fcaf 100644
--- a/tests/php/Functional/Payment/OrderItemsRefunderTest.php
+++ b/tests/php/Functional/Payment/OrderItemsRefunderTest.php
@@ -8,8 +8,8 @@
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Order;
use Mollie\Api\Resources\Refund;
-use Mollie\WooCommerce\Payment\OrderItemsRefunder;
-use Mollie\WooCommerce\Payment\RefundLineItemsBuilder;
+use Mollie\WooCommerce\Gateway\Refund\OrderItemsRefunder;
+use Mollie\WooCommerce\Gateway\Refund\RefundLineItemsBuilder;
use Mollie\WooCommerce\Shared\Data;
diff --git a/tests/php/Functional/Payment/RequestObjectTest.php b/tests/php/Functional/Payment/OrderRequestStrategyTest.php
similarity index 55%
rename from tests/php/Functional/Payment/RequestObjectTest.php
rename to tests/php/Functional/Payment/OrderRequestStrategyTest.php
index 53e8f119f..1122ededf 100644
--- a/tests/php/Functional/Payment/RequestObjectTest.php
+++ b/tests/php/Functional/Payment/OrderRequestStrategyTest.php
@@ -3,25 +3,145 @@
namespace Mollie\WooCommerceTests\Functional\Payment;
+use Mockery;
use Mollie\Api\MollieApiClient;
-use Mollie\WooCommerce\Payment\MollieOrder;
use Mollie\WooCommerce\Payment\OrderLines;
+use Mollie\WooCommerce\Payment\Request\Middleware\MiddlewareHandler;
+use Mollie\WooCommerce\Payment\Request\Middleware\OrderLinesMiddleware;
+use Mollie\WooCommerce\Payment\Request\Strategies\OrderRequestStrategy;
+use Mollie\WooCommerce\Payment\Request\Strategies\RequestStrategyInterface;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\Stubs\WC_Order_Item_Product;
use Mollie\WooCommerceTests\Stubs\WC_Settings_API;
use Mollie\WooCommerceTests\Stubs\WC_Product;
use Mollie\WooCommerceTests\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
+use WC_Order;
+
use function Brain\Monkey\Functions\stubs;
use function Brain\Monkey\Functions\when;
/**
* Class Mollie_WC_Plugin_Test
*/
-class RequestObjectTest extends TestCase
+class OrderRequestStrategyTest extends TestCase
{
- /** @var HelperMocks */
+ /**
+ * @var HelperMocks
+ */
private $helperMocks;
+
+ public function setUp(): void
+ {
+ $_POST = [];
+ parent::setUp();
+
+ when('__')->returnArg(1);
+
+ $this->helperMocks = new HelperMocks();
+ }
+
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ Mockery::close();
+ }
+
+ public function test_createRequest_returnsFailure_ifGatewayMissingOrNotMollie()
+ {
+ when('wc_get_payment_gateway_by_order')->justReturn(null);
+
+
+ stubs([
+ 'mollieWooCommerceIsMollieGateway' => false,
+ ]);
+
+ $dataHelper = $this->helperMocks->dataHelper();
+ $settingsHelper = $this->helperMocks->settingsHelper();
+
+ $middlewareHandler = new MiddlewareHandler([]);
+ $strategyClass = OrderRequestStrategy::class;
+ /** @var RequestStrategyInterface $strategy */
+ $strategy = new $strategyClass($dataHelper, $settingsHelper, $middlewareHandler);
+
+ $order = Mockery::mock(WC_Order::class);
+
+ $result = $strategy->createRequest($order, 'some-customer-id');
+ $this->assertEquals(['result' => 'failure'], $result, 'Should return failure if no gateway is found.');
+ }
+
+ public function test_createRequest_returnsFailure_ifNotMollieGateway()
+ {
+ $nonMollieGateway = new \stdClass();
+ $nonMollieGateway->id = 'some_other_gateway';
+
+ when('wc_get_payment_gateway_by_order')->justReturn($nonMollieGateway);
+ stubs([
+ 'mollieWooCommerceIsMollieGateway' => false,
+ ]);
+
+ $dataHelper = $this->helperMocks->dataHelper();
+ $settingsHelper = $this->helperMocks->settingsHelper();
+ $middlewareHandler = new MiddlewareHandler([]);
+ $strategyClass = OrderRequestStrategy::class;
+ $strategy = new $strategyClass($dataHelper, $settingsHelper, $middlewareHandler);
+ $order = Mockery::mock(WC_Order::class);
+
+ $result = $strategy->createRequest($order, 'some-customer-id');
+ $this->assertEquals(['result' => 'failure'], $result, 'Should return failure if gateway is not Mollie.');
+ }
+
+ public function test_createRequest_buildsExpectedData_forValidMollieGateway()
+ {
+ $mollieGateway = new \stdClass();
+ $mollieGateway->id = 'mollie_ideal';
+
+ when('wc_get_payment_gateway_by_order')->justReturn($mollieGateway);
+ stubs([
+ 'mollieWooCommerceIsMollieGateway' => true,
+ ]);
+
+ $dataHelper = $this->helperMocks->dataHelper();
+ $settingsHelper = $this->helperMocks->settingsHelper();
+ $order = Mockery::mock(WC_Order::class);
+ $middleware = Mockery::mock(OrderLinesMiddleware::class);
+ $middleware->shouldReceive('__invoke')->andReturnUsing(function ($data) {
+ $data['decorated'] = true;
+ return $data;
+ });
+
+ $middlewareHandler = new MiddlewareHandler([$middleware]);
+
+
+ $strategyClass = OrderRequestStrategy::class;
+ $strategy = new $strategyClass($dataHelper, $settingsHelper, $middlewareHandler);
+
+
+ $order->shouldReceive('get_id')->andReturn(1234);
+ $order->shouldReceive('get_total')->andReturn(99.99);
+ $order->shouldReceive('get_order_number')->andReturn('1001');
+ $order->shouldReceive('get_currency')->andReturn('EUR');
+
+ $result = $strategy->createRequest($order, 'cust_abc123');
+
+
+ $this->assertArrayHasKey('amount', $result);
+ $this->assertArrayHasKey('method', $result);
+ $this->assertArrayHasKey('locale', $result);
+ $this->assertArrayHasKey('metadata', $result);
+ $this->assertArrayHasKey('orderNumber', $result);
+
+ $this->assertEquals('ideal', $result['method']);
+ $this->assertEquals('en_US', $result['locale'], 'Should get locale from settings');
+ $this->assertEquals('EUR', $result['amount']['currency']);
+ $this->assertEquals('99.99', $result['amount']['value'], 'Should reflect the formatted total');
+
+ $this->assertEquals(1234, $result['metadata']['order_id']);
+ $this->assertEquals('1001', $result['orderNumber']);
+
+ $this->assertArrayHasKey('decorated', $result, 'Decorator was applied');
+ $this->assertTrue($result['decorated'], 'Decorator set its key to true');
+ }
public $products = [
'1' => [
'id' => 1,
@@ -45,12 +165,6 @@ class RequestObjectTest extends TestCase
]
];
- public function __construct($name = null, array $data = [], $dataName = '')
- {
- parent::__construct($name, $data, $dataName);
- $this->helperMocks = new HelperMocks();
- }
-
/**
* GIVEN A PAYMENT REQUEST
* WHEN THE TOTAL AMOUNT HAS DECIMALS
@@ -58,6 +172,7 @@ public function __construct($name = null, array $data = [], $dataName = '')
*
*
* @test
+ * @group skip
*/
public function processPayment_decimals_and_taxes_request_no_mismatch()
{
@@ -96,61 +211,70 @@ private function generateTestDataSet(): array
public function executeTest($order)
{
$customerId = 1;
- $wrapperMock = $this->createMock(WC_Product::class);
+ // Mock product retrieval so each product ID corresponds to a product with the given price
+ $wrapperMock = $this->createMock(WC_Product::class);
$callback = function ($productId) {
$price = $this->products[$productId]['price'];
- $productMock = $this->wcProduct($productId, $price);
-
- return $productMock;
+ return $this->wcProduct($productId, $price);
};
$wrapperMock->method('getProduct')->willReturnCallback($callback);
+ $apiClientMock = $this->createConfiguredMock(
+ MollieApiClient::class,
+ []
+ );
+ $orderLines = new OrderLines($this->helperMocks->dataHelper($apiClientMock), $this->helperMocks->pluginId());
+ $linesDecorator = new OrderLinesMiddleware($orderLines, 'no_category');
+ $paymentGateway = $this->helperMocks->genericPaymentGatewayMock();
+ when('wc_get_payment_gateway_by_order')->justReturn($paymentGateway);
stubs([
- 'wc_get_payment_gateway_by_order' => $this->mollieGateway(
- 'ideal',
- $this->helperMocks->paymentService()
- ),
'add_query_arg' => 'https://webshop.example.org/wc-api/mollie_return?order_id=1&key=wc_order_hxZniP1zDcnM8',
'WC' => $this->wooCommerce(),
'get_option' => ['enabled' => false],
'wc_get_product' => $wrapperMock,
'wc_clean' => false,
'wp_parse_url' => null,
- 'wp_strip_all_tags' => null
+ 'wp_strip_all_tags' => null,
]);
- $apiClientMock = $this->createConfiguredMock(
- MollieApiClient::class,
- []
- );
- $orderLines = new OrderLines($this->helperMocks->dataHelper($apiClientMock), $this->helperMocks->pluginId());
- $testee = new MollieOrder(
- $this->helperMocks->orderItemsRefunder(),
- 'order',
- $this->helperMocks->pluginId(),
- $this->helperMocks->apiHelper($apiClientMock),
- $this->helperMocks->settingsHelper(),
+
+
+
+ $strategy = new OrderRequestStrategy(
$this->helperMocks->dataHelper($apiClientMock),
- $this->helperMocks->loggerMock(),
- $orderLines
+ $this->helperMocks->settingsHelper(),
+ [$linesDecorator]
);
+ $createRequestResult = $strategy->createRequest($order, (string) $customerId);
- /*
- * Execute Test
- */
+ $this->assertArrayHasKey('amount', $createRequestResult, 'createRequest should include amount');
+ $this->assertArrayHasKey('value', $createRequestResult['amount'], 'createRequest->amount should have value');
+ $this->assertArrayHasKey('currency', $createRequestResult['amount'], 'createRequest->amount should have currency');
+ $this->assertArrayHasKey('method', $createRequestResult, 'createRequest should include method');
+ $this->assertArrayHasKey('locale', $createRequestResult, 'createRequest should include locale');
+ $this->assertArrayHasKey('metadata', $createRequestResult, 'createRequest should include metadata');
+ $this->assertArrayHasKey('orderNumber', $createRequestResult, 'createRequest should include orderNumber');
- $arrayResult = $testee->getPaymentRequestData($order, $customerId);
- $expectedResult = $this->noMismatchError($arrayResult);
+ $expectedResult = $this->noMismatchError($createRequestResult);
$this->assertTrue($expectedResult);
}
-
- protected function setUp(): void
+ private function wcProduct($productId, $price)
{
- $_POST = [];
- parent::setUp();
- when('__')->returnArg(1);
+ $item = $this->createConfiguredMock(
+ WC_Product::class,
+ [
+ 'get_price' => $price,
+ 'get_id'=>$productId,
+ 'get_type' => 'simple',
+ 'needs_shipping' => true,
+ 'get_sku'=>5,
+ 'is_taxable'=>true
+ ]
+ );
+
+ return $item;
}
protected function mollieGateway($paymentMethodName, $testee, $isSepa = false, $isSubscription = false)
diff --git a/tests/php/Functional/Payment/PaymentServiceTest.php b/tests/php/Functional/Payment/PaymentServiceTest.php
index 8e5d00300..39bc68396 100644
--- a/tests/php/Functional/Payment/PaymentServiceTest.php
+++ b/tests/php/Functional/Payment/PaymentServiceTest.php
@@ -5,9 +5,11 @@
use Mollie\Api\Endpoints\OrderEndpoint;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\MollieApiClient;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
+use Mollie\WooCommerce\Payment\MollieOrder;
use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
-use Mollie\WooCommerce\Payment\PaymentService;
+use Mollie\WooCommerce\Payment\PaymentFactory;
+use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\IconFactory;
use Mollie\WooCommerce\PaymentMethods\Voucher;
use Mollie\WooCommerceTests\Functional\HelperMocks;
@@ -74,19 +76,27 @@ public function processPayment_Order_success(){
);
$apiClientMock->orders = $orderEndpoints;
$voucherDefaultCategory = Voucher::NO_CATEGORY;
- $testee = new PaymentService(
+ $deprecatedGatewayHelper = $this->mollieGateway($paymentMethodId);
+ $testee = new PaymentProcessor(
$this->helperMocks->noticeMock(),
$this->helperMocks->loggerMock(),
- $this->helperMocks->paymentFactory($apiClientMock),
+ $this->paymentFactory(),
$this->helperMocks->dataHelper($apiClientMock),
$this->helperMocks->apiHelper($apiClientMock),
$this->helperMocks->settingsHelper(),
$this->helperMocks->pluginId(),
$this->paymentCheckoutService($apiClientMock),
- $voucherDefaultCategory
+ $voucherDefaultCategory,
+ ['mollie_wc_gateway_ideal' => $deprecatedGatewayHelper]
);
- $gateway = $this->mollieGateway($paymentMethodId, $testee);
- $testee->setGateway($gateway);
+ $gateway = $this->helperMocks->genericPaymentGatewayMock();
+ $gateway->id = 'mollie_wc_gateway_ideal';
+ $gateway->method('supports')->willReturnMap([
+ ['subscriptions', false]
+ ]);
+ $gateway->method('get_return_url')->willReturn($processPaymentRedirect);
+
+ $testee->setGatewayHelper($gateway->id);
stubs(
[
@@ -102,24 +112,15 @@ public function processPayment_Order_success(){
]
);
- $expectedRequestToMollie = $this->expectedRequestData($wcOrder);
- $orderEndpoints->method('create')->with($expectedRequestToMollie);
-
/*
* Expectations
*/
- expect('is_plugin_active')
- ->andReturn(false);
+ //we are not testing the request data, as that is tested in a separate test
+
expect('get_option')
->with('mollie-payments-for-woocommerce_api_switch')
->andReturn(false);
- expect('get_transient')->andReturn(['ideal'=>['id'=>'ideal', 'status'=>'activated']]);
- $wcOrder->expects($this->any())
- ->method('get_billing_company')
- ->willReturn('');
- $wcOrder->expects($this->any())
- ->method('get_billing_phone')
- ->willReturn('+34345678900');
+
/*
* Execute Test
*/
@@ -127,7 +128,7 @@ public function processPayment_Order_success(){
'result' => 'success',
'redirect' => $processPaymentRedirect,
);
- $arrayResult = $testee->processPayment(1, $wcOrder, $paymentMethod, $processPaymentRedirect);
+ $arrayResult = $testee->processPayment($wcOrder, $gateway);
self::assertEquals($expectedResult, $arrayResult);
}
@@ -157,26 +158,29 @@ public function processAsMollieOrder_BailsIf_FraudException()
$apiClientMock = $this->createMock(MollieApiClient::class);
$apiClientMock->orders = $orderEndpointsMock;
$voucherDefaultCategory = Voucher::NO_CATEGORY;
-
- $testee = new PaymentService(
+ $gateway = $this->helperMocks->genericPaymentGatewayMock();
+ $gateway->id = 'mollie_wc_gateway_ideal';
+ $deprecatedGatewayHelper = $this->mollieGateway($paymentMethodId);
+ $testee = new PaymentProcessor(
$this->helperMocks->noticeMock(),
$this->helperMocks->loggerMock(),
- $this->helperMocks->paymentFactory($apiClientMock),
+ $this->helperMocks->paymentFactory(),
$this->helperMocks->dataHelper($apiClientMock),
$this->helperMocks->apiHelper($apiClientMock),
$this->helperMocks->settingsHelper(),
$this->helperMocks->pluginId(),
$this->paymentCheckoutService($apiClientMock),
- $voucherDefaultCategory
+ $voucherDefaultCategory,
+ ['mollie_wc_gateway_ideal' => $deprecatedGatewayHelper]
);
- $gateway = $this->mollieGateway($paymentMethodId, $testee);
$testee->setGateway($gateway);
+ $testee->setGatewayHelper('mollie_wc_gateway_ideal');
$wcOrderId = 1;
$wcOrderKey = 'wc_order_hxZniP1zDcnM8';
$wcOrder = $this->wcOrder($wcOrderId, $wcOrderKey);
$cusomerId = 1;
$apiKey = 'test_test';
- $method = new \ReflectionMethod(PaymentService::class, 'processAsMollieOrder');
+ $method = new \ReflectionMethod(PaymentProcessor::class, 'processAsMollieOrder');
$method->setAccessible(true);
$this->expectException(ApiException::class);
@@ -198,11 +202,34 @@ protected function setUp(): void
when('__')->returnArg(1);
}
- protected function mollieGateway($paymentMethodName, $testee, $isSepa = false, $isSubscription = false){
- return $this->helperMocks->mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscription, [], $testee);
+ protected function mollieGateway($paymentMethodName, $isSepa = false, $isSubscription = false){
+ return $this->helperMocks->mollieGatewayBuilder($paymentMethodName, $isSepa, $isSubscription, []);
}
+ public function paymentFactory(){
+ return new PaymentFactory(
+ function(){
+ return $this->mollieOrderMock();
+ },
+ function(){
+ return $this->molliePaymentMock();
+ }
+ );
+ }
+
+ public function mollieOrderMock()
+ {
+ $dataMock = $this->createMock(stdClass::class);
+ $dataMock->id = 'mocked_id';
+ $mollieOrder = $this->createConfiguredMock(MollieOrder::class,
+ [
+ 'getPaymentRequestData' => [],
+ 'data' => $dataMock
+ ]
+ );
+ return $mollieOrder;
+ }
/**
*
* @throws PHPUnit_Framework_Exception
diff --git a/tests/php/Functional/Payment/RefundLineItemsBuilderTest.php b/tests/php/Functional/Payment/RefundLineItemsBuilderTest.php
index b5924f04f..c316e84a0 100644
--- a/tests/php/Functional/Payment/RefundLineItemsBuilderTest.php
+++ b/tests/php/Functional/Payment/RefundLineItemsBuilderTest.php
@@ -2,9 +2,9 @@
namespace Mollie\WooCommerceTests\Functional\Payment;
-use Mollie\WooCommerce\Payment\OrderLineStatus;
-use Mollie\WooCommerce\Payment\PartialRefundException;
-use Mollie\WooCommerce\Payment\RefundLineItemsBuilder;
+use Mollie\WooCommerce\Gateway\Refund\OrderLineStatus;
+use Mollie\WooCommerce\Gateway\Refund\PartialRefundException;
+use Mollie\WooCommerce\Gateway\Refund\RefundLineItemsBuilder;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerceTests\Stubs\WC_Order_Item;
use Mollie\WooCommerceTests\TestCase;
diff --git a/tests/php/Functional/PaymentMethod/PaymentMethodTest.php b/tests/php/Functional/PaymentMethod/PaymentMethodTest.php
index 900cf6957..9deaf2796 100644
--- a/tests/php/Functional/PaymentMethod/PaymentMethodTest.php
+++ b/tests/php/Functional/PaymentMethod/PaymentMethodTest.php
@@ -1,11 +1,11 @@
pluginUrl, $this->pluginPath);
$settingsHelper = $this->helperMocks->settingsHelper();
- $paymentFieldsService = new PaymentFieldsService($this->helperMocks->dataHelper());
$surchargeService = new Surcharge();
$paymentMethod = $this->buildTesteeMock(
Creditcard::class,
- [$iconFactory, $settingsHelper, $paymentFieldsService, $surchargeService, []],
+ [$iconFactory, $settingsHelper, $surchargeService, []],
['getConfig', 'getSettings', 'getInitialOrderStatus', 'getIdFromConfig']
)->getMock();
diff --git a/tests/php/Functional/SDK/SdkTest.php b/tests/php/Functional/SDK/SdkTest.php
index eb2fd5ce2..2ca9c153b 100644
--- a/tests/php/Functional/SDK/SdkTest.php
+++ b/tests/php/Functional/SDK/SdkTest.php
@@ -9,11 +9,11 @@
use Mollie\Api\Resources\Mandate;
use Mollie\Api\Resources\MandateCollection;
use Mollie\Api\Resources\Payment;
-use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
+use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\SDK\HttpResponse;
use Mollie\WooCommerce\SDK\WordPressHttpAdapter;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
+use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\Stubs\WooCommerceMocks;
use Mollie\WooCommerceTests\TestCase;
diff --git a/tests/php/Functional/Shared/SurchargeHandlerTest.php b/tests/php/Functional/Shared/SurchargeHandlerTest.php
index bbf43be09..1a9f8817e 100644
--- a/tests/php/Functional/Shared/SurchargeHandlerTest.php
+++ b/tests/php/Functional/Shared/SurchargeHandlerTest.php
@@ -1,10 +1,10 @@
createConfiguredMock(
- MolliePaymentGateway::class,
+ MolliePaymentGatewayHandler::class,
[
'getSelectedIssuer' => 'ideal_INGBNL2A',
'get_return_url' => 'https://webshop.example.org/wc-api/',
diff --git a/tests/php/Functional/Subscription/MollieSubscriptionTest.php b/tests/php/Functional/Subscription/MollieSubscriptionTest.php
index d792bfa8b..ce9fce68a 100644
--- a/tests/php/Functional/Subscription/MollieSubscriptionTest.php
+++ b/tests/php/Functional/Subscription/MollieSubscriptionTest.php
@@ -10,7 +10,7 @@
use Mollie\Api\Resources\Payment;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\SDK\HttpResponse;
-use Mollie\WooCommerce\Subscription\MollieSubscriptionGateway;
+use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
use Mollie\WooCommerceTests\Functional\HelperMocks;
use Mollie\WooCommerceTests\TestCase;
@@ -43,7 +43,7 @@ public function renewSubscriptionPaymentTest()
$gatewayName = 'mollie_wc_gateway_ideal';
$renewalOrder = $this->wcOrder();
$subscription = $this->wcOrder(2, $gatewayName, $renewalOrder, 'active' );
-
+ $gateway = $this->helperMocks->genericPaymentGatewayMock();
$testee = $this->buildTestee();
expect('wcs_get_subscriptions_for_renewal_order')->andReturn(
@@ -52,7 +52,7 @@ public function renewSubscriptionPaymentTest()
$testee->expects($this->once())->method(
'restore_mollie_customer_id_and_mandate'
)->willReturn(false);
- expect('wc_get_payment_gateway_by_order')->andReturn($gatewayName);
+ expect('wc_get_payment_gateway_by_order')->andReturn($gateway);
$renewalOrder->expects($this->once())->method(
'set_payment_method'
)->with($gatewayName);
@@ -61,13 +61,12 @@ public function renewSubscriptionPaymentTest()
expect('wcs_get_subscription')->andReturn($subscription);
$expectedResult = ['result' => 'success'];
- $result = $testee->scheduled_subscription_payment(1.02, $renewalOrder);
+ $result = $testee->scheduled_subscription_payment(1.02, $renewalOrder, $gateway);
$this->assertEquals($expectedResult, $result);
}
private function buildTestee(){
$paymentMethod = $this->helperMocks->paymentMethodBuilder('Ideal');
- $paymentService = $this->helperMocks->paymentService();
$orderInstructionsService = $this->helperMocks->orderInstructionsService();
$mollieOrderService = $this->helperMocks->mollieOrderService();
$data = $this->helperMocks->dataHelper();
@@ -106,10 +105,9 @@ private function buildTestee(){
$pluginId = $this->helperMocks->pluginId();
$apiHelper = $this->helperMocks->apiHelper($apiClientMock);
return $this->buildTesteeMock(
- MollieSubscriptionGateway::class,
+ MollieSubscriptionGatewayHandler::class,
[
$paymentMethod,
- $paymentService,
$orderInstructionsService,
$mollieOrderService,
$data,
diff --git a/tests/php/Stubs/stubs.php b/tests/php/Stubs/stubs.php
deleted file mode 100644
index cb4c05ac2..000000000
--- a/tests/php/Stubs/stubs.php
+++ /dev/null
@@ -1,5 +0,0 @@
-