From 3b1e75a00f73446dca947d39e5a8b6e58e8e5551 Mon Sep 17 00:00:00 2001
From: Matic Luznar
Date: Tue, 1 Aug 2023 09:13:23 +0200
Subject: [PATCH 01/23] Show notice to user if payment is not successful
---
src/Gateway/MolliePaymentGateway.php | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index f71438a8..a176fd44 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -570,6 +570,12 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
if ($order_status_cancelled_payments === 'cancelled') {
return $this->get_return_url($order);
} else {
+
+ wc_add_notice(__(
+ 'You have cancelled your payment. Please complete your order with a different payment method.',
+ 'mollie-payments-for-woocommerce'
+ ), "error");
+
$this->notice->addNotice(
'notice',
__(
@@ -591,6 +597,12 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
&& !$payment->isPaid()
&& !$payment->isAuthorized()
) {
+
+ wc_add_notice(__(
+ 'Your payment was not successful. Please complete your order with a different payment method.',
+ 'mollie-payments-for-woocommerce'
+ ), "error");
+
$this->notice->addNotice(
'notice',
__(
@@ -605,6 +617,12 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
$this->paymentMethod->debugGiftcardDetails($payment, $order);
}
} catch (UnexpectedValueException $exc) {
+
+ wc_add_notice(__(
+ 'Your payment was not successful. Please complete your order with a different payment method.',
+ 'mollie-payments-for-woocommerce'
+ ), "error");
+
$this->notice->addNotice(
'notice',
__(
From c93a39ba3a0f233fb62047e4fbfca3c355c55204 Mon Sep 17 00:00:00 2001
From: Matic Luznar
Date: Tue, 1 Aug 2023 09:25:04 +0200
Subject: [PATCH 02/23] Fix spacing phpcs errors
---
src/Gateway/MolliePaymentGateway.php | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index a176fd44..32117df6 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -570,12 +570,7 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
if ($order_status_cancelled_payments === 'cancelled') {
return $this->get_return_url($order);
} else {
-
- wc_add_notice(__(
- 'You have cancelled your payment. Please complete your order with a different payment method.',
- 'mollie-payments-for-woocommerce'
- ), "error");
-
+ wc_add_notice(__('You have cancelled your payment. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
'notice',
__(
@@ -583,7 +578,6 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
'mollie-payments-for-woocommerce'
)
);
-
// Return to order payment page
return $failedRedirect;
}
@@ -597,12 +591,7 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
&& !$payment->isPaid()
&& !$payment->isAuthorized()
) {
-
- wc_add_notice(__(
- 'Your payment was not successful. Please complete your order with a different payment method.',
- 'mollie-payments-for-woocommerce'
- ), "error");
-
+ wc_add_notice(__('Your payment was not successful. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
'notice',
__(
@@ -617,12 +606,7 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
$this->paymentMethod->debugGiftcardDetails($payment, $order);
}
} catch (UnexpectedValueException $exc) {
-
- wc_add_notice(__(
- 'Your payment was not successful. Please complete your order with a different payment method.',
- 'mollie-payments-for-woocommerce'
- ), "error");
-
+ wc_add_notice(__('Your payment was not successful. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
'notice',
__(
From bd741a7933119ffe6a4dbef6eeee09c766212bd3 Mon Sep 17 00:00:00 2001
From: Matic Luznar
Date: Tue, 1 Aug 2023 11:40:59 +0200
Subject: [PATCH 03/23] Create FrontendNotice class and use it in the
MolliePaymentGateway module.
---
src/Gateway/GatewayModule.php | 5 +++--
src/Gateway/MolliePaymentGateway.php | 9 +++------
src/Notice/FrontendNotice.php | 13 +++++++++++++
src/Notice/NoticeModule.php | 6 +++---
4 files changed, 22 insertions(+), 11 deletions(-)
create mode 100644 src/Notice/FrontendNotice.php
diff --git a/src/Gateway/GatewayModule.php b/src/Gateway/GatewayModule.php
index b4c8a062..a7411952 100644
--- a/src/Gateway/GatewayModule.php
+++ b/src/Gateway/GatewayModule.php
@@ -18,6 +18,7 @@
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;
@@ -495,8 +496,8 @@ public function instantiatePaymentMethodGateways(ContainerInterface $container):
{
$logger = $container->get(Logger::class);
assert($logger instanceof Logger);
- $notice = $container->get(AdminNotice::class);
- assert($notice instanceof AdminNotice);
+ $notice = $container->get(FrontendNotice::class);
+ assert($notice instanceof FrontendNotice);
$paymentService = $container->get(PaymentService::class);
assert($paymentService instanceof PaymentService);
$mollieOrderService = $container->get(MollieOrderService::class);
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index 32117df6..c0992203 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -570,9 +570,8 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
if ($order_status_cancelled_payments === 'cancelled') {
return $this->get_return_url($order);
} else {
- wc_add_notice(__('You have cancelled your payment. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
- 'notice',
+ 'error',
__(
'You have cancelled your payment. Please complete your order with a different payment method.',
'mollie-payments-for-woocommerce'
@@ -591,9 +590,8 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
&& !$payment->isPaid()
&& !$payment->isAuthorized()
) {
- wc_add_notice(__('Your payment was not successful. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
- 'notice',
+ 'error',
__(
'Your payment was not successful. Please complete your order with a different payment method.',
'mollie-payments-for-woocommerce'
@@ -606,9 +604,8 @@ public function getReturnRedirectUrlForOrder(WC_Order $order): string
$this->paymentMethod->debugGiftcardDetails($payment, $order);
}
} catch (UnexpectedValueException $exc) {
- wc_add_notice(__('Your payment was not successful. Please complete your order with a different payment method.', 'mollie-payments-for-woocommerce'), "error");
$this->notice->addNotice(
- 'notice',
+ 'error',
__(
'Your payment was not successful. Please complete your order with a different payment method.',
'mollie-payments-for-woocommerce'
diff --git a/src/Notice/FrontendNotice.php b/src/Notice/FrontendNotice.php
new file mode 100644
index 00000000..02c59bef
--- /dev/null
+++ b/src/Notice/FrontendNotice.php
@@ -0,0 +1,13 @@
+ static function (): AdminNotice {
return new AdminNotice();
},
+ FrontendNotice::class => static function (): FrontendNotice {
+ return new FrontendNotice();
+ },
];
}
}
From a65635504661094b20327e802b26556070523c48 Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 12 Sep 2023 13:22:27 +0200
Subject: [PATCH 04/23] Check if WC_Subscription class exists instead the
subscription plugin file.
---
src/Shared/Data.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Shared/Data.php b/src/Shared/Data.php
index 536b2866..3cb509e5 100644
--- a/src/Shared/Data.php
+++ b/src/Shared/Data.php
@@ -77,7 +77,7 @@ public function isBlockPluginActive(): bool
public function isSubscriptionPluginActive(): bool
{
- $subscriptionPlugin = is_plugin_active('woocommerce-subscriptions/woocommerce-subscriptions.php');
+ $subscriptionPlugin = class_exists('WC_Subscriptions');
return apply_filters('mollie_wc_subscription_plugin_active', $subscriptionPlugin);
}
From 3e7c7563d0f31b969e6e7a9d94239b7ceaf73b8c Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 19 Sep 2023 13:48:58 +0200
Subject: [PATCH 05/23] Check if surcharge array key exists.
---
src/Gateway/Surcharge.php | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/Gateway/Surcharge.php b/src/Gateway/Surcharge.php
index 17340bf4..8bb077a0 100644
--- a/src/Gateway/Surcharge.php
+++ b/src/Gateway/Surcharge.php
@@ -105,6 +105,10 @@ public function aboveMaxLimit(float $totalAmount, array $gatewaySettings): bool
*/
public function calculateFeeAmount(WC_Cart $cart, array $gatewaySettings): float
{
+ if (!isset($gatewaySettings['payment_surcharge'])) {
+ return 0.0;
+ }
+
$surchargeType = $gatewaySettings['payment_surcharge'];
$methodName = sprintf('calculate_%s', $surchargeType);
@@ -154,7 +158,7 @@ protected function calculate_no_fee(WC_Cart $cart, array $gatewaySettings): floa
*/
protected function calculate_fixed_fee($cart, array $gatewaySettings)
{
- return !empty($gatewaySettings[Surcharge::FIXED_FEE]) ? (float) $gatewaySettings[Surcharge::FIXED_FEE] : 0.0;
+ return !empty($gatewaySettings[Surcharge::FIXED_FEE]) ? (float)$gatewaySettings[Surcharge::FIXED_FEE] : 0.0;
}
/**
@@ -294,7 +298,12 @@ protected function name_fixed_fee_percentage($paymentMethod)
$currency = get_woocommerce_currency_symbol();
$amountPercent = $paymentMethod->getProperty(self::PERCENTAGE);
/* translators: Placeholder 1: Fee amount tag. Placeholder 2: Currency. Placeholder 3: Percentage amount. */
- return sprintf(__(' + %1$s %2$s + %3$s%% fee might apply', 'mollie-payments-for-woocommerce'), $currency, $amountFix, $amountPercent);
+ return sprintf(
+ __(' + %1$s %2$s + %3$s%% fee might apply', 'mollie-payments-for-woocommerce'),
+ $currency,
+ $amountFix,
+ $amountPercent
+ );
}
/**
From b6860866207a0d34e17edf09803d8dbfee9a8f87 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Tue, 17 Oct 2023 17:44:11 +0200
Subject: [PATCH 06/23] Add details to customer email
---
src/Gateway/MolliePaymentGateway.php | 43 ++++++++++++++++++----------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index f71438a8..d45d98e9 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -30,7 +30,8 @@ class MolliePaymentGateway extends WC_Payment_Gateway implements MolliePaymentGa
/**
* @var bool
*/
- protected static $alreadyDisplayedInstructions = false;
+ protected static $alreadyDisplayedAdminInstructions = false;
+ protected static $alreadyDisplayedCustomerInstructions = false;
/**
* Recurring total, zero does not define a recurring total
*
@@ -115,7 +116,7 @@ public function __construct(
$this->paymentFactory = $paymentFactory;
$this->pluginId = $pluginId;
- // No plugin id, gateway id is unique enough
+ // No plugin id, gateway id is unique enough
$this->plugin_id = '';
// Use gateway class name as gateway id
$this->gatewayId();
@@ -156,6 +157,12 @@ public function __construct(
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);
@@ -267,17 +274,17 @@ public function isValidForUse(): bool
$test_mode = $this->dataService->isTestModeEnabled();
$this->errors[] = ($test_mode ? __(
- 'Test mode enabled.',
- 'mollie-payments-for-woocommerce'
- ) . ' ' : '') . sprintf(
+ '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'
- ),
- '',
- ''
- );
+ __(
+ 'No API key provided. Please %1$sset you Mollie API key%2$s first.',
+ 'mollie-payments-for-woocommerce'
+ ),
+ '',
+ ''
+ );
return false;
}
@@ -806,8 +813,9 @@ public function displayInstructions(
$admin_instructions = false,
$plain_text = false
) {
-
- if (!$this::$alreadyDisplayedInstructions) {
+ if (($admin_instructions && !$this::$alreadyDisplayedAdminInstructions)
+ || (!$admin_instructions && !$this::$alreadyDisplayedCustomerInstructions)
+ ) {
$order_payment_method = $order->get_payment_method();
// Invalid gateway
@@ -846,7 +854,12 @@ public function displayInstructions(
}
}
}
- $this::$alreadyDisplayedInstructions = true;
+ if ($admin_instructions && !$this::$alreadyDisplayedAdminInstructions) {
+ $this::$alreadyDisplayedAdminInstructions = true;
+ }
+ if (!$admin_instructions && !$this::$alreadyDisplayedCustomerInstructions) {
+ $this::$alreadyDisplayedCustomerInstructions = true;
+ }
}
/**
From a92bdd011a0bb96c073146ff44d5e39eca7aea37 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Wed, 18 Oct 2023 12:56:37 +0200
Subject: [PATCH 07/23] Change status on webhook completed & cbf
---
.../ApplePayButton/ApplePayDataObjectHttp.php | 2 +-
src/Payment/MollieOrder.php | 7 +++++++
src/Payment/MollieOrderService.php | 17 +++++++++--------
src/PaymentMethods/Kbc.php | 14 +++++++-------
4 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
index 38f91294..db7f6919 100644
--- a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
+++ b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
@@ -326,7 +326,7 @@ protected function addressHasRequiredFieldsValues(
sprintf('ApplePay Data Error: Missing value for %s', $requiredField)
);
$this->errors[]
- = [
+ = [
'errorCode' => $errorCode,
'contactField' => $errorValue,
];
diff --git a/src/Payment/MollieOrder.php b/src/Payment/MollieOrder.php
index 7f63813b..cb61dbc0 100644
--- a/src/Payment/MollieOrder.php
+++ b/src/Payment/MollieOrder.php
@@ -371,6 +371,13 @@ public function onWebhookCompleted(WC_Order $order, $payment, $paymentMethodTitl
if ($payment->method === 'paypal') {
$this->addPaypalTransactionIdToOrder($order);
}
+ add_filter('woocommerce_valid_order_statuses_for_payment_complete', static function ($statuses) {
+ $statuses[] = 'processing';
+ return $statuses;
+ });
+ add_filter('woocommerce_payment_complete_order_status', static function ($status) use ($order) {
+ return $order->get_status() === 'processing' ? 'completed' : $status;
+ });
$order->payment_complete($payment->id);
// Add messages to log
$this->logger->debug(__METHOD__ . ' WooCommerce payment_complete() processed and returned to ' . __METHOD__ . ' for order ' . $orderId);
diff --git a/src/Payment/MollieOrderService.php b/src/Payment/MollieOrderService.php
index 898c0686..0c7ba253 100644
--- a/src/Payment/MollieOrderService.php
+++ b/src/Payment/MollieOrderService.php
@@ -80,7 +80,7 @@ public function onWebhookAction()
$data_helper = $this->data;
$order = wc_get_order($order_id);
- if (!$order) {
+ if (!$order instanceof WC_Order) {
$this->httpResponse->setHttpResponseCode(404);
$this->logger->debug(__METHOD__ . ": Could not find order $order_id.");
return;
@@ -135,7 +135,11 @@ public function onWebhookAction()
// Log a message that webhook was called, doesn't mean the payment is actually processed
$this->logger->debug($this->gateway->id . ": Mollie payment object {$payment->id} (" . $payment->mode . ") webhook call for order {$order->get_id()}.", [true]);
+ // Get payment method title
+ $payment_method_title = $this->getPaymentMethodTitle($payment);
+ // Create the method name based on the payment status
+ $method_name = 'onWebhook' . ucfirst($payment->status);
// Order does not need a payment
if (! $this->orderNeedsPayment($order)) {
// TODO David: move to payment object?
@@ -145,7 +149,10 @@ public function onWebhookAction()
// Check and process a possible refund or chargeback
$this->processRefunds($order, $payment);
$this->processChargebacks($order, $payment);
-
+ //if the order gets updated to completed at mollie, we need to update the order status
+ if ($order->get_status() === 'processing' && $payment->isCompleted() && method_exists($payment_object, 'onWebhookCompleted')) {
+ $payment_object->onWebhookCompleted($order, $payment, $payment_method_title);
+ }
return;
}
@@ -154,12 +161,6 @@ public function onWebhookAction()
$this->setBillingAddressAfterPayment($payment, $order);
}
- // Get payment method title
- $payment_method_title = $this->getPaymentMethodTitle($payment);
-
- // Create the method name based on the payment status
- $method_name = 'onWebhook' . ucfirst($payment->status);
-
if (method_exists($payment_object, $method_name)) {
$payment_object->{$method_name}($order, $payment, $payment_method_title);
} else {
diff --git a/src/PaymentMethods/Kbc.php b/src/PaymentMethods/Kbc.php
index 361116ed..5c220cac 100644
--- a/src/PaymentMethods/Kbc.php
+++ b/src/PaymentMethods/Kbc.php
@@ -6,10 +6,10 @@
class Kbc extends AbstractPaymentMethod implements PaymentMethodI
{
-protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
-protected function getConfig(): array
-{
- return [
+ protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
+ protected function getConfig(): array
+ {
+ return [
'id' => 'kbc',
'defaultTitle' => __('KBC/CBC Payment Button', 'mollie-payments-for-woocommerce'),
'settingsDescription' => '',
@@ -23,10 +23,10 @@ protected function getConfig(): array
'filtersOnBuild' => false,
'confirmationDelayed' => true,
'SEPA' => true,
- ];
-}
+ ];
+ }
-public function getFormFields($generalFormFields): array
+ public function getFormFields($generalFormFields): array
{
$paymentMethodFormFieds = [
'issuers_dropdown_shown' => [
From 17bf7e47092719461280e14618a953ee1234630a Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Wed, 18 Oct 2023 15:57:19 +0200
Subject: [PATCH 08/23] Check 422 fraud exception and bail
---
.../ApplePayButton/ApplePayDataObjectHttp.php | 2 +-
src/Payment/PaymentService.php | 25 +++++++++++++++++++
src/PaymentMethods/Kbc.php | 14 +++++------
src/SDK/Api.php | 11 ++++++++
4 files changed, 44 insertions(+), 8 deletions(-)
diff --git a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
index 38f91294..db7f6919 100644
--- a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
+++ b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
@@ -326,7 +326,7 @@ protected function addressHasRequiredFieldsValues(
sprintf('ApplePay Data Error: Missing value for %s', $requiredField)
);
$this->errors[]
- = [
+ = [
'errorCode' => $errorCode,
'contactField' => $errorValue,
];
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php
index ea7b53f3..1e56d636 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentService.php
@@ -387,6 +387,8 @@ protected function processAsMollieOrder(
}
} catch (ApiException $e) {
$this->handleMollieOutage($e);
+ //if exception is 422 do not try to create a payment
+ $this->handleMollieFraudRejection($e);
// Don't try to create a Mollie Payment for Klarna payment methods
$order_payment_method = $order->get_payment_method();
$orderMandatoryPaymentMethods = [
@@ -873,4 +875,27 @@ public function handleMollieOutage(ApiException $e): void
);
}
}
+
+ /**
+ * Check if the exception is a fraud rejection, if so bail, log and inform user
+ * @param ApiException $e
+ * @return void
+ * @throws ApiException
+ */
+ public function handleMollieFraudRejection(ApiException $e): void
+ {
+ $isMollieFraudException = $this->apiHelper->isMollieFraudException($e);
+ if ($isMollieFraudException) {
+ $this->logger->debug(
+ "Creating payment object: The payment was declined due to suspected fraud, stopping process."
+ );
+
+ throw new ApiException(
+ __(
+ 'Payment failed due to: The payment was declined due to suspected fraud.',
+ 'mollie-payments-for-woocommerce'
+ )
+ );
+ }
+ }
}
diff --git a/src/PaymentMethods/Kbc.php b/src/PaymentMethods/Kbc.php
index 361116ed..5c220cac 100644
--- a/src/PaymentMethods/Kbc.php
+++ b/src/PaymentMethods/Kbc.php
@@ -6,10 +6,10 @@
class Kbc extends AbstractPaymentMethod implements PaymentMethodI
{
-protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
-protected function getConfig(): array
-{
- return [
+ protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
+ protected function getConfig(): array
+ {
+ return [
'id' => 'kbc',
'defaultTitle' => __('KBC/CBC Payment Button', 'mollie-payments-for-woocommerce'),
'settingsDescription' => '',
@@ -23,10 +23,10 @@ protected function getConfig(): array
'filtersOnBuild' => false,
'confirmationDelayed' => true,
'SEPA' => true,
- ];
-}
+ ];
+ }
-public function getFormFields($generalFormFields): array
+ public function getFormFields($generalFormFields): array
{
$paymentMethodFormFieds = [
'issuers_dropdown_shown' => [
diff --git a/src/SDK/Api.php b/src/SDK/Api.php
index 7b7cd5fb..d3526fb7 100644
--- a/src/SDK/Api.php
+++ b/src/SDK/Api.php
@@ -82,4 +82,15 @@ public function isMollieOutageException(\Mollie\Api\Exceptions\ApiException $e):
}
return false;
}
+
+ public function isMollieFraudException(\Mollie\Api\Exceptions\ApiException $e): bool
+ {
+ $isFraudCode = $e->getCode() === 422;
+ $isFraudMessage = strpos($e->getMessage(), 'The payment was declined due to suspected fraud') !== false;
+
+ if ($isFraudCode && $isFraudMessage) {
+ return true;
+ }
+ return false;
+ }
}
From 1b842f667fe3b670a75064500b0aeb5a5e9bd946 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Thu, 19 Oct 2023 15:53:21 +0200
Subject: [PATCH 09/23] Update wiki and support links
---
src/Settings/Page/MollieSettingsPage.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Settings/Page/MollieSettingsPage.php b/src/Settings/Page/MollieSettingsPage.php
index 03f4c402..fd265b69 100644
--- a/src/Settings/Page/MollieSettingsPage.php
+++ b/src/Settings/Page/MollieSettingsPage.php
@@ -146,10 +146,10 @@ public function addGlobalSettingsFields(array $settings): array
) . '
';
$presentation = ''
- . '' . __(
+ . ''
From 4069e886996b76434d33707b21b15abb443c6a0c Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Fri, 20 Oct 2023 11:28:27 +0200
Subject: [PATCH 10/23] Add metabox to show payment details
---
src/Gateway/GatewayModule.php | 29 +++++++++++++++++++++++++++-
src/Gateway/MolliePaymentGateway.php | 6 ++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/src/Gateway/GatewayModule.php b/src/Gateway/GatewayModule.php
index bc5b2a18..1e1a1004 100644
--- a/src/Gateway/GatewayModule.php
+++ b/src/Gateway/GatewayModule.php
@@ -6,6 +6,7 @@
namespace Mollie\WooCommerce\Gateway;
+use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
@@ -39,6 +40,7 @@
use Mollie\WooCommerce\PaymentMethods\Constants;
use Mollie\WooCommerce\Vendor\Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface as Logger;
+use WP_Post;
class GatewayModule implements ServiceModule, ExecutableModule
{
@@ -301,10 +303,35 @@ static function ($paymentContext) {
$order->save();
}
);
-
+ add_action('add_meta_boxes_woocommerce_page_wc-orders', [$this, 'addShopOrderMetabox'], 10);
return true;
}
+ /**
+ * @param Object $post
+ * @return void
+ */
+ public function addShopOrderMetabox(object $post)
+ {
+ if (! $post instanceof \WC_Order) {
+ return;
+ }
+ $meta = $post->get_meta('_mollie_payment_instructions');
+ if (empty($meta)) {
+ return;
+ }
+ $screen = wc_get_container()->get(CustomOrdersTableController::class)->custom_orders_table_usage_is_enabled()
+ ? wc_get_page_screen_id('shop-order')
+ : 'shop_order';
+ add_meta_box('mollie_order_details', __('Mollie Payment Details', 'mollie-payments-for-woocommerce'), static function () use ($meta) {
+ $allowedTags = ['strong' => []];
+ printf(
+ '%s
',
+ wp_kses($meta, $allowedTags)
+ );
+ }, $screen, 'side', 'high');
+ }
+
/**
* Disable Bank Transfer Gateway
*
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index f71438a8..6f3b6600 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -836,6 +836,12 @@ public function displayInstructions(
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;
From ce1b8981ef6da32418f45f9ea86c0a2ad3c3aedd Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Fri, 20 Oct 2023 11:51:33 +0200
Subject: [PATCH 11/23] update initial_order_status description
---
src/Settings/General/MollieGeneralSettings.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Settings/General/MollieGeneralSettings.php b/src/Settings/General/MollieGeneralSettings.php
index b0d018b9..7ac6b9d7 100644
--- a/src/Settings/General/MollieGeneralSettings.php
+++ b/src/Settings/General/MollieGeneralSettings.php
@@ -290,7 +290,7 @@ public function gatewayFormFields(
/* translators: Placeholder 1: Default order status, placeholder 2: Link to 'Hold Stock' setting */
'description' => sprintf(
__(
- 'Some payment methods take longer than a few hours to complete. The initial order state is then set to \'%1$s\'. This ensures the order is not cancelled when the setting %2$s is used.',
+ 'Some payment methods take longer than a few hours to complete. The initial order state is then set to \'%1$s\'. This ensures the order is not cancelled when the setting %2$s is used. This will also prevent the order to be canceled when expired.',
'mollie-payments-for-woocommerce'
),
wc_get_order_status_name(
From ddd3d2cbcebb55268eb17444391a648fd71576e6 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Fri, 20 Oct 2023 17:45:20 +0200
Subject: [PATCH 12/23] Add unit test to check exception
---
tests/php/Functional/HelperMocks.php | 7 ++
.../Functional/Payment/PaymentServiceTest.php | 69 +++++++++++++++++++
2 files changed, 76 insertions(+)
diff --git a/tests/php/Functional/HelperMocks.php b/tests/php/Functional/HelperMocks.php
index 9ea1a44a..61a80371 100644
--- a/tests/php/Functional/HelperMocks.php
+++ b/tests/php/Functional/HelperMocks.php
@@ -7,6 +7,7 @@
use Mollie\Api\MollieApiClient;
use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
use Mollie\WooCommerce\Notice\AdminNotice;
+use Mollie\WooCommerce\Payment\MollieOrder;
use Mollie\WooCommerce\Payment\MollieOrderService;
use Mollie\WooCommerce\Payment\OrderInstructionsService;
use Mollie\WooCommerce\Payment\OrderLines;
@@ -59,6 +60,12 @@ public function paymentFactory($apiClientMock){
);
}
+ public function mollieOrderMock()
+ {
+ return $this->getMockBuilder(MollieOrder::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ }
public function noticeMock()
{
return $this->getMockBuilder(AdminNotice::class)
diff --git a/tests/php/Functional/Payment/PaymentServiceTest.php b/tests/php/Functional/Payment/PaymentServiceTest.php
index b8c536b3..3ef13e93 100644
--- a/tests/php/Functional/Payment/PaymentServiceTest.php
+++ b/tests/php/Functional/Payment/PaymentServiceTest.php
@@ -3,6 +3,7 @@
namespace Mollie\WooCommerceTests\Functional\Payment;
use Mollie\Api\Endpoints\OrderEndpoint;
+use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\MollieApiClient;
use Mollie\WooCommerce\Gateway\MolliePaymentGateway;
use Mollie\WooCommerce\Payment\PaymentCheckoutRedirectService;
@@ -129,6 +130,64 @@ public function processPayment_Order_success(){
self::assertEquals($expectedResult, $arrayResult);
}
+ /**
+ * @test
+ * @throws ApiException
+ */
+ public function processAsMollieOrder_BailsIf_FraudException()
+ {
+ stubs([
+ 'array_filter' => [],
+ ]);
+ $mockedException = new TestApiException();
+ $mockedException->setTestCode(422);
+ $mockedException->setTestMessage('The payment was declined due to suspected fraud');
+ $orderEndpointsMock = $this->createConfiguredMock(
+ OrderEndpoint::class,
+ [
+ 'create' => new MollieOrderResponse(),
+ ]
+ );
+ $paymentMethodId = 'Ideal';
+ $orderEndpointsMock->method('create')->with([])
+ ->will($this->throwException($mockedException));
+
+ $apiClientMock = $this->createMock(MollieApiClient::class);
+ $apiClientMock->orders = $orderEndpointsMock;
+ $voucherDefaultCategory = Voucher::NO_CATEGORY;
+
+ $testee = new PaymentService(
+ $this->helperMocks->noticeMock(),
+ $this->helperMocks->loggerMock(),
+ $this->helperMocks->paymentFactory($apiClientMock),
+ $this->helperMocks->dataHelper($apiClientMock),
+ $this->helperMocks->apiHelper($apiClientMock),
+ $this->helperMocks->settingsHelper(),
+ $this->helperMocks->pluginId(),
+ $this->paymentCheckoutService($apiClientMock),
+ $voucherDefaultCategory
+ );
+ $gateway = $this->mollieGateway($paymentMethodId, $testee);
+ $testee->setGateway($gateway);
+ $wcOrderId = 1;
+ $wcOrderKey = 'wc_order_hxZniP1zDcnM8';
+ $wcOrder = $this->wcOrder($wcOrderId, $wcOrderKey);
+ $cusomerId = 1;
+ $apiKey = 'test_test';
+ $method = new \ReflectionMethod(PaymentService::class, 'processAsMollieOrder');
+ $method->setAccessible(true);
+
+ $this->expectException(ApiException::class);
+
+ $method->invoke(
+ $testee,
+ $this->helperMocks->mollieOrderMock(),
+ $wcOrder,
+ $cusomerId,
+ $apiKey
+ );
+ }
+
protected function setUp(): void
{
@@ -451,5 +510,15 @@ public function getCheckoutUrl()
}
+class TestApiException extends \Mollie\Api\Exceptions\ApiException {
+ public function setTestCode($code) {
+ $this->code = $code;
+ }
+
+ public function setTestMessage($message) {
+ $this->message = $message;
+ }
+}
+
From c2077b45e56069f043aa14092912ab919a112953 Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 24 Oct 2023 09:52:48 +0200
Subject: [PATCH 13/23] Capture payment manually
---
inc/settings/mollie_advanced_settings.php | 30 +++
mollie-payments-for-woocommerce.php | 2 +
resources/js/advancedSettings.js | 54 ++++-
.../ApplePayButton/ApplePayDataObjectHttp.php | 2 +-
.../Action/AbstractPaymentCaptureAction.php | 40 ++++
.../Capture/Action/CapturePayment.php | 65 ++++++
.../Capture/Action/VoidPayment.php | 34 +++
.../Capture/Type/ManualCapture.php | 51 +++++
.../Capture/Type/StateChangeCapture.php | 55 +++++
src/MerchantCapture/ManualCaptureStatus.php | 14 ++
src/MerchantCapture/MerchantCaptureModule.php | 194 ++++++++++++++++++
.../OrderListPaymentColumn.php | 56 +++++
src/MerchantCapture/UI/OrderActionBlock.php | 19 ++
src/MerchantCapture/UI/StatusButton.php | 15 ++
src/MerchantCapture/UI/StatusRenderer.php | 36 ++++
src/Payment/MollieOrderService.php | 1 +
src/Payment/MolliePayment.php | 4 +
src/Payment/PaymentModule.php | 2 +-
src/Payment/PaymentService.php | 7 +-
src/PaymentMethods/Kbc.php | 14 +-
src/SDK/WordPressHttpAdapter.php | 3 +-
21 files changed, 677 insertions(+), 21 deletions(-)
create mode 100644 src/MerchantCapture/Capture/Action/AbstractPaymentCaptureAction.php
create mode 100644 src/MerchantCapture/Capture/Action/CapturePayment.php
create mode 100644 src/MerchantCapture/Capture/Action/VoidPayment.php
create mode 100644 src/MerchantCapture/Capture/Type/ManualCapture.php
create mode 100644 src/MerchantCapture/Capture/Type/StateChangeCapture.php
create mode 100644 src/MerchantCapture/ManualCaptureStatus.php
create mode 100644 src/MerchantCapture/MerchantCaptureModule.php
create mode 100644 src/MerchantCapture/OrderListPaymentColumn.php
create mode 100644 src/MerchantCapture/UI/OrderActionBlock.php
create mode 100644 src/MerchantCapture/UI/StatusButton.php
create mode 100644 src/MerchantCapture/UI/StatusRenderer.php
diff --git a/inc/settings/mollie_advanced_settings.php b/inc/settings/mollie_advanced_settings.php
index 31750d6b..e4026f49 100644
--- a/inc/settings/mollie_advanced_settings.php
+++ b/inc/settings/mollie_advanced_settings.php
@@ -199,6 +199,36 @@ class="mollie-settings-advanced-payment-desc-label button button-secondary butto
__('Clear now', 'mollie-payments-for-woocommerce')
) . ')',
],
+ [
+ 'id' => $pluginName . '_place_payment_onhold',
+ 'title' => __('Placing payments on Hold', 'mollie-payments-for-woocommerce'),
+ 'type' => 'select',
+ 'desc_tip' => true,
+ 'options' => [
+ 'immediate_capture' => __('Capture payments immediately', 'mollie-payments-for-woocommerce'),
+ 'later_capture' => __('Authorize payments for a later capture', 'mollie-payments-for-woocommerce'),
+ ],
+ 'default' => 'immediate_capture',
+ 'desc' => sprintf(
+ __(
+ 'Authorized payment can be captured or voided by changing the order status instead of doing it manually.',
+ 'mollie-payments-for-woocommerce'
+ )
+ ),
+ ],
+ [
+ 'id' => $pluginName . '_capture_or_void',
+ 'title' => __(
+ 'Capture or void on status change',
+ 'mollie-payments-for-woocommerce'
+ ),
+ 'type' => 'checkbox',
+ 'default' => 'no',
+ 'desc' => __(
+ 'Capture authorized payments automatically when setting the order status to Processing or Completed. Void the payment by setting the order status Canceled.',
+ 'mollie-payments-for-woocommerce'
+ ),
+ ],
[
'id' => $pluginName . '_sectionend',
'type' => 'sectionend',
diff --git a/mollie-payments-for-woocommerce.php b/mollie-payments-for-woocommerce.php
index 4ff8709a..75cb243c 100644
--- a/mollie-payments-for-woocommerce.php
+++ b/mollie-payments-for-woocommerce.php
@@ -19,6 +19,7 @@
namespace Mollie\WooCommerce;
+use Mollie\WooCommerce\MerchantCapture\MerchantCaptureModule;
use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Package;
use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Properties\PluginProperties;
use Mollie\WooCommerce\Activation\ActivationModule;
@@ -161,6 +162,7 @@ function initialize()
new GatewayModule(),
new VoucherModule(),
new PaymentModule(),
+ new MerchantCaptureModule(),
new UninstallModule(),
];
$modules = apply_filters('mollie_wc_plugin_modules', $modules);
diff --git a/resources/js/advancedSettings.js b/resources/js/advancedSettings.js
index d78b22aa..3aa2bc0d 100644
--- a/resources/js/advancedSettings.js
+++ b/resources/js/advancedSettings.js
@@ -1,9 +1,9 @@
(
- function ({_, jQuery }) {
+ function ({_, jQuery}) {
function mollie_settings__insertTextAtCursor(target, text, dontIgnoreSelection) {
if (target.setRangeText) {
- if ( !dontIgnoreSelection ) {
+ if (!dontIgnoreSelection) {
// insert at end
target.setRangeText(text, target.value.length, target.value.length, "end");
} else {
@@ -16,13 +16,14 @@
}
target.focus();
}
- jQuery(document).ready(function($) {
+
+ jQuery(document).ready(function ($) {
$(".mollie-settings-advanced-payment-desc-label")
.data("ignore-click", "false")
- .on("mousedown", function(e) {
+ .on("mousedown", function (e) {
const input = document.getElementById("mollie-payments-for-woocommerce_api_payment_description");
- if ( document.activeElement && input === document.activeElement ) {
- $(this).on("mouseup.molliesettings", function(e) {
+ if (document.activeElement && input === document.activeElement) {
+ $(this).on("mouseup.molliesettings", function (e) {
$(this).data("ignore-click", "true");
$(this).off(".molliesettings");
const tag = $(this).data("tag");
@@ -31,15 +32,15 @@
});
}
let $this = $(this);
- $(window).on("mouseup.molliesettings drag.molliesettings blur.molliesettings", function(e) {
+ $(window).on("mouseup.molliesettings drag.molliesettings blur.molliesettings", function (e) {
$this.off(".molliesettings");
$(window).off(".molliesettings");
});
})
- .on("click", function(e) {
+ .on("click", function (e) {
e.preventDefault();
e.stopImmediatePropagation();
- if ( $(this).data("ignore-click") === "false" ) {
+ if ($(this).data("ignore-click") === "false") {
const tag = $(this).data("tag");
const input = document.getElementById("mollie-payments-for-woocommerce_api_payment_description");
mollie_settings__insertTextAtCursor(input, tag, false);
@@ -48,9 +49,44 @@
}
})
;
+ registerManualCaptureFields();
});
}
)
(
window
)
+
+function registerManualCaptureFields() {
+ const onHoldSelect = jQuery('[name="mollie-payments-for-woocommerce_place_payment_onhold"]');
+ if (onHoldSelect.length === 0) {
+ return;
+ }
+ toggleManualCaptureFields(onHoldSelect);
+ onHoldSelect.on('change', function(){
+ toggleManualCaptureFields(onHoldSelect);
+ })
+}
+
+function toggleManualCaptureFields(onHoldSelect) {
+ const currentValue = onHoldSelect.find('option:selected');
+ if (currentValue.length === 0) {
+ return;
+ }
+
+ const captureStatusChangeField = jQuery('[name="mollie-payments-for-woocommerce_capture_or_void"]');
+ if (captureStatusChangeField.length === 0) {
+ return;
+ }
+
+ const captureStatusChangeFieldParent = captureStatusChangeField.closest('tr');
+ if (captureStatusChangeFieldParent.length === 0) {
+ return;
+ }
+
+ if (currentValue.val() === 'later_capture') {
+ captureStatusChangeFieldParent.show();
+ } else {
+ captureStatusChangeFieldParent.hide();
+ }
+}
diff --git a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
index 38f91294..db7f6919 100644
--- a/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
+++ b/src/Buttons/ApplePayButton/ApplePayDataObjectHttp.php
@@ -326,7 +326,7 @@ protected function addressHasRequiredFieldsValues(
sprintf('ApplePay Data Error: Missing value for %s', $requiredField)
);
$this->errors[]
- = [
+ = [
'errorCode' => $errorCode,
'contactField' => $errorValue,
];
diff --git a/src/MerchantCapture/Capture/Action/AbstractPaymentCaptureAction.php b/src/MerchantCapture/Capture/Action/AbstractPaymentCaptureAction.php
new file mode 100644
index 00000000..70d3ef8b
--- /dev/null
+++ b/src/MerchantCapture/Capture/Action/AbstractPaymentCaptureAction.php
@@ -0,0 +1,40 @@
+apiHelper = $apiHelper;
+ $this->settingsHelper = $settingsHelper;
+ $this->order = wc_get_order($orderId);
+ $this->logger = $logger;
+ $this->pluginId = $pluginId;
+ $this->setApiKey();
+ }
+
+ protected function setApiKey()
+ {
+ $this->apiKey = $this->settingsHelper->getApiKey();
+ }
+}
diff --git a/src/MerchantCapture/Capture/Action/CapturePayment.php b/src/MerchantCapture/Capture/Action/CapturePayment.php
new file mode 100644
index 00000000..41fd5ab7
--- /dev/null
+++ b/src/MerchantCapture/Capture/Action/CapturePayment.php
@@ -0,0 +1,65 @@
+order->get_meta('_mollie_payment_id');
+
+ if (!$paymentId) {
+ $this->logger->error('Missing Mollie payment ID in order ' . $this->order->get_id());
+ $this->order->add_order_note(
+ __(
+ 'The Mollie payment ID is missing, and we are unable to capture the funds.',
+ 'mollie-payments-for-woocommerce'
+ )
+ );
+ return;
+ }
+
+ $paymentCapturesApi = $this->apiHelper->getApiClient($this->apiKey)->paymentCaptures;
+ $captureData = [
+ 'amount' => [
+ 'currency' => $this->order->get_currency(),
+ 'value' => $this->order->get_total(),
+ ],
+ ];
+ $this->logger->debug(
+ 'SEND AN ORDER CAPTURE, orderId: ' . $this->order->get_id(
+ ) . ' transactionId: ' . $paymentId . 'Capture data: ' . json_encode($captureData)
+ );
+ $paymentCapturesApi->createForId($paymentId, $captureData);
+ $this->order->update_meta_data(
+ MerchantCaptureModule::ORDER_PAYMENT_STATUS_META_KEY,
+ ManualCaptureStatus::STATUS_WAITING
+ );
+ $this->order->add_order_note(
+ sprintf(
+ __(
+ 'The payment capture of %s has been sent successfully, and we are currently awaiting confirmation.',
+ 'mollie-payments-for-woocommerce'
+ ),
+ wc_price($this->order->get_total())
+ )
+ );
+ $this->order->save();
+ } catch (ApiException $exception) {
+ $this->logger->error($exception->getMessage());
+ $this->order->add_order_note(
+ __(
+ 'Payment Capture Failed. We encountered an issue while processing the payment capture.',
+ 'mollie-payments-for-woocommerce'
+ )
+ );
+ }
+ }
+}
diff --git a/src/MerchantCapture/Capture/Action/VoidPayment.php b/src/MerchantCapture/Capture/Action/VoidPayment.php
new file mode 100644
index 00000000..0ef1d152
--- /dev/null
+++ b/src/MerchantCapture/Capture/Action/VoidPayment.php
@@ -0,0 +1,34 @@
+order->get_meta('_mollie_payment_id');
+ $paymentCapturesApi = $this->apiHelper->getApiClient($this->apiKey)->payments;
+ try {
+ $paymentCapturesApi->cancel($paymentId);
+ $this->order->update_meta_data(
+ MerchantCaptureModule::ORDER_PAYMENT_STATUS_META_KEY,
+ ManualCaptureStatus::STATUS_VOIDED
+ );
+ $this->order->save();
+ } catch (ApiException $exception) {
+ $this->logger->error($exception->getMessage());
+ $this->order->add_order_note(
+ __(
+ 'Payment Void Failed. We encountered an issue while canceling the pre-authorized payment.',
+ 'mollie-payments-for-woocommerce'
+ )
+ );
+ }
+ }
+}
diff --git a/src/MerchantCapture/Capture/Type/ManualCapture.php b/src/MerchantCapture/Capture/Type/ManualCapture.php
new file mode 100644
index 00000000..70c890c2
--- /dev/null
+++ b/src/MerchantCapture/Capture/Type/ManualCapture.php
@@ -0,0 +1,51 @@
+container = $container;
+ add_action('woocommerce_order_actions', [$this, 'enableOrderCaptureButton'], 10, 2);
+ add_action('woocommerce_order_action_' . self::MOLLIE_MANUAL_CAPTURE_ACTION, [$this, 'manualCapture']);
+ add_filter('woocommerce_mollie_wc_gateway_creditcard_args', [$this, 'sendManualCaptureMode']);
+ }
+
+ public function enableOrderCaptureButton(array $actions, \WC_Order $order): array
+ {
+ if (!$this->container->get('merchant.manual_capture.can_capture_the_order')($order)) {
+ return $actions;
+ }
+ $actions[self::MOLLIE_MANUAL_CAPTURE_ACTION] = __(
+ 'Capture authorized Mollie payment',
+ 'mollie-payments-for-woocommerce'
+ );
+ return $actions;
+ }
+
+ public function sendManualCaptureMode(array $paymentData): array
+ {
+ if ($this->container->get('merchant.manual_capture.enabled')) {
+ $paymentData['captureMode'] = 'manual';
+ }
+ return $paymentData;
+ }
+
+ public function manualCapture(\WC_Order $order)
+ {
+
+ ($this->container->get(CapturePayment::class))($order->get_id());
+ }
+}
diff --git a/src/MerchantCapture/Capture/Type/StateChangeCapture.php b/src/MerchantCapture/Capture/Type/StateChangeCapture.php
new file mode 100644
index 00000000..9e9ec3e8
--- /dev/null
+++ b/src/MerchantCapture/Capture/Type/StateChangeCapture.php
@@ -0,0 +1,55 @@
+container = $container;
+ add_action('woocommerce_order_status_changed', [$this, "orderStatusChange"], 10, 3);
+ }
+
+ public function orderStatusChange(int $orderId, string $oldStatus, string $newStatus)
+ {
+ $stateChangeCaptureEnabled = $this->container->get('merchant.manual_capture.on_status_change_enabled');
+ if (empty($stateChangeCaptureEnabled) || $stateChangeCaptureEnabled === 'no') {
+ return;
+ }
+
+ if (!in_array($oldStatus, $this->container->get('merchant.manual_capture.void_statuses'))) {
+ return;
+ }
+
+ if (in_array($newStatus, [SharedDataDictionary::STATUS_PROCESSING, SharedDataDictionary::STATUS_COMPLETED])) {
+ $this->capturePayment($orderId);
+ return;
+ }
+
+ if ($newStatus === SharedDataDictionary::STATUS_CANCELLED) {
+ $this->voidPayment($orderId);
+ }
+ }
+
+ protected function capturePayment(int $orderId)
+ {
+ ($this->container->get(CapturePayment::class))($orderId);
+ }
+
+ protected function voidPayment(int $orderId)
+ {
+ ($this->container->get(VoidPayment::class))($orderId);
+ }
+}
diff --git a/src/MerchantCapture/ManualCaptureStatus.php b/src/MerchantCapture/ManualCaptureStatus.php
new file mode 100644
index 00000000..06c34985
--- /dev/null
+++ b/src/MerchantCapture/ManualCaptureStatus.php
@@ -0,0 +1,14 @@
+ static function () {
+ $captureType = get_option('mollie-payments-for-woocommerce_place_payment_onhold');
+ return $captureType === 'later_capture';
+ },
+ 'merchant.manual_capture.supported_methods' => static function () {
+ return ['mollie_wc_gateway_creditcard'];
+ },
+ 'merchant.manual_capture.void_statuses' => static function () {
+ return apply_filters('mollie_wc_gateway_void_order_state', [SharedDataDictionary::STATUS_ON_HOLD]);
+ },
+ 'merchant.manual_capture.capture_statuses' => static function () {
+ return apply_filters('mollie_wc_gateway_capture_order_state', [SharedDataDictionary::STATUS_ON_HOLD]);
+ },
+ 'merchant.manual_capture.is_authorized' => static function ($container) {
+ return static function (WC_Order $order) use ($container) {
+ $orderIsAuthorized = $order->get_meta(
+ self::ORDER_PAYMENT_STATUS_META_KEY
+ ) === ManualCaptureStatus::STATUS_AUTHORIZED;
+ $isManualCaptureMethod = in_array(
+ $order->get_payment_method(),
+ $container->get('merchant.manual_capture.supported_methods')
+ );
+
+ return $isManualCaptureMethod && $orderIsAuthorized;
+ };
+ },
+ 'merchant.manual_capture.is_waiting' => static function ($container) {
+ return static function (WC_Order $order) use ($container) {
+ $orderIsWaiting = $order->get_meta(
+ self::ORDER_PAYMENT_STATUS_META_KEY
+ ) === ManualCaptureStatus::STATUS_WAITING;
+ $isManualCaptureMethod = in_array(
+ $order->get_payment_method(),
+ $container->get('merchant.manual_capture.supported_methods')
+ );
+
+ return $isManualCaptureMethod && $orderIsWaiting;
+ };
+ },
+ 'merchant.manual_capture.can_capture_the_order' => static function ($container) {
+ return static function (WC_Order $order) use ($container) {
+ $orderIsAuthorized = $order->get_meta(
+ self::ORDER_PAYMENT_STATUS_META_KEY
+ ) === ManualCaptureStatus::STATUS_AUTHORIZED;
+ $isManualCaptureMethod = in_array(
+ $order->get_payment_method(),
+ $container->get('merchant.manual_capture.supported_methods')
+ );
+ $isCorrectState = in_array(
+ $order->get_status(),
+ $container->get('merchant.manual_capture.capture_statuses')
+ );
+ return $isManualCaptureMethod && $orderIsAuthorized && $isCorrectState;
+ };
+ },
+ 'merchant.manual_capture.on_status_change_enabled' => static function () {
+ return get_option('mollie-payments-for-woocommerce_capture_or_void', false);
+ },
+ CapturePayment::class => static function ($container) {
+ return static function (int $orderId) use ($container) {
+ /** @var Api $api */
+ $api = $container->get('SDK.api_helper');
+
+ /** @var Settings $settings */
+ $settings = $container->get('settings.settings_helper');
+
+ /** @var Logger $logger */
+ $logger = $container->get(Logger::class);
+
+ $pluginId = $container->get('shared.plugin_id');
+
+ return (new CapturePayment($orderId, $api, $settings, $logger, $pluginId))();
+ };
+ },
+ VoidPayment::class => static function ($container) {
+ return static function (int $orderId) use ($container) {
+ /** @var Api $api */
+ $api = $container->get('SDK.api_helper');
+
+ /** @var Settings $settings */
+ $settings = $container->get('settings.settings_helper');
+
+ /** @var Logger $logger */
+ $logger = $container->get(Logger::class);
+
+ $pluginId = $container->get('shared.plugin_id');
+
+ return (new VoidPayment($orderId, $api, $settings, $logger, $pluginId))();
+ };
+ },
+ ];
+ }
+
+ public function run(ContainerInterface $container): bool
+ {
+ $pluginId = $container->get('shared.plugin_id');
+ add_action($pluginId . '_after_webhook_action', static function (Payment $payment, WC_Order $order) use ($container) {
+ if ($payment->isAuthorized()) {
+ if (!$payment->getAmountCaptured() == 0.0) {
+ return;
+ }
+ $order->set_status(SharedDataDictionary::STATUS_ON_HOLD);
+ $order->update_meta_data(self::ORDER_PAYMENT_STATUS_META_KEY, ManualCaptureStatus::STATUS_AUTHORIZED);
+ $order->save();
+ } elseif ($payment->isPaid() && ($container->get('merchant.manual_capture.is_waiting'))($order)) {
+ $order->update_meta_data(self::ORDER_PAYMENT_STATUS_META_KEY, ManualCaptureStatus::STATUS_CAPTURED);
+ $order->save();
+ }
+ }, 10, 2);
+
+ add_action('woocommerce_order_refunded', static function (int $orderId) use ($container) {
+ $order = wc_get_order($orderId);
+ if (!is_a($order, WC_Order::class)) {
+ return;
+ }
+ $merchantCanCapture = ($container->get('merchant.manual_capture.is_authorized'))($order);
+ if ($merchantCanCapture) {
+ ($container->get(VoidPayment::class))($order->get_id());
+ }
+ });
+ add_action('woocommerce_order_actions_start', static function (int $orderId) use ($container) {
+ $order = wc_get_order($orderId);
+ if (!is_a($order, WC_Order::class)) {
+ return;
+ }
+ $paymentStatus = $order->get_meta(MerchantCaptureModule::ORDER_PAYMENT_STATUS_META_KEY, true);
+ $actionBlockParagraphs = [];
+
+ ob_start();
+ (new StatusRenderer())($paymentStatus);
+
+ $actionBlockParagraphs[] = ob_get_clean();
+ if (($container->get('merchant.manual_capture.can_capture_the_order'))($order)) {
+ $actionBlockParagraphs[] = __(
+ 'To capture the authorized payment, select capture action from the list below.',
+ 'mollie-payments-for-woocommerce'
+ );
+ } elseif (($container->get('merchant.manual_capture.is_authorized'))($order)) {
+ $actionBlockParagraphs[] = __(
+ 'Before capturing the authorized payment, ensure to set the order status to On Hold.',
+ 'mollie-payments-for-woocommerce'
+ );
+ }
+ (new OrderActionBlock())($actionBlockParagraphs);
+ });
+ add_filter(
+ 'mollie_wc_gateway_disable_ship_and_capture',
+ static function ($disableShipAndCapture, WC_Order $order) use ($container) {
+ if ($disableShipAndCapture) {
+ return true;
+ }
+ return $container->get('merchant.manual_capture.is_waiting')($order);
+ },
+ 10,
+ 2
+ );
+ new OrderListPaymentColumn();
+ new ManualCapture($container);
+ new StateChangeCapture($container);
+ return true;
+ }
+}
diff --git a/src/MerchantCapture/OrderListPaymentColumn.php b/src/MerchantCapture/OrderListPaymentColumn.php
new file mode 100644
index 00000000..6447336b
--- /dev/null
+++ b/src/MerchantCapture/OrderListPaymentColumn.php
@@ -0,0 +1,56 @@
+ $column) {
+ $newColumns[$columnId] = $column;
+ if ($columnId === 'order_number') {
+ $newColumns['mollie_capture_payment_status'] = __(
+ 'Payment Status',
+ 'mollie-payments-for-woocommerce'
+ );
+ $mollieColumnAdded = true;
+ }
+ }
+
+ if (!$mollieColumnAdded) {
+ $newColumns['mollie_capture_payment_status'] = __('Payment Status', 'mollie-payments-for-woocommerce');
+ }
+
+ return $newColumns;
+ }
+
+ public function renderColumnValue(string $column, int $orderId)
+ {
+ if ($column !== 'mollie_capture_payment_status') {
+ return;
+ }
+ /** @var \WC_Order $order */
+ $order = wc_get_order($orderId);
+
+ if (!is_a($order, \WC_Order::class)) {
+ return;
+ }
+
+ $molliePaymentStatus = $order->get_meta(MerchantCaptureModule::ORDER_PAYMENT_STATUS_META_KEY);
+
+ (new StatusRenderer())($molliePaymentStatus);
+ }
+}
diff --git a/src/MerchantCapture/UI/OrderActionBlock.php b/src/MerchantCapture/UI/OrderActionBlock.php
new file mode 100644
index 00000000..d0fbd656
--- /dev/null
+++ b/src/MerchantCapture/UI/OrderActionBlock.php
@@ -0,0 +1,19 @@
+";
+ foreach ($paragraphs as $paragraph) {
+ ?>
+
= wp_kses($paragraph, ['mark' => ['class' => []], 'span' => []]); ?>
+ ';
+ }
+}
diff --git a/src/MerchantCapture/UI/StatusButton.php b/src/MerchantCapture/UI/StatusButton.php
new file mode 100644
index 00000000..063217a5
--- /dev/null
+++ b/src/MerchantCapture/UI/StatusButton.php
@@ -0,0 +1,15 @@
+
+
= esc_html($text); ?>
+ pluginId . '_after_webhook_action', $payment, $order);
// Status 200
}
/**
diff --git a/src/Payment/MolliePayment.php b/src/Payment/MolliePayment.php
index 3d955c79..82636f65 100644
--- a/src/Payment/MolliePayment.php
+++ b/src/Payment/MolliePayment.php
@@ -453,6 +453,10 @@ public function refund(\WC_Order $order, $orderId, $paymentObject, $amount = nul
return new WP_Error('1', $errorMessage);
}
+ if ($paymentObject->isAuthorized()) {
+ return true;
+ }
+
if (! $paymentObject->isPaid()) {
$errorMessage = "Can not refund payment $paymentObject->id for WooCommerce order $orderId as it is not paid.";
diff --git a/src/Payment/PaymentModule.php b/src/Payment/PaymentModule.php
index 884a3d4b..440968aa 100644
--- a/src/Payment/PaymentModule.php
+++ b/src/Payment/PaymentModule.php
@@ -339,7 +339,7 @@ public function shipAndCaptureOrderAtMollie($order_id)
// To disable automatic shipping and capturing of the Mollie order when a WooCommerce order status is updated to completed,
// store an option 'mollie-payments-for-woocommerce_disableShipOrderAtMollie' with value 1
- if (get_option($this->pluginId . '_' . 'disableShipOrderAtMollie', '0') === '1') {
+ if (apply_filters('mollie_wc_gateway_disable_ship_and_capture', get_option($this->pluginId . '_' . 'disableShipOrderAtMollie', '0') === '1', $order)) {
return;
}
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php
index ea7b53f3..59fc6875 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentService.php
@@ -24,6 +24,9 @@ class PaymentService
{
public const PAYMENT_METHOD_TYPE_ORDER = 'order';
public const PAYMENT_METHOD_TYPE_PAYMENT = 'payment';
+
+ public const PAYMENT_METHOD_TYPE_CAPTURE = 'capture';
+
/**
* @var MolliePaymentGatewayI
*/
@@ -369,8 +372,7 @@ protected function processAsMollieOrder(
: '',
'orderNumber' => isset($data['orderNumber'])
? $data['orderNumber'] : '',
- 'lines' => isset($data['lines']) ? $data['lines'] : '',
- ];
+ 'lines' => isset($data['lines']) ? $data['lines'] : '', ];
$this->logger->debug(json_encode($apiCallLog));
$paymentOrder = $paymentObject;
@@ -550,6 +552,7 @@ protected function processPaymentForMollie(
$apiKey
);
}
+
return $paymentObject;
}
diff --git a/src/PaymentMethods/Kbc.php b/src/PaymentMethods/Kbc.php
index 361116ed..5c220cac 100644
--- a/src/PaymentMethods/Kbc.php
+++ b/src/PaymentMethods/Kbc.php
@@ -6,10 +6,10 @@
class Kbc extends AbstractPaymentMethod implements PaymentMethodI
{
-protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
-protected function getConfig(): array
-{
- return [
+ protected const DEFAULT_ISSUERS_DROPDOWN = 'yes';
+ protected function getConfig(): array
+ {
+ return [
'id' => 'kbc',
'defaultTitle' => __('KBC/CBC Payment Button', 'mollie-payments-for-woocommerce'),
'settingsDescription' => '',
@@ -23,10 +23,10 @@ protected function getConfig(): array
'filtersOnBuild' => false,
'confirmationDelayed' => true,
'SEPA' => true,
- ];
-}
+ ];
+ }
-public function getFormFields($generalFormFields): array
+ public function getFormFields($generalFormFields): array
{
$paymentMethodFormFieds = [
'issuers_dropdown_shown' => [
diff --git a/src/SDK/WordPressHttpAdapter.php b/src/SDK/WordPressHttpAdapter.php
index 1bffd185..5337cd0c 100644
--- a/src/SDK/WordPressHttpAdapter.php
+++ b/src/SDK/WordPressHttpAdapter.php
@@ -18,6 +18,7 @@ class WordPressHttpAdapter implements MollieHttpAdapterInterface
* HTTP status code for an empty ok response.
*/
const HTTP_NO_CONTENT = 204;
+ const PAYMENT_HTTP_NO_CONTENT = 202;
/**
* @param string $httpMethod
@@ -65,7 +66,7 @@ protected function parseResponse($response)
$statusCode = wp_remote_retrieve_response_code($response);
$httpBody = wp_remote_retrieve_body($response);
if (empty($httpBody)) {
- if ($statusCode === self::HTTP_NO_CONTENT) {
+ if ($statusCode === self::HTTP_NO_CONTENT || $statusCode === self::PAYMENT_HTTP_NO_CONTENT) {
return null;
}
From 5732e5ce2e68503a19a15d955c6f0ced042881bc Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 24 Oct 2023 10:30:57 +0200
Subject: [PATCH 14/23] Remove payment method type capture const from
PaymentService
---
src/Payment/PaymentService.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php
index 59fc6875..cb9be0cd 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentService.php
@@ -25,8 +25,6 @@ class PaymentService
public const PAYMENT_METHOD_TYPE_ORDER = 'order';
public const PAYMENT_METHOD_TYPE_PAYMENT = 'payment';
- public const PAYMENT_METHOD_TYPE_CAPTURE = 'capture';
-
/**
* @var MolliePaymentGatewayI
*/
From 257ce096734f136be41202351daac430521e7d81 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Tue, 24 Oct 2023 11:07:40 +0200
Subject: [PATCH 15/23] Fix CS
---
src/Gateway/MolliePaymentGateway.php | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php
index d45d98e9..7cf669eb 100644
--- a/src/Gateway/MolliePaymentGateway.php
+++ b/src/Gateway/MolliePaymentGateway.php
@@ -274,17 +274,17 @@ public function isValidForUse(): bool
$test_mode = $this->dataService->isTestModeEnabled();
$this->errors[] = ($test_mode ? __(
- 'Test mode enabled.',
- 'mollie-payments-for-woocommerce'
- ) . ' ' : '') . sprintf(
+ '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'
- ),
- '',
- ''
- );
+ __(
+ 'No API key provided. Please %1$sset you Mollie API key%2$s first.',
+ 'mollie-payments-for-woocommerce'
+ ),
+ '',
+ ''
+ );
return false;
}
@@ -813,7 +813,9 @@ public function displayInstructions(
$admin_instructions = false,
$plain_text = false
) {
- if (($admin_instructions && !$this::$alreadyDisplayedAdminInstructions)
+
+ if (
+ ($admin_instructions && !$this::$alreadyDisplayedAdminInstructions)
|| (!$admin_instructions && !$this::$alreadyDisplayedCustomerInstructions)
) {
$order_payment_method = $order->get_payment_method();
From 207c5f6a01e435484ca71b553acf8ebe40e0dbd4 Mon Sep 17 00:00:00 2001
From: carmenmaymo
Date: Tue, 24 Oct 2023 11:16:33 +0200
Subject: [PATCH 16/23] Update version and pot
---
languages/en_GB.pot | 112 ++++++++++++++++------------
mollie-payments-for-woocommerce.php | 2 +-
2 files changed, 64 insertions(+), 50 deletions(-)
diff --git a/languages/en_GB.pot b/languages/en_GB.pot
index ecfbc1ea..eb67e741 100644
--- a/languages/en_GB.pot
+++ b/languages/en_GB.pot
@@ -2,13 +2,14 @@
# This file is distributed under the GPLv2 or later.
msgid ""
msgstr ""
-"Project-Id-Version: Mollie Payments for WooCommerce 7.4.0\n"
-"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/WooCommerce\n"
+"Project-Id-Version: Mollie Payments for WooCommerce 7.4.1-beta\n"
+"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/html\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-10-20T15:51:47+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.8.1\n"
"X-Domain: mollie-payments-for-woocommerce\n"
@@ -508,7 +509,7 @@ msgstr ""
#: src/Buttons/ApplePayButton/AppleAjaxRequests.php:700
#: src/Buttons/PayPalButton/PayPalAjaxRequests.php:113
#: src/Buttons/PayPalButton/PayPalAjaxRequests.php:157
-#: src/Payment/PaymentService.php:716
+#: src/Payment/PaymentService.php:718
msgid "Could not create %s payment."
msgstr ""
@@ -520,85 +521,89 @@ msgstr ""
msgid "%1$sApple Pay Validation Error%2$s Check %3$sApple Server requirements page%4$s to fix it in order to make the Apple Pay button work"
msgstr ""
-#: src/Gateway/GatewayModule.php:655
+#: src/Gateway/GatewayModule.php:326
+msgid "Mollie Payment Details"
+msgstr ""
+
+#: src/Gateway/GatewayModule.php:682
msgid "Error processing %1$s payment, the %2$s field is required."
msgstr ""
-#: src/Gateway/GatewayModule.php:669
+#: src/Gateway/GatewayModule.php:696
msgid "Please enter your %1$s, this is required for %2$s payments"
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:269
+#: src/Gateway/MolliePaymentGateway.php:276
#: src/Settings/Page/MollieSettingsPage.php:314
msgid "Test mode enabled."
msgstr ""
#. translators: The surrounding %s's Will be replaced by a link to the global setting page
-#: src/Gateway/MolliePaymentGateway.php:274
+#: src/Gateway/MolliePaymentGateway.php:281
msgid "No API key provided. Please %1$sset you Mollie API key%2$s first."
msgstr ""
#. translators: Placeholder 1: payment method title. The surrounding %s's Will be replaced by a link to the Mollie profile
-#: src/Gateway/MolliePaymentGateway.php:289
+#: src/Gateway/MolliePaymentGateway.php:296
msgid "%1$s not enabled in your Mollie profile. You can enable it by editing your %2$sMollie profile%3$s."
msgstr ""
#. translators: Placeholder 1: WooCommerce currency, placeholder 2: Supported Mollie currencies
-#: src/Gateway/MolliePaymentGateway.php:304
+#: src/Gateway/MolliePaymentGateway.php:311
msgid "Current shop currency %1$s not supported by Mollie. Read more about %2$ssupported currencies and payment methods.%3$s "
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:575
+#: src/Gateway/MolliePaymentGateway.php:582
msgid "You have cancelled your payment. Please complete your order with a different payment method."
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:596
-#: src/Gateway/MolliePaymentGateway.php:610
+#: src/Gateway/MolliePaymentGateway.php:603
+#: src/Gateway/MolliePaymentGateway.php:617
msgid "Your payment was not successful. Please complete your order with a different payment method."
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:646
+#: src/Gateway/MolliePaymentGateway.php:653
msgid "Could not load order %s"
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:899
+#: src/Gateway/MolliePaymentGateway.php:918
msgid "Order cancelled"
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Gateway/MolliePaymentGateway.php:933
+#: src/Gateway/MolliePaymentGateway.php:952
msgid "%1$s payment still pending (%2$s) but customer already returned to the store. Status should be updated automatically in the future, if it doesn't this might indicate a communication issue between the site and Mollie."
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:939
+#: src/Gateway/MolliePaymentGateway.php:958
#: src/Payment/MollieObject.php:682
#: src/Payment/MollieObject.php:714
#: src/Payment/MollieOrder.php:281
#: src/Payment/MollieOrder.php:338
-#: src/Payment/MollieOrder.php:382
-#: src/Payment/MollieOrder.php:463
-#: src/Payment/MollieOrder.php:534
-#: src/Payment/MollieOrder.php:877
-#: src/Payment/MollieOrderService.php:171
-#: src/Payment/MollieOrderService.php:437
-#: src/Payment/MollieOrderService.php:500
-#: src/Payment/MollieOrderService.php:714
+#: src/Payment/MollieOrder.php:389
+#: src/Payment/MollieOrder.php:470
+#: src/Payment/MollieOrder.php:541
+#: src/Payment/MollieOrder.php:884
+#: src/Payment/MollieOrderService.php:172
+#: src/Payment/MollieOrderService.php:438
+#: src/Payment/MollieOrderService.php:501
+#: src/Payment/MollieOrderService.php:715
#: src/Payment/MolliePayment.php:236
#: src/Payment/MolliePayment.php:323
#: src/Payment/MolliePayment.php:399
#: src/Payment/MolliePayment.php:423
-#: src/Payment/PaymentService.php:801
+#: src/Payment/PaymentService.php:803
#: src/Subscription/MollieSepaRecurringGateway.php:137
#: src/Subscription/MollieSepaRecurringGateway.php:204
#: src/Subscription/MollieSubscriptionGateway.php:458
msgid "test mode"
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:950
+#: src/Gateway/MolliePaymentGateway.php:969
msgid ", payment pending."
msgstr ""
-#: src/Gateway/MolliePaymentGateway.php:982
+#: src/Gateway/MolliePaymentGateway.php:1001
msgid "Your order has been cancelled."
msgstr ""
@@ -766,72 +771,72 @@ msgid "Order authorized using %1$s payment (%2$s). Set order to completed in Woo
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrder.php:380
+#: src/Payment/MollieOrder.php:387
msgid "Order completed at Mollie for %1$s order (%2$s). At least one order line completed. Remember: Completed status for an order at Mollie is not the same as Completed status in WooCommerce!"
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrder.php:461
+#: src/Payment/MollieOrder.php:468
msgid "%1$s order (%2$s) cancelled ."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrder.php:532
+#: src/Payment/MollieOrder.php:539
msgid "%1$s order expired (%2$s) but not cancelled because of another pending payment (%3$s)."
msgstr ""
-#: src/Payment/MollieOrder.php:627
+#: src/Payment/MollieOrder.php:634
msgctxt "Order note error"
msgid "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."
msgstr ""
-#: src/Payment/MollieOrder.php:759
+#: src/Payment/MollieOrder.php:766
msgctxt "Order note error"
msgid "Can not refund order amount that has status %1$s at Mollie."
msgstr ""
-#: src/Payment/MollieOrder.php:781
+#: src/Payment/MollieOrder.php:788
msgid "Amount refund of %1$s%2$s refunded in WooCommerce and at Mollie.%3$s Refund ID: %4$s."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrder.php:872
+#: src/Payment/MollieOrder.php:879
msgid "%1$s order (%2$s) expired ."
msgstr ""
-#: src/Payment/MollieOrder.php:1095
+#: src/Payment/MollieOrder.php:1102
msgid "%1$sx %2$s cancelled for %3$s%4$s in WooCommerce and at Mollie."
msgstr ""
-#: src/Payment/MollieOrder.php:1119
+#: src/Payment/MollieOrder.php:1126
msgid "%1$sx %2$s refunded for %3$s%4$s in WooCommerce and at Mollie.%5$s Refund ID: %6$s."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment status, placeholder 3: payment ID
-#: src/Payment/MollieOrderService.php:168
+#: src/Payment/MollieOrderService.php:169
msgid "%1$s payment %2$s (%3$s), not processed."
msgstr ""
-#: src/Payment/MollieOrderService.php:400
+#: src/Payment/MollieOrderService.php:401
msgid "New chargeback %s processed! Order note and order status updated."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrderService.php:432
+#: src/Payment/MollieOrderService.php:433
msgid "%1$s payment charged back via Mollie (%2$s). You will need to manually review the payment (and adjust product stocks if you use it)."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrderService.php:494
+#: src/Payment/MollieOrderService.php:495
msgid "%1$s payment charged back via Mollie (%2$s). Subscription status updated, please review (and adjust product stocks if you use it)."
msgstr ""
#. translators: Placeholder 1: payment method title, placeholder 2: payment ID
-#: src/Payment/MollieOrderService.php:701
+#: src/Payment/MollieOrderService.php:702
msgid "%1$s payment %2$s via Mollie (%3$s %4$s). You will need to manually review the payment (and adjust product stocks if you use it)."
msgstr ""
-#: src/Payment/MollieOrderService.php:814
+#: src/Payment/MollieOrderService.php:815
msgid "New refund %s processed in Mollie Dashboard! Order note added, but order not updated."
msgstr ""
@@ -930,35 +935,39 @@ msgctxt "Order note info"
msgid "Order could not be canceled at Mollie, because order status is "
msgstr ""
-#: src/Payment/PaymentService.php:622
+#: src/Payment/PaymentService.php:624
msgid "Subscription switch failed, no valid mandate found. Place a completely new order to change your subscription."
msgstr ""
-#: src/Payment/PaymentService.php:628
+#: src/Payment/PaymentService.php:630
msgid "Failed switching subscriptions, no valid mandate."
msgstr ""
-#: src/Payment/PaymentService.php:638
+#: src/Payment/PaymentService.php:640
msgid "Order completed internally because of an existing valid mandate at Mollie."
msgstr ""
-#: src/Payment/PaymentService.php:779
+#: src/Payment/PaymentService.php:781
#: src/Subscription/MollieSepaRecurringGateway.php:126
#: src/Subscription/MollieSubscriptionGateway.php:449
msgid "Awaiting payment confirmation."
msgstr ""
#. translators: Placeholder 1: Payment method title, placeholder 2: payment ID
-#: src/Payment/PaymentService.php:799
+#: src/Payment/PaymentService.php:801
#: src/Subscription/MollieSepaRecurringGateway.php:135
#: src/Subscription/MollieSubscriptionGateway.php:456
msgid "%1$s payment started (%2$s)."
msgstr ""
-#: src/Payment/PaymentService.php:869
+#: src/Payment/PaymentService.php:871
msgid "Payment failed due to: Mollie is out of service. Please try again later."
msgstr ""
+#: src/Payment/PaymentService.php:894
+msgid "Payment failed due to: The payment was declined due to suspected fraud."
+msgstr ""
+
#: src/Payment/RefundLineItemsBuilder.php:126
msgid "Mollie doesn't allow a partial refund of the full amount or quantity of at least one order line. Trying to process this as an amount refund instead."
msgstr ""
@@ -1149,6 +1158,7 @@ msgstr ""
#: src/PaymentMethods/Ideal.php:17
#: src/PaymentMethods/Ideal.php:55
#: src/PaymentMethods/Kbc.php:16
+#: src/PaymentMethods/Kbc.php:60
msgid "Select your bank"
msgstr ""
@@ -1274,6 +1284,10 @@ msgstr ""
msgid "If you disable this, a dropdown with various KBC/CBC banks will not be shown in the WooCommerce checkout, so users will select a KBC/CBC bank on the Mollie payment page after checkout."
msgstr ""
+#: src/PaymentMethods/Kbc.php:54
+msgid "This text will be displayed as the first option in the KBC/CBC issuers drop down, if nothing is entered, 'Select your bank' will be shown. Only if the above 'Show KBC/CBC banks dropdown' is enabled."
+msgstr ""
+
#: src/PaymentMethods/Klarna.php:13
msgid "Pay with Klarna"
msgstr ""
@@ -1838,7 +1852,7 @@ msgid "Initial order status"
msgstr ""
#: src/Settings/General/MollieGeneralSettings.php:292
-msgid "Some payment methods take longer than a few hours to complete. The initial order state is then set to '%1$s'. This ensures the order is not cancelled when the setting %2$s is used."
+msgid "Some payment methods take longer than a few hours to complete. The initial order state is then set to '%1$s'. This ensures the order is not cancelled when the setting %2$s is used. This will also prevent the order to be canceled when expired."
msgstr ""
#: src/Settings/Page/MollieSettingsPage.php:112
diff --git a/mollie-payments-for-woocommerce.php b/mollie-payments-for-woocommerce.php
index 4ff8709a..fcadd0a9 100644
--- a/mollie-payments-for-woocommerce.php
+++ b/mollie-payments-for-woocommerce.php
@@ -3,7 +3,7 @@
* Plugin Name: Mollie Payments for WooCommerce
* Plugin URI: https://www.mollie.com
* Description: Accept payments in WooCommerce with the official Mollie plugin
- * Version: 7.4.0
+ * Version: 7.4.1-beta
* Author: Mollie
* Author URI: https://www.mollie.com
* Requires at least: 5.0
From 71b2253d6652a4ff5a00ce6ffb8a5fe2a073440d Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 24 Oct 2023 13:42:24 +0200
Subject: [PATCH 17/23] Fix NoticeModule namespace.
---
src/Notice/NoticeModule.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Notice/NoticeModule.php b/src/Notice/NoticeModule.php
index 49861917..e2cb7cc5 100644
--- a/src/Notice/NoticeModule.php
+++ b/src/Notice/NoticeModule.php
@@ -6,8 +6,8 @@
namespace Mollie\WooCommerce\Notice;
-use Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
-use Inpsyde\Modularity\Module\ServiceModule;
+use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
+use Mollie\WooCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
class NoticeModule implements ServiceModule
{
From dd902c70cc6b08fddb7c4dffa6d27d247aa041cc Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Tue, 24 Oct 2023 13:56:36 +0200
Subject: [PATCH 18/23] Set minimum expiry time to 10.
---
src/Settings/General/MollieGeneralSettings.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Settings/General/MollieGeneralSettings.php b/src/Settings/General/MollieGeneralSettings.php
index b0d018b9..4673e689 100644
--- a/src/Settings/General/MollieGeneralSettings.php
+++ b/src/Settings/General/MollieGeneralSettings.php
@@ -264,8 +264,8 @@ public function gatewayFormFields(
'mollie-payments-for-woocommerce'
)
),
- 'custom_attributes' => ['step' => '1', 'min' => '0', 'max' => '526000'],
- 'default' => '0',
+ 'custom_attributes' => ['step' => '1', 'min' => '10', 'max' => '526000'],
+ 'default' => '10',
'desc_tip' => false,
],
];
From bdbd3dd3c47ea215c90efde2538bb0cfe2e6573f Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Wed, 25 Oct 2023 08:48:28 +0200
Subject: [PATCH 19/23] Remove dueDate description.
---
src/Settings/General/MollieGeneralSettings.php | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/Settings/General/MollieGeneralSettings.php b/src/Settings/General/MollieGeneralSettings.php
index 4673e689..a611f7e0 100644
--- a/src/Settings/General/MollieGeneralSettings.php
+++ b/src/Settings/General/MollieGeneralSettings.php
@@ -258,12 +258,6 @@ public function gatewayFormFields(
'order_dueDate' => [
'title' => sprintf(__('Expiry time', 'mollie-payments-for-woocommerce')),
'type' => 'number',
- 'description' => sprintf(
- __(
- 'Number of MINUTES after the order will expire and will be canceled at Mollie and WooCommerce. A value of 0 means no expiry time will be considered.',
- 'mollie-payments-for-woocommerce'
- )
- ),
'custom_attributes' => ['step' => '1', 'min' => '10', 'max' => '526000'],
'default' => '10',
'desc_tip' => false,
From 69ed8f7d393d5052982d87ca2b967c5f06a8942f Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Thu, 26 Oct 2023 11:11:19 +0200
Subject: [PATCH 20/23] Replace addNotice with wc_print_notice
---
src/Payment/PaymentService.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php
index c627d9e9..5032d931 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentService.php
@@ -717,7 +717,9 @@ protected function reportPaymentCreationFailure($orderId, $e, $paymentMethodId):
$message .= 'hii ' . $e->getMessage();
}
- $this->notice->addNotice('error', $message);
+ add_action('before_woocommerce_pay_form', function() use($message){
+ wc_print_notice($message, 'error');
+ });
}
/**
From 7fc11568299ff45ed7c1a20a1e0ad6cb32fe9d53 Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Thu, 26 Oct 2023 11:18:55 +0200
Subject: [PATCH 21/23] Code style.
---
src/Payment/PaymentService.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Payment/PaymentService.php b/src/Payment/PaymentService.php
index 5032d931..20462e9c 100644
--- a/src/Payment/PaymentService.php
+++ b/src/Payment/PaymentService.php
@@ -717,7 +717,7 @@ protected function reportPaymentCreationFailure($orderId, $e, $paymentMethodId):
$message .= 'hii ' . $e->getMessage();
}
- add_action('before_woocommerce_pay_form', function() use($message){
+ add_action('before_woocommerce_pay_form', static function () use ($message) {
wc_print_notice($message, 'error');
});
}
From 0e82e62c676252f0482bd950755d5091021cb98b Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Thu, 26 Oct 2023 12:10:13 +0200
Subject: [PATCH 22/23] Change the description, fix banktransfer and skip
gateways wihout expiry
---
src/Payment/PaymentModule.php | 5 +++++
src/Settings/General/MollieGeneralSettings.php | 6 ++++++
2 files changed, 11 insertions(+)
diff --git a/src/Payment/PaymentModule.php b/src/Payment/PaymentModule.php
index 884a3d4b..055ada90 100644
--- a/src/Payment/PaymentModule.php
+++ b/src/Payment/PaymentModule.php
@@ -167,6 +167,11 @@ public function cancelOrderOnExpiryDate()
foreach ($classNames as $gateway) {
$gatewayName = strtolower($gateway) . '_settings';
$gatewaySettings = get_option($gatewayName);
+
+ if (empty($gatewaySettings["activate_expiry_days_setting"]) || $gatewaySettings["activate_expiry_days_setting"] === 'no') {
+ continue;
+ }
+
$heldDuration = isset($gatewaySettings) && isset($gatewaySettings['order_dueDate']) ? $gatewaySettings['order_dueDate'] : 0;
if ($heldDuration < 1) {
diff --git a/src/Settings/General/MollieGeneralSettings.php b/src/Settings/General/MollieGeneralSettings.php
index a611f7e0..d4436375 100644
--- a/src/Settings/General/MollieGeneralSettings.php
+++ b/src/Settings/General/MollieGeneralSettings.php
@@ -259,6 +259,12 @@ public function gatewayFormFields(
'title' => sprintf(__('Expiry time', 'mollie-payments-for-woocommerce')),
'type' => 'number',
'custom_attributes' => ['step' => '1', 'min' => '10', 'max' => '526000'],
+ 'description' => sprintf(
+ __(
+ 'Number of MINUTES after the order will expire and will be canceled at Mollie and WooCommerce.',
+ 'mollie-payments-for-woocommerce'
+ )
+ ),
'default' => '10',
'desc_tip' => false,
],
From c82b9dbeedc6028c56c0946c547892e00ec9fddf Mon Sep 17 00:00:00 2001
From: inpsyde-maticluznar
Date: Thu, 26 Oct 2023 12:12:32 +0200
Subject: [PATCH 23/23] Fix wrong gateway name when canceling the order
---
src/Payment/PaymentModule.php | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/Payment/PaymentModule.php b/src/Payment/PaymentModule.php
index 055ada90..6228d62b 100644
--- a/src/Payment/PaymentModule.php
+++ b/src/Payment/PaymentModule.php
@@ -178,7 +178,7 @@ public function cancelOrderOnExpiryDate()
continue;
}
$heldDurationInSeconds = $heldDuration * 60;
- if ($gateway === 'mollie_wc_gateway_bankTransfer') {
+ if ($gateway === 'Mollie_WC_Gateway_Banktransfer') {
$durationInHours = absint($heldDuration) * 24;
$durationInMinutes = $durationInHours * 60;
$heldDurationInSeconds = $durationInMinutes * 60;
@@ -479,6 +479,12 @@ public function cancelOrderAtMollie($order_id)
*/
public function handleExpiryDateCancelation($paymentMethods)
{
+ add_action(
+ 'init',
+ [$this, 'cancelOrderOnExpiryDate'],
+ 11,
+ 2
+ );
if (!$this->IsExpiryDateEnabled($paymentMethods)) {
as_unschedule_action('mollie_woocommerce_cancel_unpaid_orders');
return;