Skip to content

Commit

Permalink
Merge pull request #71 from Affirm/feature-split-capture
Browse files Browse the repository at this point in the history
Partial Capture
  • Loading branch information
taehyunlim authored Jan 7, 2022
2 parents 94dbf9a + 62dab8c commit a6af6fc
Show file tree
Hide file tree
Showing 12 changed files with 145 additions and 12 deletions.
31 changes: 30 additions & 1 deletion Gateway/Helper/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

namespace Astound\Affirm\Gateway\Helper;

use Magento\Framework\Math\Random;

/**
* Class Action
* Class Util
*/
class Util
{
Expand All @@ -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
*
Expand Down Expand Up @@ -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();
}

}
29 changes: 27 additions & 2 deletions Gateway/Http/Client/ClientService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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);
Expand All @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion Gateway/Request/AbstractDataBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

/**
Expand Down
13 changes: 11 additions & 2 deletions Gateway/Request/CaptureRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
namespace Astound\Affirm\Gateway\Request;

use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
use Astound\Affirm\Gateway\Helper\Util;

/**
* Class CaptureRequest
Expand Down Expand Up @@ -50,10 +51,18 @@ public function build(array $buildSubject)
if (!$storeId) {
$storeId = null;
}
if ($this->affirmPaymentConfig->getPartialCapture()) {
$_amount = $buildSubject['amount'] ? Util::formatToCents($buildSubject['amount']) : null;
$_body = [
'amount' => $_amount
];
} else {
$_body = [];
}
return [
'body' => [],
'path' => "{$transactionId}/capture",
'storeId' => $storeId
'storeId' => $storeId,
'body' => $_body
];
}
}
4 changes: 2 additions & 2 deletions Gateway/Validator/Client/PaymentActionsValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions Model/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}
48 changes: 48 additions & 0 deletions Model/Plugin/Payment/CanCapturePartial.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
*
* @category Affirm
* @package Astound_Affirm
* @copyright Copyright (c) 2021 Affirm, Inc.
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/

namespace Astound\Affirm\Model\Plugin\Payment;

use Magento\Sales\Model\Order\Payment;
use Astound\Affirm\Model\Config;

/**
* Class CanCapturePartial
*
* @package Astound\Affirm\Model\Plugin\Payment
*/
class CanCapturePartial
{
/**
* Constructor
*
* @param Config $configAffirm
*/
public function __construct(
Config $configAffirm
)
{
$this->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;
}
}
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
],
Expand Down
7 changes: 6 additions & 1 deletion etc/adminhtml/system.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@
<label>Payment Action</label>
<source_model>Astound\Affirm\Model\Adminhtml\Source\PaymentAction</source_model>
</field>
<field id="disable_for_backordered_items" translate="label" type="select" sortOrder="71" showInDefault="1" showInWebsite="1" showInStore="0">
<field id="partial_capture" translate="label" type="select" sortOrder="71" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Enable Partial Capture</label>
<depends><field id="payment_action">authorize</field></depends>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="disable_for_backordered_items" translate="label" type="select" sortOrder="72" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Disable for backordered items</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
Expand Down
3 changes: 2 additions & 1 deletion etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@
<min_order_total>0.01</min_order_total>
<max_order_total>50000</max_order_total>
<payment_action>authorize</payment_action>
<partial_capture>0</partial_capture>
<disable_for_backordered_items>0</disable_for_backordered_items>
<allowspecific>1</allowspecific>
<specificcountry>US,AS,GU,MP,PR,VI</specificcountry>
<allowspecificcurrency>1</allowspecificcurrency>
<currency>USD</currency>
<can_authorize>1</can_authorize>
<can_capture>1</can_capture>
<can_capture_partial>0</can_capture_partial>
<can_capture_partial>1</can_capture_partial>
<can_void>1</can_void>
<can_cancel>1</can_cancel>
<can_use_checkout>1</can_use_checkout>
Expand Down
3 changes: 3 additions & 0 deletions etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,9 @@
<type name="Magento\Checkout\CustomerData\Cart">
<plugin name="checkout-aslowas-minicart" type="Astound\Affirm\Model\Plugin\Checkout\CustomerData\Cart"/>
</type>
<type name="Magento\Sales\Model\Order\Payment">
<plugin name="after-can-capture-partial" type="Astound\Affirm\Model\Plugin\Payment\CanCapturePartial" sortOrder="1"/>
</type>

<!-- Init payment helper -->
<type name="Astound\Affirm\Helper\Payment">
Expand Down
2 changes: 1 addition & 1 deletion etc/module.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Astound_Affirm" setup_version="3.0.15">
<module name="Astound_Affirm" setup_version="3.1.0">
<sequence>
<module name="Magento_Checkout"/>
<module name="Magento_Sales"/>
Expand Down

0 comments on commit a6af6fc

Please sign in to comment.