From c8c92d00eb38ede609608a5517044ee846e0b1b0 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 22 Nov 2021 23:43:48 -0800 Subject: [PATCH 1/8] idempotency key using math random --- Gateway/Helper/Util.php | 31 ++++++++++++++++++++++++++- Gateway/Http/Client/ClientService.php | 29 +++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Gateway/Helper/Util.php b/Gateway/Helper/Util.php index de359129..5848d5d2 100644 --- a/Gateway/Helper/Util.php +++ b/Gateway/Helper/Util.php @@ -18,8 +18,10 @@ namespace Astound\Affirm\Gateway\Helper; +use Magento\Framework\Math\Random; + /** - * Class Action + * Class Util */ class Util { @@ -28,6 +30,22 @@ class Util */ const MONEY_FORMAT = "%.2f"; + /** + * Idempotency key + */ + const IDEMPOTENCY_KEY = "Idempotency-Key"; + + /** + * Constructor + * + * @param Random $random + */ + public function __construct( + Random $random + ) { + $this->_random = $random; + } + /** * Format to cents * @@ -71,4 +89,15 @@ protected static function formatMoney($amount) { return sprintf(self::MONEY_FORMAT, $amount); } + + /** + * Generate identifying strings to get idempotent responses + * + * @return string + */ + public function generateIdempotencyKey() + { + return $this->_random->getUniqueHash(); + } + } diff --git a/Gateway/Http/Client/ClientService.php b/Gateway/Http/Client/ClientService.php index 0d4c5ed7..3fcd439d 100644 --- a/Gateway/Http/Client/ClientService.php +++ b/Gateway/Http/Client/ClientService.php @@ -21,6 +21,8 @@ use Magento\Payment\Gateway\Http\ClientInterface; use Magento\Payment\Gateway\Http\ClientException; use Magento\Payment\Gateway\Http\TransferInterface; +use Astound\Affirm\Gateway\Helper\Request\Action; +use Astound\Affirm\Gateway\Helper\Util; use Magento\Payment\Model\Method\Logger; use Magento\Payment\Gateway\Http\ConverterInterface; use Magento\Framework\HTTP\ZendClientFactory; @@ -66,23 +68,42 @@ class ClientService implements ClientInterface */ protected $httpClientFactory; + /** + * Action + * + * @var Action + */ + protected $action; + + /** + * Util + * + * @var Util + */ + protected $util; + /** * Constructor * * @param Logger $logger * @param ConverterInterface $converter, * @param ZendClientFactory $httpClientFactory + * @param Action $action */ public function __construct( Logger $logger, AffirmLogger $affirmLogger, ConverterInterface $converter, - ZendClientFactory $httpClientFactory + ZendClientFactory $httpClientFactory, + Action $action, + Util $util ) { $this->logger = $logger; $this->affirmLogger = $affirmLogger; $this->converter = $converter; $this->httpClientFactory = $httpClientFactory; + $this->action = $action; + $this->util = $util; } /** @@ -102,6 +123,10 @@ public function placeRequest(TransferInterface $transferObject) $client = $this->httpClientFactory->create(); $client->setUri($requestUri); $client->setAuth($transferObject->getAuthUsername(), $transferObject->getAuthPassword()); + if (strpos($transferObject->getUri(), $this->action::API_TRANSACTIONS_PATH) !== false) { + $idempotencyKey = $this->util->generateIdempotencyKey(); + $client->setHeaders([Util::IDEMPOTENCY_KEY => $idempotencyKey]); + } if (!empty($transferObject->getBody())) { $data = $transferObject->getBody(); $data = json_encode($data, JSON_UNESCAPED_SLASHES); @@ -113,7 +138,7 @@ public function placeRequest(TransferInterface $transferObject) $response = $this->converter->convert($rawResponse); } catch (\Exception $e) { $log['error'] = $e->getMessage(); - $this->logger->error($log); + $this->logger->debug($log); throw new ClientException(__($e->getMessage())); } finally { $log['uri'] = $requestUri; From 85c9152d104730eafe158777deb90c5c96040b81 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 22 Nov 2021 23:47:29 -0800 Subject: [PATCH 2/8] enable partial capture --- Gateway/Request/CaptureRequest.php | 6 +++++- etc/config.xml | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Gateway/Request/CaptureRequest.php b/Gateway/Request/CaptureRequest.php index 2990a187..791f7c3f 100644 --- a/Gateway/Request/CaptureRequest.php +++ b/Gateway/Request/CaptureRequest.php @@ -19,6 +19,7 @@ namespace Astound\Affirm\Gateway\Request; use Magento\Payment\Gateway\Data\PaymentDataObjectInterface; +use Astound\Affirm\Gateway\Helper\Util; /** * Class CaptureRequest @@ -50,8 +51,11 @@ public function build(array $buildSubject) if (!$storeId) { $storeId = null; } + $_amount = $buildSubject['amount'] ? Util::formatToCents($buildSubject['amount']) : null; return [ - 'body' => [], + 'body' => [ + 'amount' => $_amount + ], 'path' => "{$transactionId}/capture", 'storeId' => $storeId ]; diff --git a/etc/config.xml b/etc/config.xml index 289988b8..19002655 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -23,6 +23,7 @@ 0.01 50000 authorize + 0 0 1 US,AS,GU,MP,PR,VI @@ -30,7 +31,7 @@ USD 1 1 - 0 + 1 1 1 1 From f68c0ed4216f9eed6ab039ecc57baa34e8827e84 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 22 Nov 2021 23:50:25 -0800 Subject: [PATCH 3/8] use config --- Gateway/Request/AbstractDataBuilder.php | 5 ++++- Gateway/Request/CaptureRequest.php | 15 ++++++++++----- Model/Config.php | 10 ++++++++++ etc/adminhtml/system.xml | 7 ++++++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Gateway/Request/AbstractDataBuilder.php b/Gateway/Request/AbstractDataBuilder.php index da8b9343..f3c8963e 100644 --- a/Gateway/Request/AbstractDataBuilder.php +++ b/Gateway/Request/AbstractDataBuilder.php @@ -21,6 +21,7 @@ use Magento\Payment\Gateway\ConfigInterface; use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Store\Model\StoreManagerInterface; +use Astound\Affirm\Model\Config; /** * Class AbstractDataBuilder @@ -56,10 +57,12 @@ abstract class AbstractDataBuilder implements BuilderInterface */ public function __construct( ConfigInterface $config, - StoreManagerInterface $storeManager + StoreManagerInterface $storeManager, + Config $configAffirm ) { $this->config = $config; $this->_storeManager = $storeManager; + $this->affirmPaymentConfig = $configAffirm; } /** diff --git a/Gateway/Request/CaptureRequest.php b/Gateway/Request/CaptureRequest.php index 791f7c3f..e37aabe0 100644 --- a/Gateway/Request/CaptureRequest.php +++ b/Gateway/Request/CaptureRequest.php @@ -51,13 +51,18 @@ public function build(array $buildSubject) if (!$storeId) { $storeId = null; } - $_amount = $buildSubject['amount'] ? Util::formatToCents($buildSubject['amount']) : null; - return [ - 'body' => [ + if ($this->affirmPaymentConfig->getPartialCapture()) { + $_amount = $buildSubject['amount'] ? Util::formatToCents($buildSubject['amount']) : null; + $_body = [ 'amount' => $_amount - ], + ]; + } else { + $_body = []; + } + return [ 'path' => "{$transactionId}/capture", - 'storeId' => $storeId + 'storeId' => $storeId, + 'body' => $_body ]; } } diff --git a/Model/Config.php b/Model/Config.php index b362ce66..47a68c45 100644 --- a/Model/Config.php +++ b/Model/Config.php @@ -652,4 +652,14 @@ public function getCheckoutFlowType() { return $this->getConfigData('checkout_flow_type'); } + + /** + * Get partial capture + * + * @return bool + */ + public function getPartialCapture() + { + return $this->getConfigData('partial_capture'); + } } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 40287162..4eb82707 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -74,7 +74,12 @@ Astound\Affirm\Model\Adminhtml\Source\PaymentAction - + + + authorize + Magento\Config\Model\Config\Source\Yesno + + Magento\Config\Model\Config\Source\Yesno From c54ce068253c7eb2586a77a5047c52faf3146f19 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 22 Nov 2021 23:50:55 -0800 Subject: [PATCH 4/8] plugin for canCapturePartial --- Model/Plugin/Payment/CanCapturePartial.php | 48 ++++++++++++++++++++++ etc/di.xml | 3 ++ 2 files changed, 51 insertions(+) create mode 100644 Model/Plugin/Payment/CanCapturePartial.php diff --git a/Model/Plugin/Payment/CanCapturePartial.php b/Model/Plugin/Payment/CanCapturePartial.php new file mode 100644 index 00000000..d1ac3dac --- /dev/null +++ b/Model/Plugin/Payment/CanCapturePartial.php @@ -0,0 +1,48 @@ +affirmPaymentConfig = $configAffirm; + } + + /** + * Plugin to verify if Partial Capture is enabled in config + * + * @param Magento\Sales\Model\Order\Payment $subject + * @param callable $result + * @return bool + */ + public function afterCanCapturePartial(Payment $subject, $result) + { + if (!$this->affirmPaymentConfig->getPartialCapture()) { + return false; + } + return $result; + } +} diff --git a/etc/di.xml b/etc/di.xml index 1341c869..0bf86eb4 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -285,6 +285,9 @@ + + + From 7437cf26dd2f5d93a65a1c088d9f3c73ca9ecafd Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Tue, 23 Nov 2021 09:02:14 -0800 Subject: [PATCH 5/8] rename capture partial plugin name --- etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/di.xml b/etc/di.xml index 0bf86eb4..68271125 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -286,7 +286,7 @@ - + From b50b7a0d54c384362c936b8255097f08acc4e51c Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 29 Nov 2021 14:42:51 -0800 Subject: [PATCH 6/8] Rename config item --- etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 4eb82707..2b226ab4 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -75,7 +75,7 @@ Astound\Affirm\Model\Adminhtml\Source\PaymentAction - + authorize Magento\Config\Model\Config\Source\Yesno From d039f2edeb601f9905a4d187292edfd28c3ae614 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Mon, 29 Nov 2021 14:43:13 -0800 Subject: [PATCH 7/8] display transaction error message --- Gateway/Validator/Client/PaymentActionsValidator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gateway/Validator/Client/PaymentActionsValidator.php b/Gateway/Validator/Client/PaymentActionsValidator.php index a86da41e..c14c495d 100644 --- a/Gateway/Validator/Client/PaymentActionsValidator.php +++ b/Gateway/Validator/Client/PaymentActionsValidator.php @@ -41,9 +41,9 @@ public function validate(array $validationSubject) if (!$validationResult) { $errorMessages = (isset($response[self::ERROR_MESSAGE])) ? - [__('Affirm error code:') . $response[self::RESPONSE_CODE] . __(' error: ') . - __($response[self::ERROR_MESSAGE])]: + [__($response[self::ERROR_MESSAGE]) . __(' Affirm status code: ') . $response[self::RESPONSE_CODE]]: [__('Transaction has been declined, please, try again later.')]; + throw new \Magento\Framework\Validator\Exception(__($errorMessages[0])); } return $this->createResult($validationResult, $errorMessages); From 62dab8cafdf1fdf9bc307cfad59ad2f5ae8b2bd3 Mon Sep 17 00:00:00 2001 From: taehyunlim Date: Thu, 6 Jan 2022 23:03:13 -0800 Subject: [PATCH 8/8] version update --- composer.json | 2 +- etc/module.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 024d578e..c9780cdb 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "affirm/magento2", "description": "Affirm's extension for the Magento 2 https://www.affirm.com/", "type": "magento2-module", - "version": "3.0.15", + "version": "3.1.0", "license": [ "BSD-3-Clause" ], diff --git a/etc/module.xml b/etc/module.xml index cf70d953..5262389d 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -10,7 +10,7 @@ */ --> - +