diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5d87b0920..4da9e6ac7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -36,8 +36,8 @@ jobs:
- name: Run PHPUnit
run: ./vendor/bin/phpunit
- - name: Run Psalm
- run: ./vendor/bin/psalm --show-info=false --threads=2
+ - name: Run PHPStan
+ run: ./vendor/bin/phpstan analyze --error-format=github
- name: Run PhpCS
run: ./vendor/bin/phpcs -n --parallel=2 --runtime-set ignore_warnings_on_exit 1
diff --git a/.idea/WooCommerce.iml b/.idea/WooCommerce.iml
index 692525fb1..3dddcc19e 100644
--- a/.idea/WooCommerce.iml
+++ b/.idea/WooCommerce.iml
@@ -73,6 +73,10 @@
+
+
+
+
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 0aea26527..d7a00f6ec 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -9,7 +9,8 @@
-
+
+
diff --git a/.idea/php.xml b/.idea/php.xml
index ff26ece69..b41d83ce0 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -22,6 +22,7 @@
+
@@ -266,6 +267,7 @@
+
@@ -280,6 +282,7 @@
+
diff --git a/composer.json b/composer.json
index 953633362..11468cc07 100644
--- a/composer.json
+++ b/composer.json
@@ -35,9 +35,12 @@
"inpsyde/php-coding-standards": "^1.0.0",
"inpsyde/composer-assets-compiler": "^2.5",
"php-stubs/wordpress-stubs": "^5.0@stable",
- "php-stubs/woocommerce-stubs": "7.9.0",
+ "php-stubs/woocommerce-stubs": "^10.6",
"vimeo/psalm": "^4.8 || ^5.13.0",
- "vlucas/phpdotenv": "^5.6"
+ "vlucas/phpdotenv": "^5.6",
+ "szepeviktor/phpstan-wordpress": "^1.3",
+ "phpstan/extension-installer": "^1.4",
+ "php-stubs/woocommerce-subscriptions-stubs": "^8.4"
},
"autoload": {
"psr-4": {
@@ -59,6 +62,8 @@
"fix-coding-standards": "vendor/bin/phpcbf",
"tests": "@php ./vendor/phpunit/phpunit/phpunit --coverage-text",
"tests:no-cov": "@php ./vendor/phpunit/phpunit/phpunit --no-coverage",
+ "phpstan": "vendor/bin/phpstan analyse",
+ "phpstan:raw": "vendor/bin/phpstan analyse --no-progress --error-format=raw",
"check-psalm": "vendor/bin/psalm",
"check-psalm:no-cache": "vendor/bin/psalm --no-cache"
},
@@ -98,7 +103,8 @@
"composer/package-versions-deprecated": true,
"automattic/jetpack-autoloader": false,
"composer/installers": true,
- "inpsyde/composer-assets-compiler": true
+ "inpsyde/composer-assets-compiler": true,
+ "phpstan/extension-installer": true
}
}
}
diff --git a/composer.lock b/composer.lock
index 51d10fb41..55c3e3bf5 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "77e2348ec8a23178cb5e3847f3d89e13",
+ "content-hash": "ed3e20f78e98d09e3f91abbee50d6941",
"packages": [
{
"name": "composer/ca-bundle",
@@ -2194,16 +2194,16 @@
},
{
"name": "php-stubs/woocommerce-stubs",
- "version": "v7.9.0",
+ "version": "v10.6.2",
"source": {
"type": "git",
"url": "https://github.com/php-stubs/woocommerce-stubs.git",
- "reference": "3a2f522e29451490c357af550227795d2b0fc55a"
+ "reference": "2cc4a2e110a4c6c93c2d4d06c786afa1faa2e9b8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-stubs/woocommerce-stubs/zipball/3a2f522e29451490c357af550227795d2b0fc55a",
- "reference": "3a2f522e29451490c357af550227795d2b0fc55a",
+ "url": "https://api.github.com/repos/php-stubs/woocommerce-stubs/zipball/2cc4a2e110a4c6c93c2d4d06c786afa1faa2e9b8",
+ "reference": "2cc4a2e110a4c6c93c2d4d06c786afa1faa2e9b8",
"shasum": ""
},
"require": {
@@ -2232,9 +2232,55 @@
],
"support": {
"issues": "https://github.com/php-stubs/woocommerce-stubs/issues",
- "source": "https://github.com/php-stubs/woocommerce-stubs/tree/v7.9.0"
+ "source": "https://github.com/php-stubs/woocommerce-stubs/tree/v10.6.2"
},
- "time": "2023-07-17T22:41:38+00:00"
+ "time": "2026-03-31T18:29:22+00:00"
+ },
+ {
+ "name": "php-stubs/woocommerce-subscriptions-stubs",
+ "version": "v8.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-stubs/woocommerce-subscriptions-stubs.git",
+ "reference": "6e225945956a40d711432a08a9f13d6cbad04922"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-stubs/woocommerce-subscriptions-stubs/zipball/6e225945956a40d711432a08a9f13d6cbad04922",
+ "reference": "6e225945956a40d711432a08a9f13d6cbad04922",
+ "shasum": ""
+ },
+ "require": {
+ "php-stubs/woocommerce-stubs": "^10.2",
+ "php-stubs/wordpress-stubs": "^5.3 || ^6.0"
+ },
+ "require-dev": {
+ "php": "~7.4 || ~8.1",
+ "php-stubs/generator": "^0.8.0"
+ },
+ "suggest": {
+ "symfony/polyfill-php74": "Symfony polyfill backporting some PHP 7.4+ features to lower PHP versions",
+ "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan"
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "WooCommerce Subscriptions function and class declaration stubs for static analysis.",
+ "homepage": "https://github.com/php-stubs/woocommerce-subscriptions-stubs",
+ "keywords": [
+ "PHPStan",
+ "static analysis",
+ "subscription",
+ "woocommerce",
+ "wordpress"
+ ],
+ "support": {
+ "issues": "https://github.com/php-stubs/woocommerce-subscriptions-stubs/issues",
+ "source": "https://github.com/php-stubs/woocommerce-subscriptions-stubs/tree/v8.4.0"
+ },
+ "time": "2026-02-14T10:11:19+00:00"
},
{
"name": "php-stubs/wordpress-stubs",
@@ -2595,6 +2641,54 @@
],
"time": "2025-12-27T19:41:33+00:00"
},
+ {
+ "name": "phpstan/extension-installer",
+ "version": "1.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/extension-installer.git",
+ "reference": "85e90b3942d06b2326fba0403ec24fe912372936"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936",
+ "reference": "85e90b3942d06b2326fba0403ec24fe912372936",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^2.0",
+ "php": "^7.2 || ^8.0",
+ "phpstan/phpstan": "^1.9.0 || ^2.0"
+ },
+ "require-dev": {
+ "composer/composer": "^2.0",
+ "php-parallel-lint/php-parallel-lint": "^1.2.0",
+ "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "PHPStan\\ExtensionInstaller\\Plugin"
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\ExtensionInstaller\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Composer plugin for automatic installation of PHPStan extensions",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/phpstan/extension-installer/issues",
+ "source": "https://github.com/phpstan/extension-installer/tree/1.4.3"
+ },
+ "time": "2024-09-04T20:21:43+00:00"
+ },
{
"name": "phpstan/phpdoc-parser",
"version": "2.3.2",
@@ -2642,6 +2736,59 @@
},
"time": "2026-01-25T14:56:51+00:00"
},
+ {
+ "name": "phpstan/phpstan",
+ "version": "1.12.33",
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1",
+ "reference": "37982d6fc7cbb746dda7773530cda557cdf119e1",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2|^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan-shim": "*"
+ },
+ "bin": [
+ "phpstan",
+ "phpstan.phar"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://phpstan.org/user-guide/getting-started",
+ "forum": "https://github.com/phpstan/phpstan/discussions",
+ "issues": "https://github.com/phpstan/phpstan/issues",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
+ }
+ ],
+ "time": "2026-02-28T20:30:03+00:00"
+ },
{
"name": "phpunit/php-code-coverage",
"version": "7.0.17",
@@ -4818,6 +4965,69 @@
],
"time": "2024-11-10T20:33:58+00:00"
},
+ {
+ "name": "szepeviktor/phpstan-wordpress",
+ "version": "v1.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/szepeviktor/phpstan-wordpress.git",
+ "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/7f8cfe992faa96b6a33bbd75c7bace98864161e7",
+ "reference": "7f8cfe992faa96b6a33bbd75c7bace98864161e7",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0",
+ "php-stubs/wordpress-stubs": "^4.7 || ^5.0 || ^6.0",
+ "phpstan/phpstan": "^1.10.31",
+ "symfony/polyfill-php73": "^1.12.0"
+ },
+ "require-dev": {
+ "composer/composer": "^2.1.14",
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "php-parallel-lint/php-parallel-lint": "^1.1",
+ "phpstan/phpstan-strict-rules": "^1.2",
+ "phpunit/phpunit": "^8.0 || ^9.0",
+ "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0",
+ "wp-coding-standards/wpcs": "3.1.0 as 2.3.0"
+ },
+ "suggest": {
+ "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods"
+ },
+ "type": "phpstan-extension",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "SzepeViktor\\PHPStan\\WordPress\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "WordPress extensions for PHPStan",
+ "keywords": [
+ "PHPStan",
+ "code analyse",
+ "code analysis",
+ "static analysis",
+ "wordpress"
+ ],
+ "support": {
+ "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues",
+ "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v1.3.5"
+ },
+ "time": "2024-06-28T22:27:19+00:00"
+ },
{
"name": "theseer/tokenizer",
"version": "1.3.1",
diff --git a/inc/woocommerce.php b/inc/woocommerce.php
index 27fe5b025..e163e8665 100644
--- a/inc/woocommerce.php
+++ b/inc/woocommerce.php
@@ -30,11 +30,11 @@ function is_order_received_page()
if (!function_exists('untrailingslashit')) {
/**
- * @since WooCommerce 2.2.0
- * @param string $string
+ * @param string|null $string
* @return string
+ * @since WooCommerce 2.2.0
*/
- function untrailingslashit($string)
+ function untrailingslashit(?string $string): string
{
if ($string === null) {
return '';
diff --git a/lib/payment-gateway/src/PaymentGateway.php b/lib/payment-gateway/src/PaymentGateway.php
index e1b07f77e..83ca66c76 100644
--- a/lib/payment-gateway/src/PaymentGateway.php
+++ b/lib/payment-gateway/src/PaymentGateway.php
@@ -67,6 +67,8 @@ public function __construct(
unset($this->form_fields);
unset($this->enabled);
+ // phpstan:ignore [wc-stub] process_admin_options is inherited from WC_Payment_Gateway but absent from stubs
+ // @phpstan-ignore-next-line
add_action(
'woocommerce_update_options_payment_gateways_' . $this->id,
[$this, 'process_admin_options']
@@ -420,7 +422,7 @@ public function get_field_value($key, $field, $postData = [])
sprintf('Field "%1$s" is invalid: %2$s', $key, $exception->getMessage())
);
- return null;
+ return '';
}
}
diff --git a/lib/payment-gateway/src/PaymentGatewayModule.php b/lib/payment-gateway/src/PaymentGatewayModule.php
index 9d5de0fa0..1ecb7ebf6 100644
--- a/lib/payment-gateway/src/PaymentGatewayModule.php
+++ b/lib/payment-gateway/src/PaymentGatewayModule.php
@@ -48,7 +48,7 @@ public function services(): array
* prevent potential namespace conflicts when multiple plugins use this payment gateway library.
*/
'payment_gateways.plugin_slug' => static function (ContainerInterface $container): string {
- /** @var PluginProperties $properties */
+ /** @var PluginProperties $pluginProperties */
$pluginProperties = $container->get(Package::PROPERTIES);
return $pluginProperties->baseName();
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
new file mode 100644
index 000000000..b867be060
--- /dev/null
+++ b/phpstan.neon.dist
@@ -0,0 +1,29 @@
+parameters:
+ level: 5
+ dynamicConstantNames:
+ - M4W_PLUGIN_DIR
+ - M4W_FILE
+ - M4W_PLUGIN_URL
+ paths:
+ - mollie-payments-for-woocommerce.php
+ - lib/
+ - inc/
+ - src/
+ excludePaths:
+ - '*/node_modules/*'
+ bootstrapFiles:
+ - vendor/php-stubs/woocommerce-stubs/woocommerce-stubs.php
+ - vendor/php-stubs/woocommerce-stubs/woocommerce-packages-stubs.php
+ - vendor/php-stubs/woocommerce-subscriptions-stubs/woocommerce-subscriptions-stubs.php
+ ignoreErrors:
+ # apply_filters is variadic in WordPress but the stubs only declare 2 required params
+ - '#^Function apply_filters invoked with [0-9]+ parameters, [0-9]+ required\.$#'
+ # CustomOrdersTableController is an internal WooCommerce class not in stubs
+ - '#^(Class Automattic\\WooCommerce\\Internal\\DataStores\\Orders\\CustomOrdersTableController not found|Call to method custom_orders_table_usage_is_enabled\(\) on an unknown class)#'
+ # Vendored PSR container uses a namespaced path
+ - '#(unknown class|Call to method .+ on an unknown class|has unknown class) Mollie\\WooCommerce\\Vendor\\Psr\\Container\\ContainerInterface#'
+ # WC()->cart and WC()->customer are typed as non-nullable in stubs but can be null at runtime
+ - '#^(Property WooCommerce::\$cart \(WC_Cart\) in isset\(\) is not nullable|Left side of && is always true)\.$#'
+ # M4W_PLUGIN_DIR constant is defined at runtime in the main plugin file
+ - '#^Constant M4W_PLUGIN_DIR not found\.$#'
+
diff --git a/src/Assets/AssetsModule.php b/src/Assets/AssetsModule.php
index bbc575873..d5953b80b 100644
--- a/src/Assets/AssetsModule.php
+++ b/src/Assets/AssetsModule.php
@@ -518,7 +518,7 @@ function () use ($container, $pluginUrl, $pluginPath) {
);
add_action(
'admin_init',
- function () use ($container, $pluginVersion, $pluginUrl) {
+ function () use ($pluginVersion, $pluginUrl) {
if (is_admin()) {
global $current_section;
wp_register_script(
diff --git a/src/Buttons/AbstractExpressButton.php b/src/Buttons/AbstractExpressButton.php
index 83596238f..568f7a02d 100644
--- a/src/Buttons/AbstractExpressButton.php
+++ b/src/Buttons/AbstractExpressButton.php
@@ -18,6 +18,10 @@ public function bootstrap()
$this->enqueueScripts();
}
+ protected function enqueueScripts(): void
+ {
+ }
+
protected function registerAjaxHandlers()
{
foreach ($this->getAjaxHandlers() as $action => $callback) {
diff --git a/src/Buttons/ApplePayButton/AppleAjaxRequests.php b/src/Buttons/ApplePayButton/AppleAjaxRequests.php
index 19fa8afd1..a50929eee 100644
--- a/src/Buttons/ApplePayButton/AppleAjaxRequests.php
+++ b/src/Buttons/ApplePayButton/AppleAjaxRequests.php
@@ -214,8 +214,8 @@ public function createWcOrder()
$applePayRequestDataObject->orderData('productDetail');
$cartItemKey = $cart->add_to_cart(
- filter_input(INPUT_POST, 'productId'),
- (bool) filter_input(INPUT_POST, 'productQuantity', FILTER_VALIDATE_INT)
+ (int)filter_input(INPUT_POST, 'productId', FILTER_SANITIZE_NUMBER_INT),
+ (int)filter_input(INPUT_POST, 'productQuantity', FILTER_VALIDATE_INT)
);
$this->addAddressesToOrder($applePayRequestDataObject);
@@ -300,7 +300,7 @@ protected function whichCalculateTotals(
* @param $productId
* @param $productQuantity
* @param $customerAddress
- * @param null $shippingMethod
+ * @param mixed $shippingMethod
*/
protected function calculateTotalsSingleProduct(
$productId,
@@ -405,6 +405,8 @@ protected function cartShippingMethods(
): array {
$shippingMethodsArray = [];
+ // phpstan:ignore [wc-stub] WC()->shipping is WC_Shipping|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$shippingMethods = WC()->shipping->calculate_shipping(
$this->getShippingPackages(
$customerAddress,
@@ -451,6 +453,8 @@ protected function getShippingPackages($customerAddress, $total)
$packages = [];
$packages[0]['contents'] = WC()->cart->cart_contents;
$packages[0]['contents_cost'] = $total;
+ // phpstan:ignore [wc-stub] WC()->session exposes applied_coupon as a dynamic property; WC session stubs lack coverage
+ // @phpstan-ignore-next-line
$packages[0]['applied_coupons'] = WC()->session->applied_coupon;
$packages[0]['destination']['country'] = $customerAddress['country'];
$packages[0]['destination']['state'] = '';
@@ -516,7 +520,7 @@ protected function cartCalculationResults(
* method
*
* @param $customerAddress
- * @param null $shippingMethodId
+ * @param mixed $shippingMethodId
*/
protected function calculateTotalsCartPage(
$customerAddress = null,
@@ -689,7 +693,7 @@ function ($result, $order_id) {
wp_send_json_error(
$this->responseTemplates->authorizationResultResponse(
'STATUS_FAILURE',
- 0,
+ '0',
[['errorCode' => 'unknown']]
)
);
diff --git a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
index 8a5dcf667..a496e9036 100644
--- a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
+++ b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
@@ -6,6 +6,9 @@
use Psr\Log\LoggerInterface as Logger;
+/**
+ * @phpcs:disable Inpsyde.CodeQuality.PropertyPerClassLimit.TooManyProperties
+ */
class ApplePayDataObjectHttp
{
/**
@@ -77,6 +80,7 @@ public function hasErrors()
{
return !empty($this->errors);
}
+
/**
* Returns errors
* @return array
@@ -179,7 +183,7 @@ public function orderData($callerPage)
!array_key_exists('emailAddress', $data[PropertiesDictionary::SHIPPING_CONTACT])
|| !$data[PropertiesDictionary::SHIPPING_CONTACT]['emailAddress']
) {
- $this->errors[] = [
+ $this->errors[] = [
'errorCode' => PropertiesDictionary::SHIPPING_CONTACT_INVALID,
'contactField' => 'emailAddress',
];
@@ -279,8 +283,8 @@ protected function simplifiedAddress($contactInfo)
* are not empty.
* If not it adds a contactField error to the object's error list
*
- * @param array $post The address to check
- * @param array $required The required fields for the given address
+ * @param array $post The address to check
+ * @param array $required The required fields for the given address
* @param string $errorCode Either shipping or billing kind
*
* @return bool
@@ -304,8 +308,7 @@ protected function addressHasRequiredFieldsValues(
$this->logger->debug(
sprintf('ApplePay Data Error: Missing value for %s', $requiredField)
);
- $this->errors[]
- = [
+ $this->errors[] = [
'errorCode' => $errorCode,
'contactField' => $errorValue,
];
@@ -318,7 +321,7 @@ protected function addressHasRequiredFieldsValues(
/**
* Returns the address details for after authorization steps
*
- * @param array $data
+ * @param array $data
*
* @param string $errorCode differentiates between billing and shipping information
*
diff --git a/src/Buttons/ApplePayButton/ApplePayDirectHandler.php b/src/Buttons/ApplePayButton/ApplePayDirectHandler.php
index 53bd3f2b8..7ff8a4485 100644
--- a/src/Buttons/ApplePayButton/ApplePayDirectHandler.php
+++ b/src/Buttons/ApplePayButton/ApplePayDirectHandler.php
@@ -11,6 +11,8 @@ class ApplePayDirectHandler
/**
* @var AdminNotice
*/
+ // phpstan:ignore [dead-code] injected via constructor but never read; kept in case future methods need admin notice access
+ // @phpstan-ignore-next-line
private $adminNotice;
/**
* @var AppleAjaxRequests
diff --git a/src/Buttons/ApplePayButton/ApplePayExpressButton.php b/src/Buttons/ApplePayButton/ApplePayExpressButton.php
index a0f2297f0..582919429 100644
--- a/src/Buttons/ApplePayButton/ApplePayExpressButton.php
+++ b/src/Buttons/ApplePayButton/ApplePayExpressButton.php
@@ -31,6 +31,8 @@ public function getButtonComponent(): string
public function canShow(): bool
{
return !empty($_SERVER['HTTPS']) &&
+ // phpstan:ignore [dead-code] isEnabledInSettings() is called but not declared in this class or its ancestors; likely missing trait or interface method
+ // @phpstan-ignore-next-line
$this->isEnabledInSettings();
}
@@ -42,6 +44,8 @@ public function getAjaxHandlers(): array
public function getScriptData(): array
{
return [
+ // phpstan:ignore [dead-code] getCountryCode() is called but not declared in this class or its ancestors; likely missing trait or interface method
+ // @phpstan-ignore-next-line
'shop' => ['countryCode' => $this->getCountryCode()],
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('mollie_applepay'),
diff --git a/src/Buttons/ApplePayButton/ResponsesToApple.php b/src/Buttons/ApplePayButton/ResponsesToApple.php
index d09608e52..82c570d7f 100644
--- a/src/Buttons/ApplePayButton/ResponsesToApple.php
+++ b/src/Buttons/ApplePayButton/ResponsesToApple.php
@@ -14,7 +14,7 @@ class ResponsesToApple
*/
protected $logger;
/**
- * @var
+ * @var mixed
*/
protected $deprecatedAppleHelper;
diff --git a/src/Buttons/PayPalButton/PayPalAjaxRequests.php b/src/Buttons/PayPalButton/PayPalAjaxRequests.php
index 56829ac55..d634f8d5b 100644
--- a/src/Buttons/PayPalButton/PayPalAjaxRequests.php
+++ b/src/Buttons/PayPalButton/PayPalAjaxRequests.php
@@ -9,13 +9,12 @@
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Shared\GatewaySurchargeHandler;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
use WC_Data_Exception;
class PayPalAjaxRequests
{
/**
- * @var
+ * @var mixed
*/
protected $gateway;
/**
@@ -135,7 +134,6 @@ public function createWcOrderFromCart()
$lockKey = 'mollie_paypal_cart_order_lock';
if (WC()->session->get($lockKey)) {
wp_send_json_error('Duplicate request');
- return;
}
WC()->session->set($lockKey, true);
@@ -243,7 +241,7 @@ protected function processOrderPayment($orderId)
* Handles the order creation in cart page
*
* @return array
- * @throws Exception
+ * @throws \Exception
*/
protected function createOrderFromCart()
{
@@ -257,7 +255,6 @@ protected function createOrderFromCart()
/**
* Checks if the nonce in the data object is valid
*
- * @param PayPalDataObjectHttp $PayPalRequestDataObject
*/
protected function isNonceValid(): bool
{
diff --git a/src/Buttons/PayPalButton/PayPalDataObjectHttp.php b/src/Buttons/PayPalButton/PayPalDataObjectHttp.php
index 66784ee3a..9c23cdc29 100644
--- a/src/Buttons/PayPalButton/PayPalDataObjectHttp.php
+++ b/src/Buttons/PayPalButton/PayPalDataObjectHttp.php
@@ -5,7 +5,6 @@
namespace Mollie\WooCommerce\Buttons\PayPalButton;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
class PayPalDataObjectHttp
{
@@ -138,7 +137,7 @@ protected function assignDataObjectValues(array $data)
* Selector for the different filters to apply to each field
* @param $value
*
- * @return int
+ * @return int|false
*/
protected function filterType($value)
{
diff --git a/src/Buttons/PayPalButton/PayPalExpressButton.php b/src/Buttons/PayPalButton/PayPalExpressButton.php
index 52eab99e9..801a247fa 100644
--- a/src/Buttons/PayPalButton/PayPalExpressButton.php
+++ b/src/Buttons/PayPalButton/PayPalExpressButton.php
@@ -167,6 +167,7 @@ private function registerCartPageHook(): void
private function isVirtualProduct(\WC_Product $product): bool
{
if ($product->is_type('variable')) {
+ assert($product instanceof \WC_Product_Variable);
foreach ($product->get_available_variations() as $variation) {
if ($variation['is_virtual']) {
return true;
diff --git a/src/Buttons/PayPalButton/WCOrderCalculator.php b/src/Buttons/PayPalButton/WCOrderCalculator.php
index 259eb1ad6..2e717d050 100644
--- a/src/Buttons/PayPalButton/WCOrderCalculator.php
+++ b/src/Buttons/PayPalButton/WCOrderCalculator.php
@@ -5,7 +5,6 @@
namespace Mollie\WooCommerce\Buttons\PayPalButton;
use WC_Order;
-use WC_Order_Item_Product;
class WCOrderCalculator extends WC_Order
{
@@ -30,23 +29,23 @@ public function calculate_totals($and_taxes = true)
// Sum shipping costs.
foreach ($this->get_shipping_methods() as $shipping) {
- $shipping_total += $this->round($shipping->get_total(), wc_get_price_decimals());
+ $shipping_total += $this->round((float)$shipping->get_total(), wc_get_price_decimals());
}
- $this->set_shipping_total($shipping_total);
+ $this->set_shipping_total((string)$shipping_total);
// Sum fee costs.
foreach ($this->get_fees() as $item) {
- $fee_total = $item->get_total();
+ $fee_total = (float)$item->get_total();
if (0 > $fee_total) {
$max_discount = $this->round($cart_total + $fees_total + $shipping_total, wc_get_price_decimals()) * -1;
if ($fee_total < $max_discount && 0 > $max_discount) {
- $item->set_total($max_discount);
+ $item->set_total((string)$max_discount);
}
}
- $fees_total += $item->get_total();
+ $fees_total += (float)$item->get_total();
}
// Calculate taxes for items, shipping, discounts. Note; this also triggers save().
@@ -56,6 +55,8 @@ public function calculate_totals($and_taxes = true)
// Sum taxes again so we can work out how much tax was discounted. This uses original values, not those possibly rounded to 2dp.
foreach ($this->get_items() as $item) {
+ // phpstan:ignore [wc-stub] get_items() returns WC_Order_Item[] but get_taxes() is only typed on product/shipping subtypes
+ // @phpstan-ignore-next-line
$taxes = $item->get_taxes();
foreach ($taxes['total'] as $tax_rate_id => $tax) {
@@ -67,9 +68,15 @@ public function calculate_totals($and_taxes = true)
}
}
- $this->set_discount_total($this->round($cart_subtotal - $cart_total, wc_get_price_decimals()));
- $this->set_discount_tax(wc_round_tax_total($cart_subtotal_tax - $cart_total_tax));
- $this->set_total($this->round($cart_total + $fees_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals()));
+ $this->set_discount_total((string)$this->round($cart_subtotal - $cart_total, wc_get_price_decimals()));
+ $this->set_discount_tax((string)wc_round_tax_total($cart_subtotal_tax - $cart_total_tax));
+ $this->set_total(
+ (string)$this->round(
+ $cart_total + $fees_total + (float)$this->get_shipping_total() + (float)$this->get_cart_tax(
+ ) + (float)$this->get_shipping_tax(),
+ wc_get_price_decimals()
+ )
+ );
do_action('woocommerce_order_after_calculate_totals', $and_taxes, $this);
@@ -86,6 +93,8 @@ public function update_taxes()
$saved_rate_ids = [];
foreach ($this->get_items([ 'line_item', 'fee' ]) as $item_id => $item) {
+ // phpstan:ignore [wc-stub] get_items() returns WC_Order_Item[] but get_taxes() is only typed on product/shipping subtypes
+ // @phpstan-ignore-next-line
$taxes = $item->get_taxes();
foreach ($taxes['total'] as $tax_rate_id => $tax) {
$tax_amount = $this->round_line_tax($tax, false);
@@ -114,8 +123,12 @@ public function update_taxes()
continue;
}
$saved_rate_ids[] = $tax->get_rate_id();
- $tax->set_tax_total(isset($cart_taxes[ $tax->get_rate_id() ]) ? $cart_taxes[ $tax->get_rate_id() ] : 0);
- $tax->set_shipping_tax_total(! empty($shipping_taxes[ $tax->get_rate_id() ]) ? $shipping_taxes[ $tax->get_rate_id() ] : 0);
+ $tax->set_tax_total(
+ (string)(isset($cart_taxes[$tax->get_rate_id()]) ? $cart_taxes[$tax->get_rate_id()] : 0)
+ );
+ $tax->set_shipping_tax_total(
+ (string)(!empty($shipping_taxes[$tax->get_rate_id()]) ? $shipping_taxes[$tax->get_rate_id()] : 0)
+ );
$tax->save();
}
@@ -125,17 +138,21 @@ public function update_taxes()
foreach ($new_rate_ids as $tax_rate_id) {
$item = new \WC_Order_Item_Tax();
$item->set_rate($tax_rate_id);
- $item->set_tax_total(isset($cart_taxes[ $tax_rate_id ]) ? $cart_taxes[ $tax_rate_id ] : 0);
- $item->set_shipping_tax_total(! empty($shipping_taxes[ $tax_rate_id ]) ? $shipping_taxes[ $tax_rate_id ] : 0);
+ $item->set_tax_total((string)(isset($cart_taxes[$tax_rate_id]) ? $cart_taxes[$tax_rate_id] : 0));
+ $item->set_shipping_tax_total(
+ (string)(!empty($shipping_taxes[$tax_rate_id]) ? $shipping_taxes[$tax_rate_id] : 0)
+ );
$this->add_item($item);
}
- $this->set_shipping_tax(array_sum($shipping_taxes));
- $this->set_cart_tax(array_sum($cart_taxes));
+ $this->set_shipping_tax((string)array_sum($shipping_taxes));
+ $this->set_cart_tax((string)array_sum($cart_taxes));
}
public function add_product($product, $qty = 1, $args = [])
{
+ // phpstan:ignore [wc-stub] parent WC_Order::add_product() declares $product as WC_Product; override loosens the type to allow null/false
+ // @phpstan-ignore-next-line
if ($product) {
$default_args = [
'name' => $product->get_name(),
diff --git a/src/Gateway/GatewayModule.php b/src/Gateway/GatewayModule.php
index a6e8e0d12..61643aa1c 100644
--- a/src/Gateway/GatewayModule.php
+++ b/src/Gateway/GatewayModule.php
@@ -20,9 +20,7 @@
use Mollie\WooCommerce\Gateway\Voucher\MaybeDisableGateway;
use Mollie\WooCommerce\Payment\MollieOrderService;
use Mollie\WooCommerce\PaymentMethods\Constants;
-use Mollie\WooCommerce\PaymentMethods\IconFactory;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
-use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\GatewaySurchargeHandler;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
@@ -173,20 +171,22 @@ static function ($paymentContext) {
if (!$title) {
return;
}
+ // phpstan:ignore [wc-stub] $paymentContext is passed via WC REST action with no declared type; ->order is a WC_Order
+ // @phpstan-ignore-next-line
$order = $paymentContext->order;
$order->set_payment_method_title($title);
$order->save();
}
);
add_action('add_meta_boxes_woocommerce_page_wc-orders', [$this, 'addShopOrderMetabox'], 10);
- add_filter('woocommerce_checkout_fields', static function ($fields) use ($container) {
+ add_filter('woocommerce_checkout_fields', static function ($fields) {
if (!isset($fields['billing']['billing_phone']) || !$fields['billing']['billing_phone']['required']) {
update_option('mollie_wc_is_phone_required_flag', false);
} else {
update_option('mollie_wc_is_phone_required_flag', true);
}
return $fields;
- }, 10, 3);
+ }, 10, 1);
add_action('init', static function () use ($container) {
$paymentMethods = $container->get('gateway.paymentMethods');
@@ -523,7 +523,7 @@ public function paymentButtonsBootstrap(ContainerInterface $container): void
*
* @return array
*/
- protected function instantiatePaymentMethods(): array
+ public function instantiatePaymentMethods(): array
{
$paymentMethods = [];
$allGatewayClassNames = SharedDataDictionary::GATEWAY_CLASSNAMES;
@@ -547,10 +547,6 @@ protected function instantiatePaymentMethods(): array
/**
* @param string $id
- * @param IconFactory $iconFactory
- * @param Settings $settingsHelper
- * @param Surcharge $surchargeService
- * @param array $paymentMethods
* @return PaymentMethodI | array
*/
public function buildPaymentMethod(
diff --git a/src/Gateway/MolliePaymentGatewayHandler.php b/src/Gateway/MolliePaymentGatewayHandler.php
index e8fcb488a..1ae392a0d 100644
--- a/src/Gateway/MolliePaymentGatewayHandler.php
+++ b/src/Gateway/MolliePaymentGatewayHandler.php
@@ -10,7 +10,6 @@
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\MollieOrderService;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\HttpResponse;
@@ -190,6 +189,8 @@ public function is_available($gateway): bool
return true;
}
+ // phpstan:ignore [wc-stub] WC()->cart is WC_Cart|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$order_total = WC()->cart ? WC()->cart->get_total('edit') : 0;
$currency = $this->getCurrencyFromOrder();
$billingCountry = $this->getBillingCountry();
@@ -422,10 +423,12 @@ public function activePaymentObject($orderId, $useCache): Payment
* @param $title
* @param null $id
*
- * @return string|void
+ * @return string
*/
public function onOrderReceivedTitle($title, $id = null)
{
+ // phpstan:ignore [wc-stub] get_the_ID() returns int|false; comparison with nullable $id triggers a false-positive
+ // @phpstan-ignore-next-line
if (is_order_received_page() && get_the_ID() === $id) {
$order = false;
$orderReceived = get_query_var('order-received');
@@ -526,9 +529,9 @@ public function onOrderReceivedTitle($title, $id = null)
/**
* @param $text
- * @param WC_Order| null $order
+ * @param WC_Order|null $order
*
- * @return string|void
+ * @return string
*/
public function onOrderReceivedText($text, $order)
{
@@ -583,6 +586,8 @@ public function getCurrencyFromOrder()
*/
public function getBillingCountry()
{
+ // phpstan:ignore [wc-stub] WC()->customer is WC_Customer|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$customerExistsAndHasCountry = WC()->customer && !empty(WC()->customer->get_billing_country());
$fallbackToShopCountry = wc_get_base_location()['country'];
$billingCountry = $customerExistsAndHasCountry ? WC()->customer->get_billing_country() : $fallbackToShopCountry;
@@ -642,6 +647,8 @@ protected function checkEnabledNorDirectDebit($gateway): bool
*/
protected function cartAmountAvailable()
{
+ // phpstan:ignore [wc-stub] WC()->cart is WC_Cart|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
return WC()->cart && WC()->cart->get_total('edit') > 0;
}
diff --git a/src/Gateway/Refund/RefundLineItemsBuilder.php b/src/Gateway/Refund/RefundLineItemsBuilder.php
index 21908786a..df79294dd 100644
--- a/src/Gateway/Refund/RefundLineItemsBuilder.php
+++ b/src/Gateway/Refund/RefundLineItemsBuilder.php
@@ -106,10 +106,9 @@ private function buildLineItem(
) {
$toRefundItemQuantity = abs((int) $toRefundItem->get_quantity());
- $toRefundItemAmount = number_format(
- abs($toRefundItem->get_total() + $toRefundItem->get_total_tax()),
- 2
- );
+ // @phpstan-ignore-next-line
+ $toRefundItemTotal = (float)$toRefundItem->get_total() + (float)$toRefundItem->get_total_tax();
+ $toRefundItemAmount = number_format(abs($toRefundItemTotal), 2);
$toRefundRemoteItemPrice = property_exists($toRefundRemoteItem->unitPrice, 'value') && $toRefundRemoteItem->unitPrice->value !== null
? $toRefundRemoteItem->unitPrice->value
: 0;
diff --git a/src/Gateway/Surcharge.php b/src/Gateway/Surcharge.php
index 61b5c2c00..9417b299f 100644
--- a/src/Gateway/Surcharge.php
+++ b/src/Gateway/Surcharge.php
@@ -288,8 +288,6 @@ protected function name_fixed_fee_percentage($paymentMethod)
if (
!$paymentMethod->getProperty(self::FIXED_FEE)
|| !$paymentMethod->getProperty(self::PERCENTAGE)
- || $paymentMethod->getProperty(self::FIXED_FEE) === ''
- || $paymentMethod->getProperty(self::PERCENTAGE) === ''
|| $paymentMethod->getProperty(self::PERCENTAGE) <= 0
|| $paymentMethod->getProperty(self::FIXED_FEE) <= 0
) {
diff --git a/src/Gateway/Voucher/MaybeDisableGateway.php b/src/Gateway/Voucher/MaybeDisableGateway.php
index 845d0f505..c896a870f 100644
--- a/src/Gateway/Voucher/MaybeDisableGateway.php
+++ b/src/Gateway/Voucher/MaybeDisableGateway.php
@@ -4,9 +4,6 @@
namespace Mollie\WooCommerce\Gateway\Voucher;
-use Inpsyde\PaymentGateway\PaymentGateway;
-use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
-use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\Voucher;
class MaybeDisableGateway
@@ -45,6 +42,8 @@ public function haveCartProductsCategories(): bool
}
$cart = WC()->cart;
+ // phpstan:ignore [wc-stub] WC()->cart is WC_Cart|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
if (!$cart) {
return false;
}
diff --git a/src/Gateway/inc/services.php b/src/Gateway/inc/services.php
index 6c21a431e..64b3f7f70 100644
--- a/src/Gateway/inc/services.php
+++ b/src/Gateway/inc/services.php
@@ -12,19 +12,20 @@
use Mollie\WooCommerce\Buttons\PayPalButton\PayPalButtonHandler;
use Mollie\WooCommerce\Buttons\PayPalButton\PayPalExpressButton;
use Mollie\WooCommerce\Gateway\DeprecatedGatewayBuilder;
+use Mollie\WooCommerce\Gateway\GatewayModule;
use Mollie\WooCommerce\Gateway\Refund\OrderItemsRefunder;
use Mollie\WooCommerce\Gateway\Refund\RefundLineItemsBuilder;
use Mollie\WooCommerce\Gateway\Refund\RefundProcessor;
use Mollie\WooCommerce\Gateway\Surcharge;
use Mollie\WooCommerce\Notice\AdminNotice;
use Mollie\WooCommerce\Payment\MollieOrderService;
-use Mollie\WooCommerce\Payment\Webhooks\WebhookHandler;
-use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
use Mollie\WooCommerce\Payment\PaymentFactory;
use Mollie\WooCommerce\Payment\PaymentProcessor;
+use Mollie\WooCommerce\Payment\Webhooks\WebhookHandler;
use Mollie\WooCommerce\PaymentMethods\Constants;
use Mollie\WooCommerce\PaymentMethods\IconFactory;
+use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\SDK\HttpResponse;
@@ -45,7 +46,7 @@
},
'gateway.paymentMethods' => static function (ContainerInterface $container): array {
$onlyAvailableMethods = $container->get('gateway.getPaymentMethodsAfterFeatureFlag');
- $allPaymentMethods = (new self())->instantiatePaymentMethods();
+ $allPaymentMethods = (new GatewayModule())->instantiatePaymentMethods();
//we want only the methods after the feature flags
return array_filter($allPaymentMethods, static function ($method, $key) use ($onlyAvailableMethods) {
return array_key_exists($key, $onlyAvailableMethods);
@@ -305,6 +306,8 @@ static function ($order_id) use ($instructionsManager, $paymentGateway, $depreca
}
// Empty cart
+ // phpstan:ignore [wc-stub] WC()->cart is WC_Cart|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
if (WC()->cart) {
WC()->cart->empty_cart();
}
@@ -393,6 +396,9 @@ static function ($filteredOption) {
];
- $paymentMethods = (new self())->instantiatePaymentMethods();
- return array_merge($services, (new self())->providePaymentMethodServices(...array_values($paymentMethods)));
+ $paymentMethods = (new GatewayModule())->instantiatePaymentMethods();
+ return array_merge(
+ $services,
+ (new GatewayModule())->providePaymentMethodServices(...array_values($paymentMethods))
+ );
};
diff --git a/src/Log/WcPsrLoggerAdapter.php b/src/Log/WcPsrLoggerAdapter.php
index 52c8f68ce..f8d233167 100644
--- a/src/Log/WcPsrLoggerAdapter.php
+++ b/src/Log/WcPsrLoggerAdapter.php
@@ -91,9 +91,7 @@ public function log($level, $message, array $context = [])
}
$context['source'] = $this->loggerSource;
- $interpolatedMessage = is_string($message)
- ? $this->interpolate($message, $this->getReplacements($context))
- : $message;
+ $interpolatedMessage = $this->interpolate((string)$message, $this->getReplacements($context));
$this->wcLogger->log($level, $interpolatedMessage, $context);
}
diff --git a/src/MerchantCapture/Capture/Type/ManualCapture.php b/src/MerchantCapture/Capture/Type/ManualCapture.php
index 59243b275..ba18961c0 100644
--- a/src/MerchantCapture/Capture/Type/ManualCapture.php
+++ b/src/MerchantCapture/Capture/Type/ManualCapture.php
@@ -5,7 +5,6 @@
namespace Mollie\WooCommerce\MerchantCapture\Capture\Type;
use Mollie\WooCommerce\MerchantCapture\Capture\Action\CapturePayment;
-use Mollie\WooCommerce\Payment\MollieOrderService;
use Psr\Container\ContainerInterface;
class ManualCapture
@@ -65,9 +64,8 @@ public function sendManualCaptureMode(array $paymentData): array
return $paymentData;
}
- public function manualCapture(\WC_Order $order)
+ public function manualCapture(\WC_Order $order): void
{
-
($this->container->get(CapturePayment::class))($order->get_id());
//give paid webhook time to arrive so that updated correctly bevor showing the order in the backend
sleep(3);
diff --git a/src/Payment/LineItems/OrderLines.php b/src/Payment/LineItems/OrderLines.php
index a436e76fc..ed8f78a10 100644
--- a/src/Payment/LineItems/OrderLines.php
+++ b/src/Payment/LineItems/OrderLines.php
@@ -16,7 +16,7 @@ class OrderLines implements LineItemProvider
/**
* Formatted order lines.
*
- * @var $order_lines
+ * @var array
*/
private $order_lines = [];
@@ -182,7 +182,7 @@ private function process_items()
}
if ($product instanceof \WC_Product && $product->get_image_id()) {
- $productImage = wp_get_attachment_image_src($product->get_image_id(), 'full');
+ $productImage = wp_get_attachment_image_src((int)$product->get_image_id(), 'full');
if (isset($productImage[0]) && wc_is_valid_url($productImage[0])) {
$mollie_order_item['imageUrl'] = $productImage[0];
}
@@ -214,7 +214,10 @@ private function process_shipping()
foreach ($shipping_methods as $shipping_method) {
$vatRate = 0;
if ($shipping_method->get_total_tax() > 0 && $shipping_method->get_total() > 0) {
- $vatRate = round($shipping_method->get_total_tax() / $shipping_method->get_total(), 4) * 100;
+ $vatRate = round(
+ (float)$shipping_method->get_total_tax() / (float)$shipping_method->get_total(),
+ 4
+ ) * 100;
}
$shipping = [
'type' => 'shipping_fee',
@@ -223,15 +226,24 @@ private function process_shipping()
'vatRate' => $vatRate,
'unitPrice' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total() + $shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total() + (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
'totalAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total() + $shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total() + (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
'vatAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
'metadata' => [
'order_item_id' => $shipping_method->get_id(),
@@ -314,18 +326,27 @@ private function process_gift_cards()
{
if (!empty($this->order->get_items('gift_card'))) {
foreach ($this->order->get_items('gift_card') as $cart_gift_card) {
+ // phpstan:ignore [wc-stub] WC gift card item's get_amount() is not declared in stubs
+ // @phpstan-ignore-next-line
+ $giftCardAmount = $cart_gift_card->get_amount();
$gift_card = [
'type' => 'gift_card',
'name' => $cart_gift_card->get_name(),
'unitPrice' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue(-$cart_gift_card->get_amount(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ -$giftCardAmount,
+ $this->currency
+ ),
],
'vatRate' => 0,
'quantity' => 1,
'totalAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue(-$cart_gift_card->get_amount(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ -$giftCardAmount,
+ $this->currency
+ ),
],
'vatAmount' => [
'currency' => $this->currency,
@@ -366,6 +387,8 @@ private function get_item_name($cart_item)
*
* @return integer $item_tax_amount Item tax amount.
*/
+ // phpstan:ignore [dead-code] private method appears unused; kept for potential future use
+ // @phpstan-ignore-next-line
private function get_item_tax_amount($cart_item)
{
return $cart_item['line_tax'];
diff --git a/src/Payment/LineItems/PaymentLines.php b/src/Payment/LineItems/PaymentLines.php
index aaecb5cf1..a5ab75ec6 100644
--- a/src/Payment/LineItems/PaymentLines.php
+++ b/src/Payment/LineItems/PaymentLines.php
@@ -17,7 +17,7 @@ class PaymentLines implements LineItemProvider
/**
* Formatted order lines.
*
- * @var $order_lines
+ * @var array
*/
private $order_lines = [];
@@ -173,7 +173,7 @@ private function process_items()
}
if ($product instanceof \WC_Product && $product->get_image_id()) {
- $productImage = wp_get_attachment_image_src($product->get_image_id(), 'full');
+ $productImage = wp_get_attachment_image_src((int)$product->get_image_id(), 'full');
if (isset($productImage[0]) && wc_is_valid_url($productImage[0])) {
$mollie_order_item['imageUrl'] = $productImage[0];
}
@@ -205,7 +205,10 @@ private function process_shipping()
foreach ($shipping_methods as $shipping_method) {
$vatRate = 0;
if ($shipping_method->get_total_tax() > 0 && $shipping_method->get_total() > 0) {
- $vatRate = round($shipping_method->get_total_tax() / $shipping_method->get_total(), 4) * 100;
+ $vatRate = round(
+ (float)$shipping_method->get_total_tax() / (float)$shipping_method->get_total(),
+ 4
+ ) * 100;
}
$shipping = [
'type' => 'shipping_fee',
@@ -214,15 +217,24 @@ private function process_shipping()
'vatRate' => $vatRate,
'unitPrice' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total() + $shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total() + (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
'totalAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total() + $shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total() + (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
'vatAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue($shipping_method->get_total_tax(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ (float)$shipping_method->get_total_tax(),
+ $this->currency
+ ),
],
];
@@ -300,18 +312,27 @@ private function process_gift_cards()
{
if (!empty($this->order->get_items('gift_card'))) {
foreach ($this->order->get_items('gift_card') as $cart_gift_card) {
+ // phpstan:ignore [wc-stub] WC gift card item's get_amount() is not declared in stubs
+ // @phpstan-ignore-next-line
+ $giftCardAmount = $cart_gift_card->get_amount();
$gift_card = [
'type' => 'gift_card',
'description' => $cart_gift_card->get_name(),
'unitPrice' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue(-$cart_gift_card->get_amount(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ -$giftCardAmount,
+ $this->currency
+ ),
],
'vatRate' => 0,
'quantity' => 1,
'totalAmount' => [
'currency' => $this->currency,
- 'value' => $this->dataHelper->formatCurrencyValue(-$cart_gift_card->get_amount(), $this->currency),
+ 'value' => $this->dataHelper->formatCurrencyValue(
+ -$giftCardAmount,
+ $this->currency
+ ),
],
'vatAmount' => [
'currency' => $this->currency,
diff --git a/src/Payment/MollieObject.php b/src/Payment/MollieObject.php
index dda1bb111..f2e6a7ad9 100644
--- a/src/Payment/MollieObject.php
+++ b/src/Payment/MollieObject.php
@@ -11,9 +11,9 @@
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
+use Psr\Log\LoggerInterface as Logger;
use WC_Order;
use WC_Payment_Gateway;
-use Psr\Log\LoggerInterface as Logger;
class MollieObject
{
@@ -47,6 +47,8 @@ class MollieObject
/**
* @var null
*/
+ // phpstan:ignore [dead-code] typed @var null; kept as a placeholder — subclasses shadow this with properly typed versions
+ // @phpstan-ignore-next-line
private $paymentMethod;
protected RequestFactory $requestFactory;
@@ -415,7 +417,7 @@ public function getActiveMolliePayment($order_id, $use_cache = true)
);
} catch (ApiException $exception) {
$this->logger->debug($exception->getMessage());
- return;
+ return null;
}
return $this->getPaymentObjectPayment(
@@ -591,8 +593,12 @@ public function addMandateIdMetaToFirstPaymentSubscriptionOrder(
$subscriptions = wcs_get_subscriptions_for_renewal_order($order);
}
foreach ($subscriptions as $subscription) {
+ // phpstan:ignore [mollie-stub] Mollie Payment object exposes id and mandateId as dynamic stdClass properties not covered by type definitions
+ // @phpstan-ignore-next-line
$subscription->update_meta_data('_mollie_payment_id', $payment->id);
$subscription->update_meta_data('_mollie_mandate_id', $payment->mandateId);
+ // phpstan:ignore [mollie-stub] Mollie Payment object exposes method as a dynamic property; also set_payment_method() may not be typed on WC_Subscription stubs
+ // @phpstan-ignore-next-line
$subscription->set_payment_method('mollie_wc_gateway_' . $payment->method);
$subscription->save();
$subscriptionParentOrder = $subscription->get_parent();
@@ -722,6 +728,8 @@ function_exists('wcs_order_contains_renewal')
!empty($emails) && !empty($orderId)
&& !empty($emails['WC_Email_Failed_Order'])
) {
+ // phpstan:ignore [wc-stub] WC_Email subclass accessed via mailer array; trigger() not typed on WC_Email base class in stubs
+ // @phpstan-ignore-next-line
$emails['WC_Email_Failed_Order']->trigger($orderId);
}
} elseif (mollieWooCommerceIsMollieGateway($gateway->id)) {
diff --git a/src/Payment/MollieOrder.php b/src/Payment/MollieOrder.php
index ba955b142..b107e399f 100644
--- a/src/Payment/MollieOrder.php
+++ b/src/Payment/MollieOrder.php
@@ -5,21 +5,17 @@
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\Payment;
use Mollie\Api\Resources\Refund;
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 UnexpectedValueException;
use WC_Order;
use WP_Error;
@@ -226,11 +222,14 @@ public function refund(WC_Order $order, $orderId, $paymentObject, $amount = null
$totals = 0;
foreach ($items as $itemId => $itemData) {
- $totals += $itemData->get_total() + $itemData->get_total_tax();
+ // @phpstan-ignore-next-line
+ $totals += (float)$itemData->get_total() + (float)$itemData->get_total_tax();
}
$totals = number_format(abs($totals), 2); // WooCommerce - sum of all refund items
- $checkAmount = $amount ? number_format((float)$amount, 2) : 0; // WooCommerce - refund amount
+ // phpstan:ignore [wc-stub] $amount arrives via WC refund API as string|null; (float) cast already handles it but stubs type it inconsistently
+ // @phpstan-ignore-next-line
+ $checkAmount = number_format((float)($amount ?? 0), 2); // WooCommerce - refund amount
if ($checkAmount !== $totals) {
$errorMessage = _x('The sum of refunds for all order lines is not identical to the refund amount, so this refund will be processed as a payment amount refund, not an order line refund.', 'Order note error', 'mollie-payments-for-woocommerce');
@@ -272,8 +271,6 @@ public function refund(WC_Order $order, $orderId, $paymentObject, $amount = null
$this->logger->debug(__METHOD__ . ' - ' . $exceptionMessage);
return new WP_Error(1, $exceptionMessage);
}
-
- return false;
}
/**
@@ -318,6 +315,8 @@ public function refund_order_items($order, $orderId, $amount, $items, $paymentOb
if ($originalOrderItemId === $line->metadata->order_item_id) {
// Calculate the total refund amount for one order line
+ // phpstan:ignore [mollie-stub] Mollie order line exposes unitPrice->value as a dynamic stdClass property not covered by type definitions
+ // @phpstan-ignore-next-line
$lineTotalRefundAmount = abs($item->get_quantity()) * $line->unitPrice->value;
// Mollie doesn't allow a partial refund of the full amount or quantity of at least one order line, so when merchants try that, warn them and block the process
@@ -325,6 +324,8 @@ public function refund_order_items($order, $orderId, $amount, $items, $paymentOb
$noteMessage = sprintf(
"Mollie doesn't allow a partial refund of the full amount or quantity of at least one order line. Use 'Refund amount' instead. The WooCommerce order item ID is %s, Mollie order line ID is %s.",
$originalOrderItemId,
+ // phpstan:ignore [mollie-stub] Mollie order line exposes id as a dynamic property not covered by type definitions
+ // @phpstan-ignore-next-line
$line->id
);
@@ -386,7 +387,7 @@ public function refund_amount($order, $amount, $paymentObject, $reason)
throw new Exception(esc_html(sprintf("%s", $noteMessage)));
}
- if ($paymentObject->isPaid() || $paymentObject->isShipping() || $paymentObject->isCompleted()) {
+ if ($paymentObject->isPaid() || $paymentObject->isCompleted()) {
$refund = $this->apiHelper->getApiClient($apiKey)->payments->refund($paymentObjectPayment, [
'amount' => [
'currency' => $this->dataHelper->getOrderCurrency($order),
@@ -470,13 +471,15 @@ protected function processOrderItemsRefund(
// Get the Mollie order
$mollieOrder = $this->apiHelper->getApiClient($apiKey)->orders->get($paymentObject->id);
- $itemTotalAmount = abs(number_format($item->get_total() + $item->get_total_tax(), 2));
+ $itemTotalAmount = abs((float)number_format($item->get_total() + $item->get_total_tax(), 2));
// Prepare the order line to update
if (!empty($line->discountAmount)) {
$lines = [
'lines' => [
[
+ // phpstan:ignore [mollie-stub] Mollie order line exposes id as a dynamic property not covered by type definitions
+ // @phpstan-ignore-next-line
'id' => $line->id,
'quantity' => abs($item->get_quantity()),
'amount' => [
@@ -502,6 +505,8 @@ protected function processOrderItemsRefund(
];
}
+ $refund = null;
+ $noteMessage = '';
if ($line->status === 'created' || $line->status === 'authorized') {
// Returns null if successful.
$refund = $mollieOrder->cancelLines($lines);
@@ -563,7 +568,7 @@ protected function processOrderItemsRefund(
$this->pluginId . '_refund_created',
[$refund, $order],
'5.3.1',
- self::ACTION_AFTER_REFUND_PAYMENT_CREATED
+ MolliePayment::ACTION_AFTER_REFUND_PAYMENT_CREATED
);
$order->add_order_note($noteMessage);
diff --git a/src/Payment/MollieOrderService.php b/src/Payment/MollieOrderService.php
index 555380c77..1546bd9b9 100644
--- a/src/Payment/MollieOrderService.php
+++ b/src/Payment/MollieOrderService.php
@@ -36,6 +36,8 @@ class MollieOrderService
protected $data;
protected $pluginId;
private ContainerInterface $container;
+ // phpstan:ignore [dead-code] declared but never assigned after construction; likely a concurrency guard placeholder
+ // @phpstan-ignore-next-line
private string $currentLockValue;
private WebhookHandler $webhookHandler;
@@ -584,6 +586,8 @@ protected function processChargebacks(WC_Order $order, $payment)
!empty($emails) && !empty($orderId)
&& !empty($emails['WC_Email_Failed_Order'])
) {
+ // phpstan:ignore [wc-stub] WC_Email subclass accessed via mailer array; trigger() not typed on WC_Email base class in stubs
+ // @phpstan-ignore-next-line
$emails['WC_Email_Failed_Order']->trigger($orderId);
}
diff --git a/src/Payment/MolliePayment.php b/src/Payment/MolliePayment.php
index f5641c1fd..e2f91ded7 100644
--- a/src/Payment/MolliePayment.php
+++ b/src/Payment/MolliePayment.php
@@ -4,20 +4,15 @@
namespace Mollie\WooCommerce\Payment;
-use Inpsyde\PaymentGateway\PaymentGateway;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Payment;
use Mollie\Api\Resources\Refund;
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_Subscriptions_Manager;
use WP_Error;
class MolliePayment extends MollieObject
@@ -74,9 +69,6 @@ public function getPaymentRequestData($order, $customerId)
return $this->requestFactory->createRequest('payment', $order, $customerId);
}
- /**
- * @return void
- */
public function setActiveMolliePayment($orderId)
{
self::$paymentId = $this->getMolliePaymentIdFromPaymentObject();
@@ -87,6 +79,7 @@ public function setActiveMolliePayment($orderId)
self::$order->save();
parent::setActiveMolliePayment($orderId);
+ return $this;
}
public function getMolliePaymentIdFromPaymentObject()
diff --git a/src/Payment/MollieSubscription.php b/src/Payment/MollieSubscription.php
index db787150f..1807603ea 100644
--- a/src/Payment/MollieSubscription.php
+++ b/src/Payment/MollieSubscription.php
@@ -5,7 +5,7 @@
use Mollie\Api\Types\SequenceType;
use Mollie\WooCommerce\Payment\Request\Middleware\MiddlewareHandler;
use Mollie\WooCommerce\Payment\Request\Middleware\PaymentDescriptionMiddleware;
-use Mollie\WooCommerce\PaymentMethods\AbstractPaymentMethod;
+use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Subscription\MollieSubscriptionGatewayHandler;
use Psr\Log\LoggerInterface as Logger;
@@ -13,18 +13,25 @@
class MollieSubscription extends MollieObject
{
protected $pluginId;
- /**
- * @var mixed
- */
- private AbstractPaymentMethod $paymentMethod;
+ // phpstan:ignore [dead-code] injected via constructor but never read in this class; MollieObject subclasses access it through other paths
+ // @phpstan-ignore-next-line
+ private PaymentMethodI $paymentMethod;
protected MiddlewareHandler $middleware;
/**
* Molliesubscription constructor.
*
*/
- public function __construct($pluginId, Api $apiHelper, $settingsHelper, $dataHelper, Logger $logger, AbstractPaymentMethod $paymentMethod, $middlewareHandler)
- {
+ public function __construct(
+ $pluginId,
+ Api $apiHelper,
+ $settingsHelper,
+ $dataHelper,
+ Logger $logger,
+ PaymentMethodI $paymentMethod,
+ $middlewareHandler
+ ) {
+
$this->pluginId = $pluginId;
$this->apiHelper = $apiHelper;
$this->settingsHelper = $settingsHelper;
diff --git a/src/Payment/PaymentModule.php b/src/Payment/PaymentModule.php
index 82d765d17..3e7b8f74e 100644
--- a/src/Payment/PaymentModule.php
+++ b/src/Payment/PaymentModule.php
@@ -114,7 +114,7 @@ function () use ($paymentMethods) {
$this->handleExpiryDateCancelation($paymentMethods);
},
10,
- 2
+ 0
);
add_action(
OrderItemsRefunder::ACTION_AFTER_REFUND_ORDER_ITEMS,
@@ -165,7 +165,7 @@ public function cancelOrderOnExpiryDate()
continue;
}
- $heldDuration = isset($gatewaySettings) && isset($gatewaySettings['order_dueDate']) ? $gatewaySettings['order_dueDate'] : 0;
+ $heldDuration = isset($gatewaySettings['order_dueDate']) ? $gatewaySettings['order_dueDate'] : 0;
if ($heldDuration < 1) {
continue;
@@ -530,7 +530,7 @@ public function handleExpiryDateCancelation($paymentMethods)
'mollie_woocommerce_cancel_unpaid_orders',
[$this, 'cancelOrderOnExpiryDate'],
11,
- 2
+ 0
);
}
}
diff --git a/src/Payment/PaymentProcessor.php b/src/Payment/PaymentProcessor.php
index 4e38b5d28..a4fbc42be 100644
--- a/src/Payment/PaymentProcessor.php
+++ b/src/Payment/PaymentProcessor.php
@@ -9,12 +9,12 @@
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Payment;
use Mollie\WooCommerce\Notice\NoticeInterface;
+use Mollie\WooCommerce\PaymentMethods\Constants;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Settings\Settings;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
-use Mollie\WooCommerce\PaymentMethods\Constants;
use Psr\Log\LoggerInterface as Logger;
use WC_Order;
@@ -24,7 +24,7 @@ class PaymentProcessor implements PaymentProcessorInterface
public const PAYMENT_METHOD_TYPE_PAYMENT = 'payment';
/**
- * @var
+ * @var mixed
*/
protected $deprecatedGatewayHelper;
/**
diff --git a/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php b/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php
index 12b686c8c..bbf7a9f64 100644
--- a/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php
+++ b/src/Payment/Request/Middleware/AddSequenceTypeForSubscriptionsMiddleware.php
@@ -7,6 +7,7 @@
use Mollie\Api\Types\SequenceType;
use Mollie\WooCommerce\Shared\Data;
use WC_Order;
+use WC_Payment_Gateway;
/**
* Middleware to add sequence type for subscription payments.
@@ -47,7 +48,7 @@ public function __construct($dataHelper, $pluginId)
public function __invoke(array $requestData, WC_Order $order, $context, callable $next): array
{
$gateway = wc_get_payment_gateway_by_order($order);
- if ($gateway) {
+ if ($gateway instanceof WC_Payment_Gateway) {
$requestData = $this->addSequenceTypeForSubscriptionsFirstPayments($order->get_id(), $gateway, $requestData, $context);
}
return $next($requestData, $order, $context);
diff --git a/src/Payment/Request/Middleware/CustomerBirthdateMiddleware.php b/src/Payment/Request/Middleware/CustomerBirthdateMiddleware.php
index a74f37c04..f7cc3424f 100644
--- a/src/Payment/Request/Middleware/CustomerBirthdateMiddleware.php
+++ b/src/Payment/Request/Middleware/CustomerBirthdateMiddleware.php
@@ -2,8 +2,8 @@
namespace Mollie\WooCommerce\Payment\Request\Middleware;
-use WC_Order;
use Mollie\WooCommerce\Shared\FieldConstants;
+use WC_Order;
/**
* Middleware to handle customer birthdate in the request.
@@ -13,6 +13,8 @@ class CustomerBirthdateMiddleware implements RequestMiddlewareInterface
/**
* @var array The payment methods.
*/
+ // phpstan:ignore [dead-code] injected via constructor but never read; likely needed once birthdate validation checks which methods require it
+ // @phpstan-ignore-next-line
private array $paymentMethods;
/**
@@ -37,7 +39,7 @@ public function __construct(array $paymentMethods)
public function __invoke(array $requestData, WC_Order $order, $context, $next): array
{
$birthdatePostedFieldName = $this->getBirthdatePostedFieldName($order);
- if (!$birthdatePostedFieldName || $birthdatePostedFieldName === '' || !is_string($birthdatePostedFieldName)) {
+ if (!$birthdatePostedFieldName) {
return $next($requestData, $order, $context);
}
$format = "Y-m-d";
diff --git a/src/Payment/Webhooks/WebhookHandler.php b/src/Payment/Webhooks/WebhookHandler.php
index 7ff54f6e6..3ae95bd6a 100644
--- a/src/Payment/Webhooks/WebhookHandler.php
+++ b/src/Payment/Webhooks/WebhookHandler.php
@@ -270,6 +270,7 @@ public function onWebhookCanceled(
$mollieObject->setCancelledMolliePaymentId($orderId, $payment->id);
$orderStatusCancelledPayments = $this->settingsHelper->getOrderStatusCancelledPayments();
+ $newOrderStatus = SharedDataDictionary::STATUS_PENDING;
if ($orderStatusCancelledPayments === 'pending' || $orderStatusCancelledPayments === null) {
$newOrderStatus = SharedDataDictionary::STATUS_PENDING;
diff --git a/src/PaymentMethods/AbstractPaymentMethod.php b/src/PaymentMethods/AbstractPaymentMethod.php
index f6f5071c5..effe1251c 100644
--- a/src/PaymentMethods/AbstractPaymentMethod.php
+++ b/src/PaymentMethods/AbstractPaymentMethod.php
@@ -57,6 +57,18 @@ abstract class AbstractPaymentMethod implements PaymentMethodI, PaymentMethodDef
*/
protected bool $translationsInitialized = false;
+ abstract protected function getConfig(): array;
+
+ abstract public function getFormFields(array $generalFormFields): array;
+
+ public function filtersOnBuild(): void
+ {
+ }
+
+ public function debugGiftcardDetails($payment, \WC_Order $order): void
+ {
+ }
+
public function __construct()
{
$this->config = $this->getConfig();
@@ -477,6 +489,8 @@ public function blocksData(ContainerInterface $container): array
], $iconProvider->provideIcons())
: [];
+ // phpstan:ignore [wc-stub] WC()->customer is WC_Customer|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$billingCountry = WC()->customer ? WC()->customer->get_billing_country() : '';
$allowedCountries = $this->getProperty('allowed_countries');
diff --git a/src/PaymentMethods/Banktransfer.php b/src/PaymentMethods/Banktransfer.php
index 5f21cc38b..be376b5e1 100644
--- a/src/PaymentMethods/Banktransfer.php
+++ b/src/PaymentMethods/Banktransfer.php
@@ -90,7 +90,7 @@ public function getFormFields($generalFormFields): array
return array_merge($generalFormFields, $paymentMethodFormFieds);
}
- public function filtersOnBuild()
+ public function filtersOnBuild(): void
{
add_filter('woocommerce_mollie_wc_gateway_' . $this->getProperty('id') . 'payment_args', function (array $args, \WC_Order $order): array {
return $this->addPaymentArguments($args, $order);
diff --git a/src/PaymentMethods/Billie.php b/src/PaymentMethods/Billie.php
index 18b1e85f3..a2e5072d3 100644
--- a/src/PaymentMethods/Billie.php
+++ b/src/PaymentMethods/Billie.php
@@ -65,7 +65,7 @@ public function initializeTranslations(): void
* Add filters and actions for the Billie payment method.
* This will be added during constructor
*/
- public function filtersOnBuild()
+ public function filtersOnBuild(): void
{
add_filter(
'woocommerce_after_checkout_validation',
@@ -73,7 +73,7 @@ public function filtersOnBuild()
11,
2
);
- add_action(
+ add_filter(
'woocommerce_checkout_posted_data',
[$this, 'switchFields'],
11
diff --git a/src/PaymentMethods/Giftcard.php b/src/PaymentMethods/Giftcard.php
index bced341f4..8d1490522 100644
--- a/src/PaymentMethods/Giftcard.php
+++ b/src/PaymentMethods/Giftcard.php
@@ -18,7 +18,7 @@ class Giftcard extends AbstractPaymentMethod implements PaymentMethodI
public function debugGiftcardDetails(
$payment,
\WC_Order $order
- ) {
+ ): void {
$details = $payment->details;
if (!$details) {
diff --git a/src/PaymentMethods/Paybybank.php b/src/PaymentMethods/Paybybank.php
index 2f9a11f14..bd6a777ec 100644
--- a/src/PaymentMethods/Paybybank.php
+++ b/src/PaymentMethods/Paybybank.php
@@ -88,7 +88,7 @@ public function getFormFields(array $generalFormFields): array
return array_merge($generalFormFields, $paymentMethodFormFields);
}
- public function filtersOnBuild()
+ public function filtersOnBuild(): void
{
add_filter('woocommerce_mollie_wc_gateway_' . $this->getProperty('id') . 'payment_args', function (array $args, \WC_Order $order): array {
return $this->addPaymentArguments($args, $order);
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php b/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php
index e42ae8e03..f70c2a76f 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/AbstractPaymentFieldsRenderer.php
@@ -11,9 +11,6 @@ class AbstractPaymentFieldsRenderer implements PaymentFieldsRendererInterface
protected MolliePaymentGatewayHandler $deprecatedHelperGateway;
protected string $gatewayDescription;
- /**
- * @var mixed
- */
protected Data $dataHelper;
public function __construct($deprecatedHelperGateway, $gateway, $dataHelper)
diff --git a/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php b/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
index 26f2638b6..6586650b2 100644
--- a/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
+++ b/src/PaymentMethods/PaymentFieldsStrategies/IssuersDropdownBehavior.php
@@ -80,8 +80,7 @@ public function issuersDropdownMarkup(
}
/**
- * @param $description
- * @param string $html
+ * @param $gateway
* @param $issuers
* @param $selectedIssuer
*
diff --git a/src/PaymentMethods/PaymentMethodI.php b/src/PaymentMethods/PaymentMethodI.php
index a6bf5b514..a44e3ee43 100644
--- a/src/PaymentMethods/PaymentMethodI.php
+++ b/src/PaymentMethods/PaymentMethodI.php
@@ -12,4 +12,18 @@ public function getProperty(string $propertyName);
public function hasProperty(string $propertyName): bool;
public function blocksData(ContainerInterface $container): array;
+
+ public function shouldDisplayIcon(): bool;
+
+ public function id(): string;
+
+ public function initializeTranslations(): void;
+
+ public function updateSettingsWithDefaults(ContainerInterface $container): array;
+
+ public function getInitialOrderStatus(): string;
+
+ public function filtersOnBuild(): void;
+
+ public function debugGiftcardDetails($payment, \WC_Order $order): void;
}
diff --git a/src/PaymentMethods/PaymentRedirectStrategies/DefaultRedirectStrategy.php b/src/PaymentMethods/PaymentRedirectStrategies/DefaultRedirectStrategy.php
index 1efbdc90e..ec414d22f 100644
--- a/src/PaymentMethods/PaymentRedirectStrategies/DefaultRedirectStrategy.php
+++ b/src/PaymentMethods/PaymentRedirectStrategies/DefaultRedirectStrategy.php
@@ -4,8 +4,8 @@
namespace Mollie\WooCommerce\PaymentMethods\PaymentRedirectStrategies;
-use Mollie\WooCommerce\Payment\MollieOrder;
-use Mollie\WooCommerce\Payment\MolliePayment;
+use Mollie\Api\Resources\Order as MollieApiOrder;
+use Mollie\Api\Resources\Payment as MollieApiPayment;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use WC_Order;
@@ -15,11 +15,11 @@ class DefaultRedirectStrategy implements PaymentRedirectStrategyI
* Redirect location after successfully completing process_payment
*
* @param WC_Order $order
- * @param MollieOrder|MolliePayment $payment_object
+ * @param MollieApiOrder|MollieApiPayment $paymentObject
*
*/
public function execute(PaymentMethodI $paymentMethod, $order, $paymentObject, string $redirectUrl)
{
- return $paymentObject->getCheckoutUrl();
+ return $paymentObject->getCheckoutUrl();
}
}
diff --git a/src/PaymentMethods/Voucher.php b/src/PaymentMethods/Voucher.php
index b43ad714a..40a7c6dde 100644
--- a/src/PaymentMethods/Voucher.php
+++ b/src/PaymentMethods/Voucher.php
@@ -4,9 +4,6 @@
namespace Mollie\WooCommerce\PaymentMethods;
-use Mollie\WooCommerce\Payment\MollieOrder;
-use Mollie\WooCommerce\Payment\MolliePayment;
-
class Voucher extends AbstractPaymentMethod implements PaymentMethodI
{
/**
@@ -54,9 +51,8 @@ protected function getConfig(): array
];
}
- public function filtersOnBuild()
+ public function filtersOnBuild(): void
{
-
add_action('mollie-payments-for-woocommerce_after_webhook_action', [$this, 'addPaymentDetailsOrderNote'], 10, 2);
}
@@ -93,6 +89,8 @@ public function addPaymentDetailsOrderNote($payment, \WC_Order $order): void
if (isset($details->remainderAmount)) {
$remainder = sprintf(
__('%1$s: %2$s %3$s
', 'mollie-payments-for-woocommerce'),
+ // phpstan:ignore [mollie-stub] Mollie payment detail object exposes remainderMethod as a dynamic property not covered by type definitions
+ // @phpstan-ignore-next-line
$details->remainderMethod,
$details->remainderAmount->value,
$details->remainderAmount->currency
diff --git a/src/SDK/Api.php b/src/SDK/Api.php
index 861aee416..47d767cce 100644
--- a/src/SDK/Api.php
+++ b/src/SDK/Api.php
@@ -10,9 +10,9 @@
class Api
{
/**
- * @var \Mollie\Api\MollieApiClient
+ * @var \Mollie\Api\MollieApiClient|null
*/
- protected static $api_client;
+ protected static ?MollieApiClient $api_client = null;
/**
* @var string
*/
@@ -29,7 +29,7 @@ public function __construct(string $pluginVersion, string $pluginId)
}
/**
- * @param bool $test_mode
+ * @param string $apiKey
* @param bool $needToUpdateApiKey If the apiKey was updated discard the old instance, and create a new one with the new key.
*
* @return \Mollie\Api\MollieApiClient
@@ -59,7 +59,7 @@ public function getApiClient($apiKey, $needToUpdateApiKey = false)
);
}
- if (empty(self::$api_client) || $needToUpdateApiKey) {
+ if (self::$api_client === null || $needToUpdateApiKey) {
$client = new MollieApiClient(null, new WordPressHttpAdapterPicker());
$client->setApiKey($apiKey);
$client->setApiEndpoint($this->getApiEndpoint());
diff --git a/src/SDK/WordPressHttpAdapter.php b/src/SDK/WordPressHttpAdapter.php
index 53aa5825d..6985d76c4 100644
--- a/src/SDK/WordPressHttpAdapter.php
+++ b/src/SDK/WordPressHttpAdapter.php
@@ -5,7 +5,6 @@
namespace Mollie\WooCommerce\SDK;
use Mollie\Api\Exceptions\ApiException;
-use Mollie\Api\Exceptions\CurlConnectTimeoutException;
use Mollie\Api\HttpAdapter\MollieHttpAdapterInterface;
class WordPressHttpAdapter implements MollieHttpAdapterInterface
@@ -43,7 +42,7 @@ public function send($httpMethod, $url, $headers, $httpBody)
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
- $message = $response->get_error_message() ?? 'Unknown error';
+ $message = $response->get_error_message();
$code = is_int($response->get_error_code()) ? $response->get_error_code() : 0;
// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped
throw new ApiException(esc_html($message), $code);
@@ -99,9 +98,7 @@ protected function parseResponse($response)
$message .= ". Documentation: {$body->_links->documentation->href}";
}
- if ($httpBody) {
- $message .= ". Request body: {$httpBody}";
- }
+ $message .= ". Request body: {$httpBody}";
// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped
throw new ApiException(esc_html($message), $statusCode, esc_html($field));
// phpcs:enable WordPress.Security.EscapeOutput.ExceptionNotEscaped
diff --git a/src/SDK/WordPressHttpAdapterPicker.php b/src/SDK/WordPressHttpAdapterPicker.php
index 20683c55d..438a52861 100644
--- a/src/SDK/WordPressHttpAdapterPicker.php
+++ b/src/SDK/WordPressHttpAdapterPicker.php
@@ -9,7 +9,8 @@
class WordPressHttpAdapterPicker implements MollieHttpAdapterPickerInterface
{
/**
- * @return \GuzzleHttp\ClientInterface|\Mollie\Api\HttpAdapter\MollieHttpAdapterInterface
+ * @param mixed $httpClient
+ * @return \Mollie\Api\HttpAdapter\MollieHttpAdapterInterface
*/
public function pickHttpAdapter($httpClient)
{
diff --git a/src/Settings/General/MultiCountrySettingsField.php b/src/Settings/General/MultiCountrySettingsField.php
index d919e0b79..fcf9b40e3 100644
--- a/src/Settings/General/MultiCountrySettingsField.php
+++ b/src/Settings/General/MultiCountrySettingsField.php
@@ -28,6 +28,8 @@ public function multiSelectCountry($paymentMethod)
$gatewayId = $paymentMethod->getProperty('id');
$id = 'woocommerce_mollie_wc_gateway_' . $gatewayId . '_allowed_countries';
$title = __('Sell to specific countries', 'mollie-payments-for-woocommerce');
+ // phpstan:ignore [wc-stub] WC()->countries is WC_Countries|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$countries = WC()->countries->countries;
asort($countries);
ob_start();
diff --git a/src/Settings/Page/Section/PaymentMethods.php b/src/Settings/Page/Section/PaymentMethods.php
index bdf1cbba8..ecf46567d 100644
--- a/src/Settings/Page/Section/PaymentMethods.php
+++ b/src/Settings/Page/Section/PaymentMethods.php
@@ -54,7 +54,7 @@ public function renderGateways(): string
$activatedGateways = '';
$deactivatedGateways = '';
- /** @var AbstractPaymentMethod $paymentMethod */
+ /** @var AbstractPaymentMethod[] $paymentMethods */
$paymentMethods = $this->container->get('gateway.paymentMethods');
$enabledMethods = $this->container->get('gateway.paymentMethodsEnabledAtMollie');
if (!in_array(Constants::DIRECTDEBIT, $enabledMethods, true)) {
@@ -200,7 +200,7 @@ protected function paymentGatewayButton(AbstractPaymentMethod $paymentMethod, $e
'enabled',
'mollie-payments-for-woocommerce'
)) . '';
- } elseif ($enabledInMollie && !$enabledInWoo) {
+ } elseif (!$enabledInWoo) {
$messageOrLink = '' . esc_html(__(
'disabled',
'mollie-payments-for-woocommerce'
diff --git a/src/Settings/Settings.php b/src/Settings/Settings.php
index 417413015..8928751b6 100644
--- a/src/Settings/Settings.php
+++ b/src/Settings/Settings.php
@@ -169,13 +169,13 @@ public function isOrderApiSetting()
return !$orderApiSetting || is_string($orderApiSetting) && trim($orderApiSetting) === PaymentProcessor::PAYMENT_METHOD_TYPE_ORDER;
}
/**
- * @param bool $overrideTestMode
+ * @param bool|null $overrideTestMode Pass null to use the current test mode setting.
*
* @return false|string
*/
- public function getApiKey($overrideTestMode = 2)
+ public function getApiKey(?bool $overrideTestMode = null)
{
- $isTestModeEnabled = $overrideTestMode === 2 ? $this->isTestModeEnabled() : $overrideTestMode;
+ $isTestModeEnabled = $overrideTestMode === null ? $this->isTestModeEnabled() : $overrideTestMode;
$settingId = $isTestModeEnabled ? 'test_api_key' : 'live_api_key';
$apiKeyId = $this->getSettingId($settingId);
$apiKey = get_option($apiKeyId);
@@ -418,7 +418,15 @@ public function getSettingId($setting)
$max_option_name_length = 191;
if ($setting_id_length > $max_option_name_length) {
- trigger_error(sprintf('Setting id %s (%s) to long for database column wp_options.option_name which is varchar(%s).', esc_html($setting_id), esc_html($setting_id_length), esc_html($max_option_name_length)), E_USER_WARNING);
+ trigger_error(
+ sprintf(
+ 'Setting id %s (%s) to long for database column wp_options.option_name which is varchar(%s).',
+ esc_html($setting_id),
+ esc_html((string)$setting_id_length),
+ esc_html((string)$max_option_name_length)
+ ),
+ E_USER_WARNING
+ );
}
return $setting_id;
@@ -541,7 +549,7 @@ protected function updateGatewaySettings($gateway)
* If we are calling this the api key has been updated, we need a new api object
* to retrieve a new profile id
*
- * @return CurrentProfile
+ * @return \Mollie\Api\Resources\CurrentProfile
* @throws ApiException
*/
protected function mollieWooCommerceMerchantProfile()
@@ -575,7 +583,7 @@ public function mollieWooCommerceMerchantProfileId()
if (!$merchantProfileId) {
try {
$merchantProfile = $this->mollieWooCommerceMerchantProfile();
- $merchantProfileId = isset($merchantProfile->id) ? $merchantProfile->id : '';
+ $merchantProfileId = $merchantProfile->id;
} catch (ApiException $exception) {
$merchantProfileId = '';
}
diff --git a/src/Settings/SettingsModule.php b/src/Settings/SettingsModule.php
index 3c1f3a1b0..a73d08536 100644
--- a/src/Settings/SettingsModule.php
+++ b/src/Settings/SettingsModule.php
@@ -6,16 +6,15 @@
namespace Mollie\WooCommerce\Settings;
+use Inpsyde\Modularity\Module\ExecutableModule;
+use Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
+use Inpsyde\Modularity\Module\ServiceModule;
use Mollie\WooCommerce\Notice\AdminNotice;
-use Mollie\WooCommerce\PaymentMethods\Constants;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Settings\Webhooks\WebhookTestService;
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\Status;
use Mollie\WooCommerce\Uninstall\CleanDb;
-use Inpsyde\Modularity\Module\ExecutableModule;
-use Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
-use Inpsyde\Modularity\Module\ServiceModule;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface as Logger;
@@ -178,7 +177,7 @@ function () use ($optionName, $defaultAdvancedOptions, $defaultComponentsOptions
$this->maybeSaveDefaultSettings('mollie_components_', $testedOption, $defaultComponentsOptions);
},
10,
- 2
+ 0
);
$this->isTestNoticePrinted = false;
add_action('woocommerce_settings_saved', function () {
diff --git a/src/Shared/Data.php b/src/Shared/Data.php
index 4387c30de..0c9290dbf 100644
--- a/src/Shared/Data.php
+++ b/src/Shared/Data.php
@@ -7,11 +7,9 @@
use Exception;
use InvalidArgumentException;
use Mollie\Api\Resources\Method;
-use Mollie\WooCommerce\Buttons\ApplePayButton\DataToAppleButtonScripts;
use Mollie\WooCommerce\SDK\Api;
use Mollie\WooCommerce\Settings\Settings;
use Psr\Log\LoggerInterface as Logger;
-use Psr\Log\LogLevel;
use WC_Customer;
use WC_Order;
@@ -111,11 +109,11 @@ public function isTestModeEnabled(): bool
}
/**
- * @param bool $overrideTestMode
+ * @param bool|null $overrideTestMode Pass null to use the current test mode setting.
*
* @return false|string
*/
- public function getApiKey($overrideTestMode = 2)
+ public function getApiKey(?bool $overrideTestMode = null)
{
return $this->settingsHelper->getApiKey($overrideTestMode);
}
@@ -160,7 +158,16 @@ public function getTransientId($transient)
$max_option_name_length = 191;
if ($option_name_length > $max_option_name_length) {
- trigger_error(sprintf('Transient id %s is to long. Option name %s (%s) will be to long for database column wp_options.option_name which is varchar(%s).', esc_html($transient_id), esc_html($option_name), esc_html($option_name_length), esc_html($max_option_name_length)), E_USER_WARNING);
+ trigger_error(
+ sprintf(
+ 'Transient id %s is to long. Option name %s (%s) will be to long for database column wp_options.option_name which is varchar(%s).',
+ esc_html($transient_id),
+ esc_html($option_name),
+ esc_html((string)$option_name_length),
+ esc_html((string)$max_option_name_length)
+ ),
+ E_USER_WARNING
+ );
}
return $transient_id;
@@ -212,9 +219,13 @@ public function wooCommerceFiltersForCheckout(): array
{
$cart = WC()->cart;
+ // phpstan:ignore [wc-stub] WC()->cart is WC_Cart|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$cartTotal = $cart ? $cart->get_total('edit') : 0;
$currency = get_woocommerce_currency();
+ // phpstan:ignore [wc-stub] WC()->customer is WC_Customer|null at runtime; WooCommerce stubs declare it non-nullable
+ // @phpstan-ignore-next-line
$customerExistsAndHasCountry = WC()->customer && !empty(WC()->customer->get_billing_country());
$fallbackToShopCountry = wc_get_base_location()['country'];
$billingCountry = $customerExistsAndHasCountry ? WC()->customer->get_billing_country() : $fallbackToShopCountry;
@@ -324,7 +335,7 @@ public function getRegularPaymentMethods($apiKey, $testMode = false, $useCache =
$methods = $this->getAllAvailablePaymentMethods($useCache);
// We cannot access allActive for all methods so we filter them out here
$filtered_methods = array_filter($methods, static function ($method) use ($testMode) {
- if ($testMode === "live") {
+ if (!$testMode) {
return $method['status'] === "activated";
} else {
return in_array($method['status'], ["activated", "pending-review"]);
@@ -409,7 +420,6 @@ public function getApiPaymentMethods($useCache = true, $filters = [])
}
/**
- * @param bool $testMode
* @param $method
*
* @return mixed|\Mollie\Api\Resources\Method|null
@@ -550,8 +560,8 @@ public function setUserMollieCustomerIdAtSubscription($orderId, $customerId)
}
/**
- * @param int $userId
- * @param bool $testMode
+ * @param int $userId
+ * @param string $apiKey
* @return null|string
*/
public function getUserMollieCustomerId($userId, $apiKey)
@@ -601,7 +611,7 @@ public function getUserMollieCustomerId($userId, $apiKey)
// Get the best name for use as Mollie Customer name
$user_full_name = $userdata->first_name . ' ' . $userdata->last_name;
- if (strlen(trim($user_full_name)) === null) {
+ if (strlen(trim($user_full_name)) === 0) {
$user_full_name = $userdata->display_name;
}
diff --git a/src/Shared/GatewaySurchargeHandler.php b/src/Shared/GatewaySurchargeHandler.php
index 8a408de44..91a5ef467 100644
--- a/src/Shared/GatewaySurchargeHandler.php
+++ b/src/Shared/GatewaySurchargeHandler.php
@@ -120,7 +120,6 @@ public function updateSurchargeOrderPay()
'newTotal' => $order->get_total(),
];
wp_send_json_success($data);
- return;
}
$amount = $this->surcharge->calculateFeeAmountOrder($order, $gatewaySettings);
diff --git a/src/Subscription/MollieSepaRecurringGatewayHandler.php b/src/Subscription/MollieSepaRecurringGatewayHandler.php
index 04905a9f5..07c78b611 100644
--- a/src/Subscription/MollieSepaRecurringGatewayHandler.php
+++ b/src/Subscription/MollieSepaRecurringGatewayHandler.php
@@ -9,12 +9,10 @@
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Resources\Payment;
use Mollie\Api\Types\SequenceType;
-use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Payment\MollieObject;
use Mollie\WooCommerce\Payment\MollieOrderService;
use Mollie\WooCommerce\Payment\PaymentFactory;
-use Mollie\WooCommerce\Payment\PaymentProcessor;
use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
@@ -67,7 +65,6 @@ public function __construct(
if (isset($directDebitSettings['enabled']) && $directDebitSettings['enabled'] === 'yes') {
$this->recurringMollieMethod = $directDebitPaymentMethod;
}
- return $this;
}
/**
@@ -182,7 +179,11 @@ public function handlePaidOrderWebhook($order, $payment)
) {
$payment_method_title = $this->getPaymentMethodTitle($payment);
+ // phpstan:ignore [mollie-stub] Mollie Payment object exposes mode and id as dynamic stdClass properties not covered by type definitions
+ // @phpstan-ignore-next-line
$isTestMode = $payment->mode === 'test';
+ // phpstan:ignore [mollie-stub] see above — $payment->id is also a dynamic property on the same object
+ // @phpstan-ignore-next-line
$paymentMessage = $payment->id . (
$isTestMode
? (' - ' . __('test mode', 'mollie-payments-for-woocommerce'))
diff --git a/src/Subscription/MollieSubscriptionGatewayHandler.php b/src/Subscription/MollieSubscriptionGatewayHandler.php
index 6198655d8..88c00b1b3 100644
--- a/src/Subscription/MollieSubscriptionGatewayHandler.php
+++ b/src/Subscription/MollieSubscriptionGatewayHandler.php
@@ -7,15 +7,16 @@
use Exception;
use Mollie\Api\Exceptions\ApiException;
use Mollie\WooCommerce\Gateway\MolliePaymentGatewayHandler;
+use Mollie\WooCommerce\Notice\NoticeInterface;
use Mollie\WooCommerce\Payment\MollieObject;
+use Mollie\WooCommerce\Payment\MollieOrderService;
use Mollie\WooCommerce\Payment\MollieSubscription;
use Mollie\WooCommerce\Payment\PaymentFactory;
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\SelectedIssuerMiddleware;
use Mollie\WooCommerce\Payment\Request\Middleware\UrlMiddleware;
+use Mollie\WooCommerce\PaymentMethods\Constants;
use Mollie\WooCommerce\PaymentMethods\InstructionStrategies\OrderInstructionsManager;
use Mollie\WooCommerce\PaymentMethods\PaymentMethodI;
use Mollie\WooCommerce\SDK\Api;
@@ -25,7 +26,6 @@
use Mollie\WooCommerce\Shared\Data;
use Mollie\WooCommerce\Shared\SharedDataDictionary;
use Psr\Log\LoggerInterface as Logger;
-use Mollie\WooCommerce\PaymentMethods\Constants;
use WC_Order;
class MollieSubscriptionGatewayHandler extends MolliePaymentGatewayHandler
@@ -108,7 +108,7 @@ function ($renewal_total, WC_Order $renewal_order) use ($gateway) {
$this->scheduled_subscription_payment($renewal_total, $renewal_order, $gateway);
},
10,
- 3
+ 2
);
// A resubscribe order to record a customer resubscribing to an expired or cancelled subscription.
@@ -125,7 +125,7 @@ function ($payment_meta, $subscription) use ($gateway) {
return $this->add_subscription_payment_meta($payment_meta, $subscription, $gateway);
},
10,
- 3
+ 2
);
add_action(
'woocommerce_subscription_validate_payment_meta',
@@ -197,12 +197,12 @@ public function update_subscription_status_for_direct_debit($renewal_order)
/**
* @param $renewal_total
- * @param WC_Order $renewal_order
+ * @param WC_Order|false $renewal_order
*
* @return array
* @throws InvalidApiKey
*/
- public function scheduled_subscription_payment($renewal_total, WC_Order $renewal_order, $gateway)
+ public function scheduled_subscription_payment($renewal_total, $renewal_order, $gateway)
{
if (! $renewal_order) {
$this->logger->debug($this->id . ': Could not load renewal order or process renewal payment.');
@@ -408,6 +408,8 @@ public function scheduled_subscription_payment($renewal_total, WC_Order $renewal
// Log successful creation of 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));
+ // phpstan:ignore [mollie-stub] Mollie Payment object exposes _links and mode as dynamic stdClass properties not covered by type definitions
+ // @phpstan-ignore-next-line
if (isset($payment->_links->changePaymentState->href) && $payment->mode === 'test') {
$renewal_order->add_order_note('MOLLIE TEST MODE: URL to change payment state for renewal payment: ' . $payment->_links->changePaymentState->href . '');
}
@@ -634,8 +636,8 @@ public function validate_subscription_payment_meta($payment_method_id, $payment_
*/
public function update_failing_payment_method($subscription, $renewal_order)
{
- $subscription->update_meta_data('_mollie_customer_id', $renewal_order->mollie_customer_id);
- $subscription->update_meta_data('_mollie_payment_id', $renewal_order->mollie_payment_id);
+ $subscription->update_meta_data('_mollie_customer_id', $renewal_order->get_meta('_mollie_customer_id', true));
+ $subscription->update_meta_data('_mollie_payment_id', $renewal_order->get_meta('_mollie_payment_id', true));
$subscription->save();
}