-
Notifications
You must be signed in to change notification settings - Fork 220
[ECP-8668] Refactor the logic of getting capture mode of payment methods #3286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9d85d2c
ecc908f
929cbfa
ac0f55f
aca68cc
809e0ef
dc407b2
5420dd1
a5a8772
bf84594
802601d
edb15d6
832909a
1aa1a74
bbed102
54b2838
b063542
36f9346
2fd2269
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,10 +14,12 @@ | |
| use Adyen\AdyenException; | ||
| use Adyen\Client; | ||
| use Adyen\ConnectionException; | ||
| use Adyen\Payment\Helper\Util\PaymentMethodUtil; | ||
| use Adyen\Model\Checkout\PaymentMethodsRequest; | ||
| use Adyen\Payment\Logger\AdyenLogger; | ||
| use Adyen\Payment\Model\Config\Source\CaptureMode; | ||
| use Adyen\Payment\Model\Config\Source\RenderMode; | ||
| use Adyen\Payment\Model\Config\Source\SepaFlow; | ||
| use Adyen\Payment\Model\Method\TxVariantFactory; | ||
| use Adyen\Payment\Model\Notification; | ||
| use Adyen\Payment\Model\Ui\Adminhtml\AdyenMotoConfigProvider; | ||
| use Adyen\Payment\Model\Ui\AdyenPayByLinkConfigProvider; | ||
|
|
@@ -54,6 +56,7 @@ class PaymentMethods extends AbstractHelper | |
| const ADYEN_ONE_CLICK = 'adyen_oneclick'; | ||
| const ADYEN_PAY_BY_LINK = 'adyen_pay_by_link'; | ||
| const ADYEN_PAYPAL = 'adyen_paypal'; | ||
| const ADYEN_SEPADIRECTDEBIT = 'adyen_sepadirectdebit'; | ||
| const ADYEN_BOLETO = 'adyen_boleto'; | ||
| const ADYEN_PREFIX = 'adyen_'; | ||
| const ADYEN_CC_VAULT = 'adyen_cc_vault'; | ||
|
|
@@ -114,6 +117,7 @@ class PaymentMethods extends AbstractHelper | |
| * @param ShopperConversionId $generateShopperConversionId | ||
| * @param CheckoutSession $checkoutSession | ||
| * @param RequestInterface $request | ||
| * @param TxVariantFactory $txVariantFactory | ||
| */ | ||
| public function __construct( | ||
| Context $context, | ||
|
|
@@ -134,7 +138,8 @@ public function __construct( | |
| protected readonly Locale $localeHelper, | ||
| protected readonly ShopperConversionId $generateShopperConversionId, | ||
| protected readonly CheckoutSession $checkoutSession, | ||
| protected readonly RequestInterface $request | ||
| protected readonly RequestInterface $request, | ||
| protected readonly TxVariantFactory $txVariantFactory | ||
| ) { | ||
| parent::__construct($context); | ||
| } | ||
|
|
@@ -636,6 +641,17 @@ public function isWalletPaymentMethod(MethodInterface $paymentMethodInstance): b | |
| return boolval($paymentMethodInstance->getConfigData('is_wallet')); | ||
| } | ||
|
|
||
| /** | ||
| * This method returns the `supports_manual_capture` configuration value of a given payment method instance. | ||
| * | ||
| * @param MethodInterface $paymentMethodInstance | ||
| * @return bool | ||
| */ | ||
| public function supportsManualCapture(MethodInterface $paymentMethodInstance): bool | ||
| { | ||
| return boolval($paymentMethodInstance->getConfigData('supports_manual_capture')); | ||
| } | ||
|
|
||
| /** | ||
| * @param MethodInterface $paymentMethodInstance | ||
| * @return bool | ||
|
|
@@ -720,182 +736,102 @@ public function getCcAvailableTypesByAlt(): array | |
|
|
||
| /** | ||
| * Checks whether if the capture mode is auto on an order with the given notification `paymentMethod`. | ||
| * Note that, only a `notificationPaymentMethod` related to the order should be provided. | ||
| * | ||
| * @param Order $order Order object | ||
| * @param string $notificationPaymentMethod `paymentMethod` provided on the webhook of the given order | ||
| * @return bool | ||
| */ | ||
| public function isAutoCapture(Order $order, string $notificationPaymentMethod): bool | ||
| { | ||
| // TODO::Add a validation checking `$notificationPaymentMethod` belongs to the correct order (webhook) or not. | ||
|
|
||
| $payment = $order->getPayment(); | ||
| $paymentMethodInstance = $payment->getMethodInstance(); | ||
|
|
||
| // validate if payment methods allows manual capture | ||
| if (PaymentMethodUtil::isManualCaptureSupported($notificationPaymentMethod)) { | ||
| $captureMode = trim( | ||
| (string) $this->configHelper->getConfigData( | ||
| 'capture_mode', | ||
| 'adyen_abstract', | ||
| $order->getStoreId() | ||
| ) | ||
| ); | ||
| $sepaFlow = trim( | ||
| (string) $this->configHelper->getConfigData( | ||
| 'sepa_flow', | ||
| 'adyen_abstract', | ||
| $order->getStoreId() | ||
| ) | ||
| ); | ||
| $paymentCode = $order->getPayment()->getMethod(); | ||
| $autoCaptureOpenInvoice = $this->configHelper->getAutoCaptureOpenInvoice($order->getStoreId()); | ||
| $manualCapturePayPal = trim( | ||
| (string) $this->configHelper->getConfigData( | ||
| 'paypal_capture_mode', | ||
| 'adyen_abstract', | ||
| $order->getStoreId() | ||
| ) | ||
| $isAutoCapture = true; | ||
|
|
||
| /* | ||
| * First, validate the incoming tx_variant supports manual capture on the tx_variant level. | ||
| * Then check configuration and payment method specific settings. | ||
| */ | ||
| if ($this->txVariantSupportsManualCapture($notificationPaymentMethod)) { | ||
| $captureModePos = $this->configHelper->getAdyenPosCloudConfigData( | ||
| 'capture_mode_pos', | ||
| $order->getStoreId() | ||
| ); | ||
|
|
||
| /* | ||
| * if you are using authcap the payment method is manual. | ||
| * There will be a capture send to indicate if payment is successful | ||
| */ | ||
| if ($notificationPaymentMethod == "sepadirectdebit") { | ||
| if ($sepaFlow == "authcap") { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'Manual Capture is applied for sepa because it is in authcap flow', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return false; | ||
| // Use order payment method to evaluate the capture mode instead of notification payment method for POS | ||
| if ($order->getPayment()->getMethod() === AdyenPosCloudConfigProvider::CODE && | ||
| $captureModePos === CaptureMode::CAPTURE_MODE_MANUAL) { | ||
| // Evaluate capture mode of POS payments based on the order's `paymentMethod` field and configuration | ||
| $isAutoCapture = false; | ||
| } else { | ||
| // Evaluate capture mode of ECOM payments based on the webhook's `paymentMethod` field | ||
|
|
||
| $sepaFlow = $this->configHelper->getSepaFlow($order->getStoreId()); | ||
| $isPaypalManualCapture = $this->configHelper->isPaypalManualCapture($order->getStoreId()); | ||
| $autoCaptureOpenInvoice = $this->configHelper->getAutoCaptureOpenInvoice($order->getStoreId()); | ||
| $captureMode = $this->configHelper->getCaptureMode($order->getStoreId()); | ||
|
|
||
| /* | ||
| * `adyenTxVariant` can be `null` if a card variant is provided. In this case, skip payment | ||
| * method specific checks and use the global capture mode setting. | ||
| */ | ||
| $adyenTxVariant = $this->txVariantFactory->create(['txVariant' => $notificationPaymentMethod]); | ||
|
Comment on lines
+752
to
+775
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a redundant instantiation of the
Comment on lines
+752
to
+775
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
|
||
| if (isset($adyenTxVariant)) { | ||
| $webhookMethodInstance = $adyenTxVariant->getMethodInstance(); | ||
| $webhookMethodCode = $webhookMethodInstance->getCode(); | ||
|
|
||
| if (($webhookMethodCode === self::ADYEN_SEPADIRECTDEBIT && $sepaFlow === SepaFlow::SEPA_FLOW_AUTHCAP) || | ||
| ($webhookMethodCode === self::ADYEN_PAYPAL && $isPaypalManualCapture) || | ||
| ($this->isOpenInvoice($webhookMethodInstance) && !$autoCaptureOpenInvoice) || | ||
| ($captureMode === CaptureMode::CAPTURE_MODE_MANUAL) | ||
| ) { | ||
| $isAutoCapture = false; | ||
| } | ||
| } else { | ||
| // payment method ideal, cash adyen_boleto has direct capture | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method does not allow manual capture.(2) paymentCode:' . | ||
| $paymentCode . ' paymentMethod:' . $notificationPaymentMethod . ' sepaFLow:' . $sepaFlow, | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return true; | ||
| if ($captureMode === CaptureMode::CAPTURE_MODE_MANUAL) { | ||
| $isAutoCapture = false; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if ($paymentCode == "adyen_pos_cloud") { | ||
| $captureModePos = $this->configHelper->getAdyenPosCloudConfigData( | ||
| 'capture_mode_pos', | ||
| $order->getStoreId() | ||
| ); | ||
| if (strcmp((string) $captureModePos, 'auto') === 0) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method is POS Cloud and configured to be working as auto capture ', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return true; | ||
| } elseif (strcmp((string) $captureModePos, 'manual') === 0) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method is POS Cloud and configured to be working as manual capture ', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return false; | ||
| } | ||
| } | ||
| return $isAutoCapture; | ||
| } | ||
|
Comment on lines
744
to
+797
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The refactored |
||
|
|
||
| // if auto capture mode for openinvoice is turned on then use auto capture | ||
| if ($autoCaptureOpenInvoice && $this->isOpenInvoice($paymentMethodInstance)) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method is configured to be working as auto capture ', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return true; | ||
| } | ||
| /** | ||
| * This method checks if the tx_variant supports manual capture. | ||
| * | ||
| * @param string $txVariant | ||
| * @return bool | ||
| */ | ||
| private function txVariantSupportsManualCapture(string $txVariant): bool | ||
| { | ||
| $supportsManualCapture = false; | ||
| $cardVariants = $this->adyenHelper->getCcTypesAltData(); | ||
|
|
||
| // if PayPal capture modues is different from the default use this one | ||
| if (strcmp($notificationPaymentMethod, 'paypal') === 0) { | ||
| if ($manualCapturePayPal) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method is paypal and configured to work as manual capture', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return false; | ||
| } else { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'This payment method is paypal and configured to work as auto capture', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return true; | ||
| } | ||
| } | ||
| if (strcmp($captureMode, 'manual') === 0) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'Capture mode for this payment is set to manual', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| [ | ||
| 'paymentMethod' => $notificationPaymentMethod, | ||
| 'pspReference' => $order->getPayment()->getData('adyen_psp_reference') | ||
| ] | ||
| ) | ||
| ); | ||
| return false; | ||
| } | ||
| // Check the card (scheme or giftcard) method manual capture support | ||
| if (filter_var($cardVariants[$txVariant]['manual_capture'] ?? false, FILTER_VALIDATE_BOOLEAN)) { | ||
| $supportsManualCapture = true; | ||
| } else { | ||
| $adyenTxVariant = $this->txVariantFactory->create(['txVariant' => $txVariant]); | ||
|
|
||
| /* | ||
| * online capture after delivery, use Magento backend to online invoice | ||
| * (if the option auto capture mode for openinvoice is not set) | ||
| * If AdyenTxVariant object is evaluated, rely on the method instance. | ||
| * Otherwise, fallback back to auto capture by-default. | ||
| */ | ||
| if ($this->isOpenInvoice($paymentMethodInstance)) { | ||
| $this->adyenLogger->addAdyenNotification( | ||
| 'Capture mode for klarna is by default set to manual', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return false; | ||
| if (isset($adyenTxVariant)) { | ||
| if (!empty($adyenTxVariant->getCard())) { | ||
| // Check the wallet method capture mode using card portion and method instance together | ||
| $supportsManualCapture = filter_var( | ||
| $cardVariants[$adyenTxVariant->getCard()]['manual_capture'] ?? false, | ||
| FILTER_VALIDATE_BOOLEAN | ||
| ) && $this->supportsManualCapture($adyenTxVariant->getMethodInstance()); | ||
|
Comment on lines
+823
to
+826
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic for checking manual capture support on wallet variants is incorrect. It currently uses the full $supportsManualCapture = filter_var(
$cardVariants[$adyenTxVariant->getCard()]['manual_capture'] ?? false,
FILTER_VALIDATE_BOOLEAN
) && $this->supportsManualCapture($adyenTxVariant->getMethodInstance()); |
||
| } elseif ($this->supportsManualCapture($adyenTxVariant->getMethodInstance())) { | ||
| // Check the alternative payment method manual capture mode based on the method instance | ||
| $supportsManualCapture = true; | ||
| } | ||
| } | ||
|
|
||
| $this->adyenLogger->addAdyenNotification( | ||
| 'Capture mode is set to auto capture', | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
| return true; | ||
| } else { | ||
| // does not allow manual capture so is always immediate capture | ||
| $this->adyenLogger->addAdyenNotification( | ||
| sprintf('Payment method %s, does not allow manual capture', $notificationPaymentMethod), | ||
| array_merge( | ||
| $this->adyenLogger->getOrderContext($order), | ||
| ['pspReference' => $order->getPayment()->getData('adyen_psp_reference')] | ||
| ) | ||
| ); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| return $supportsManualCapture; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactored
isAutoCapturemethod has removed all the diagnostic logging that was present in the previous implementation. While the new logic is cleaner, losing these logs can make troubleshooting webhook processing significantly harder in production environments. Consider re-introducing relevant log messages to indicate why a specific capture mode was chosen.