diff --git a/Controller/Callback.php b/Controller/Callback.php
index 035df08..9fa69bb 100644
--- a/Controller/Callback.php
+++ b/Controller/Callback.php
@@ -4,6 +4,7 @@
use PicPay\Checkout\Helper\Data as HelperData;
use PicPay\Checkout\Helper\Order as HelperOrder;
+use PicPay\Checkout\Helper\Tds as HelperTds;
use PicPay\Checkout\Model\CallbackFactory;
use PicPay\Checkout\Model\ResourceModel\Callback as CallbackResourceModel;
use Magento\Framework\App\Action\Action;
@@ -33,6 +34,11 @@ abstract class Callback extends Action implements \Magento\Framework\App\CsrfAwa
*/
protected $helperOrder;
+ /**
+ * @var HelperTds
+ */
+ protected $helperTds;
+
/**
* @var CallbackFactory
*/
@@ -70,6 +76,7 @@ public function __construct(
ResultFactory $resultFactory,
HelperData $helperData,
HelperOrder $helperOrder,
+ HelperTds $helperTds,
CallbackFactory $callbackFactory,
CallbackResourceModel $callbackResourceModel,
ManagerInterface $eventManager,
@@ -78,6 +85,7 @@ public function __construct(
$this->resultFactory = $resultFactory;
$this->helperData = $helperData;
$this->helperOrder = $helperOrder;
+ $this->helperTds = $helperTds;
$this->callbackFactory = $callbackFactory;
$this->callbackResourceModel = $callbackResourceModel;
$this->eventManager = $eventManager;
diff --git a/Controller/Callback/Payments.php b/Controller/Callback/Payments.php
index dc42f80..b24dbe3 100644
--- a/Controller/Callback/Payments.php
+++ b/Controller/Callback/Payments.php
@@ -11,14 +11,11 @@
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\ResultFactory;
use PicPay\Checkout\Controller\Callback;
-use PicPay\Checkout\Gateway\Http\Client\Api;
-use PicPay\Checkout\Helper\Order;
use Laminas\Http\Response;
-use PicPay\Checkout\Helper\Order as HelperOrder;
-use Magento\Sales\Model\Order as SalesOrder;
class Payments extends Callback
{
+ public const DEFAULT_STATUS_CODE = 500;
/**
* @var string
*/
@@ -43,31 +40,29 @@ public function execute()
$this->helperData->log(__('Webhook %1', __CLASS__), self::LOG_NAME);
$result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
- $statusCode = 500;
+ $statusCode = self::DEFAULT_STATUS_CODE;
$orderIncrementId = '';
try {
- $content = $this->getContent($this->getRequest());
- $this->logParams($content);
+ $webhookData = $this->getContent($this->getRequest());
+ $this->logParams($webhookData);
$method = 'picpay-payments';
+ $content = isset($webhookData['type']) ? $webhookData['data'] : $webhookData;
+ $chargeId = $content['chargeId'] ?? $content['merchantChargeId'];
- $content = isset($content['type']) ? $content['data'] : $content;
-
- if (isset($content['status'])) {
- $chargeId = $content['merchantChargeId'];
- if (isset($content['status'])) {
- $picpayStatus = $content['status'];
- $order = $this->helperOrder->loadOrderByMerchantChargeId($chargeId);
- if ($order->getId()) {
- $orderIncrementId = $order->getIncrementId();
- $method = $order->getPayment()->getMethod();
- $amount = $content['amount'] ? $content['amount'] / 100 : $order->getGrandTotal();
- $refundedAmount = $content['refundedAmount'] ? $content['refundedAmount'] / 100 : 0;
-
- $this->helperOrder->updateOrder($order, $picpayStatus, $content, $amount, $method, true, $refundedAmount);
- $statusCode = Response::STATUS_CODE_200;
- }
- }
+ $statusCode = $this->processTds($webhookData, $chargeId, $content, $statusCode);
+ if (
+ isset($content['status'])
+ && $statusCode === self::DEFAULT_STATUS_CODE
+ && $order = $this->helperOrder->loadOrderByMerchantChargeId($chargeId)
+ ) {
+ $status = $content['status'];
+ $orderIncrementId = $order->getIncrementId();
+ $method = $order->getPayment()->getMethod();
+ $amount = $content['amount'] ? $content['amount'] / 100 : $order->getGrandTotal();
+ $refundedAmount = $content['refundedAmount'] ? $content['refundedAmount'] / 100 : 0;
+ $this->helperOrder->updateOrder($order, $status, $content, $amount, $method, true, $refundedAmount);
+ $statusCode = Response::STATUS_CODE_200;
}
/** @var \PicPay\Checkout\Model\Callback $callBack */
@@ -78,11 +73,22 @@ public function execute()
$callBack->setPayload($this->helperData->jsonEncode($content));
$this->callbackResourceModel->save($callBack);
} catch (\Exception $e) {
- $statusCode = 500;
+ $statusCode = self::DEFAULT_STATUS_CODE;
$this->helperData->getLogger()->error($e->getMessage());
}
$result->setHttpResponseCode($statusCode);
return $result;
}
+
+ public function processTds(array $webhookData, string $chargeId, array $content, int $statusCode): int
+ {
+ $quote = $this->helperTds->loadQuoteByChargeId($chargeId);
+ if (isset($webhookData['type']) && $webhookData['type'] == 'THREE_DS_CHALLENGE' && $quote->getId()) {
+ $quote = $this->helperTds->loadQuoteByChargeId($chargeId);
+ $this->helperTds->updateQuote($quote, $content);
+ $statusCode = Response::STATUS_CODE_200;
+ }
+ return $statusCode;
+ }
}
diff --git a/Controller/Tds/Challenge.php b/Controller/Tds/Challenge.php
new file mode 100644
index 0000000..5e2f7f3
--- /dev/null
+++ b/Controller/Tds/Challenge.php
@@ -0,0 +1,89 @@
+checkoutSession = $checkoutSession;
+ $this->json = $json;
+ $this->resultJsonFactory = $resultJsonFactory;
+ $this->quoteRepository = $quoteRepository;
+
+ parent::__construct($context);
+ }
+
+ public function execute()
+ {
+ try {
+ $result = $this->resultJsonFactory->create();
+
+ $quoteId = $this->checkoutSession->getQuoteId();
+ $quote = $this->quoteRepository->get($quoteId);
+
+ if ($quote->getPicpayChargeId()) {
+ $tdsChallengeStatus = $quote->getPicpayChallengeStatus();
+ return $result->setData([
+ 'challenge_hash' => hash_hmac('sha256', $quote->getPicpayChargeId(), $quote->getId()),
+ 'challenge_customer_email' => $quote->getCustomerEmail(),
+ 'challenge_customer_name' => $quote->getCustomerFirstname() . ' ' . $quote->getCustomerLastname(),
+ 'challenge_customer_address' => $quote->getBillingAddress()->getStreet(),
+ 'challenge_status' => $tdsChallengeStatus,
+ 'charge_id' => $quote->getPicpayChargeId()
+ ]);
+ }
+ } catch (\Exception $e) {
+ return $result->setData(['error' => true, 'message' => $e->getMessage()]);
+ }
+
+ return $result->setData(['error' => true, 'message' => __('No orders found for this user.')]);
+ }
+
+ public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
+ {
+ $result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
+ $result->setHttpResponseCode(403);
+ return new InvalidRequestException(
+ $result
+ );
+ }
+
+ public function validateForCsrf(RequestInterface $request): ?bool
+ {
+ return true;
+ }
+}
diff --git a/Controller/Tds/Enrollment.php b/Controller/Tds/Enrollment.php
new file mode 100644
index 0000000..cc70aa7
--- /dev/null
+++ b/Controller/Tds/Enrollment.php
@@ -0,0 +1,102 @@
+resultJsonFactory = $resultJsonFactory;
+ $this->json = $json;
+ $this->tds = $tds;
+
+ parent::__construct($context);
+ }
+
+ public function execute()
+ {
+ $result = $this->resultJsonFactory->create();
+
+ try {
+ $content = $this->getRequest()->getContent();
+ $bodyParams = ($content) ? $this->json->unserialize($content) : [];
+ $response = $this->tds->runTdsRequest($bodyParams);
+
+ if ($response['response']['chargeId']) {
+ $result->setJsonData($this->json->serialize($response['response']['transactions'][0]));
+ }
+
+ $responseCode = 200;
+ } catch (\Exception $e) {
+ $responseCode = 500;
+ $this->messageManager->addErrorMessage($e->getMessage());
+ }
+
+ $result->setHttpResponseCode($responseCode);
+ return $result;
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @return InvalidRequestException|null
+ */
+ public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
+ {
+ $result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
+ $result->setHttpResponseCode(403);
+ return new InvalidRequestException(
+ $result
+ );
+ }
+
+ /**
+ * @param RequestInterface $request
+ * @return bool|null
+ */
+ public function validateForCsrf(RequestInterface $request): ?bool
+ {
+ return true;
+ }
+}
diff --git a/Gateway/Http/Client.php b/Gateway/Http/Client.php
index e0a0d18..ab7eced 100644
--- a/Gateway/Http/Client.php
+++ b/Gateway/Http/Client.php
@@ -79,7 +79,7 @@ protected function getDefaultHeaders(): array
{
return [
'Content-Type' => 'application/json',
- 'caller-origin' => 'M2-v' . $this->helper->getModuleVersion()
+ 'caller-origin' => 'Magento'
];
}
diff --git a/Gateway/Http/Client/Api.php b/Gateway/Http/Client/Api.php
index 2d9e3b4..bb9d940 100644
--- a/Gateway/Http/Client/Api.php
+++ b/Gateway/Http/Client/Api.php
@@ -24,6 +24,7 @@
use PicPay\Checkout\Gateway\Http\Client\Api\Refund;
use PicPay\Checkout\Gateway\Http\Client\Api\Capture;
use PicPay\Checkout\Gateway\Http\Client\Api\Token;
+use PicPay\Checkout\Gateway\Http\Client\Api\Tds;
use PicPay\Checkout\Gateway\Http\ClientInterface;
use PicPay\Checkout\Helper\Data;
@@ -74,6 +75,11 @@ class Api
*/
private $token;
+ /**
+ * @var Tds
+ */
+ private $tds;
+
/**
* @var string
*/
@@ -88,7 +94,8 @@ public function __construct(
Refund $refund,
Capture $capture,
Card $card,
- Query $query
+ Query $query,
+ Tds $tds
) {
$this->helper = $helper;
$this->token = $token;
@@ -99,6 +106,7 @@ public function __construct(
$this->capture = $capture;
$this->card = $card;
$this->query = $query;
+ $this->tds = $tds;
}
/**
@@ -186,6 +194,14 @@ public function card(): ClientInterface
return $this->getClient($this->card);
}
+ /**
+ * @throws \Exception
+ */
+ public function tds(): ClientInterface
+ {
+ return $this->getClient($this->tds);
+ }
+
/**
* @throws \Exception
*/
diff --git a/Gateway/Http/Client/Api/Tds.php b/Gateway/Http/Client/Api/Tds.php
new file mode 100644
index 0000000..879c4b1
--- /dev/null
+++ b/Gateway/Http/Client/Api/Tds.php
@@ -0,0 +1,48 @@
+getEndpointPath('payments/tds_setup');
+ $method = Request::METHOD_POST;
+ return $this->makeRequest($path, $method, 'payments', $data);
+ }
+
+ public function enrollment(array $data): array
+ {
+ $path = $this->getEndpointPath('payments/tds_enrollment');
+ $method = Request::METHOD_POST;
+ return $this->makeRequest($path, $method, 'payments', $data);
+ }
+
+ public function challengeStatus($chargeId): array
+ {
+ $path = $this->getEndpointPath('payments/tds_challenge_status');
+ $method = Request::METHOD_GET;
+ return $this->makeRequest($path, $method);
+ }
+
+ public function authorization($data): array
+ {
+ $path = $this->getEndpointPath('payments/tds_authorization');
+ $method = Request::METHOD_POST;
+ return $this->makeRequest($path, $method, 'payments', $data);
+ }
+}
diff --git a/Gateway/Http/Client/Transaction.php b/Gateway/Http/Client/Transaction.php
index 3d74c2e..8f13873 100644
--- a/Gateway/Http/Client/Transaction.php
+++ b/Gateway/Http/Client/Transaction.php
@@ -71,7 +71,7 @@ public function placeRequest(TransferInterface $transferObject)
break;
default:
- $transaction = $this->api->create()->execute($requestBody, $config['store_id']);
+ $transaction = $this->executeCardTransaction($config, $requestBody);
}
$this->api->logResponse($transaction, self::LOG_NAME);
@@ -83,4 +83,21 @@ public function placeRequest(TransferInterface $transferObject)
return ['status' => $status, 'status_code' => $statusCode, 'transaction' => $transaction['response']];
}
+
+ /**
+ * @param $config
+ * @param $requestBody
+ * @return array
+ * @throws \Exception
+ */
+ protected function executeCardTransaction($config, $requestBody): array
+ {
+ if ($config['use_tds']) {
+ $transaction = $this->api->tds()->authorization($requestBody);
+ $transaction['response'] = $transaction['response']['charge'] ?? $transaction['response'];
+ return $transaction;
+ }
+
+ return $this->api->create()->execute($requestBody, $config['store_id']);
+ }
}
diff --git a/Gateway/Request/CaptureRequest.php b/Gateway/Request/CaptureRequest.php
index 0f75bce..0cec75c 100644
--- a/Gateway/Request/CaptureRequest.php
+++ b/Gateway/Request/CaptureRequest.php
@@ -45,7 +45,7 @@ public function build(array $buildSubject)
];
$clientConfig = [
- 'order_id' => $payment->getAdditionalInformation('merchantChargeId'),
+ 'order_id' => $payment->getAdditionalInformation('merchantChargeId') ?? $order->getPicpayMerchantId(),
'status' => $payment->getAdditionalInformation('status'),
'store_id' => $order->getStoreId()
];
diff --git a/Gateway/Request/CreditCard/TransactionRequest.php b/Gateway/Request/CreditCard/TransactionRequest.php
index 6e15339..74cff28 100644
--- a/Gateway/Request/CreditCard/TransactionRequest.php
+++ b/Gateway/Request/CreditCard/TransactionRequest.php
@@ -2,17 +2,24 @@
namespace PicPay\Checkout\Gateway\Request\CreditCard;
+use Magento\Catalog\Api\CategoryRepositoryInterface;
+use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Customer\Model\Session as CustomerSession;
+use Magento\Framework\Event\ManagerInterface;
use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Stdlib\DateTime\DateTime;
+use Magento\Payment\Gateway\ConfigInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Payment;
+use PicPay\Checkout\Gateway\Http\Client\Api;
use PicPay\Checkout\Gateway\Request\PaymentsRequest;
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
use Magento\Payment\Gateway\Request\BuilderInterface;
+use PicPay\Checkout\Helper\Data;
use PicPay\Checkout\Model\Ui\CreditCard\ConfigProvider;
class TransactionRequest extends PaymentsRequest implements BuilderInterface
{
-
/**
* Builds ENV request
*
@@ -32,10 +39,18 @@ public function build(array $buildSubject)
$payment = $buildSubject['payment']->getPayment();
$order = $payment->getOrder();
- $this->validateCard($order, $payment);
- $request = $this->getTransactions($order, $buildSubject['amount']);
+ if ($payment->getAdditionalInformation('use_tds_authorization')) {
+ $request = $this->authorizationRequest->getRequest($order);
+ } else {
+ $this->validateCard($order, $payment);
+ $request = $this->getTransactions($order, $buildSubject['amount']);
+ }
- return ['request' => $request, 'client_config' => ['store_id' => $order->getStoreId()]];
+ $clientConfig = [
+ 'store_id' => $order->getStoreId(),
+ 'use_tds' => $payment->getAdditionalInformation('use_tds_authorization')
+ ];
+ return ['request' => $request, 'client_config' => $clientConfig];
}
/**
diff --git a/Gateway/Request/PaymentsRequest.php b/Gateway/Request/PaymentsRequest.php
index 678ef27..a9ca6fb 100644
--- a/Gateway/Request/PaymentsRequest.php
+++ b/Gateway/Request/PaymentsRequest.php
@@ -21,6 +21,7 @@
namespace PicPay\Checkout\Gateway\Request;
use PicPay\Checkout\Gateway\Http\Client\Api;
+use PicPay\Checkout\Gateway\Request\Tds\AuthorizationRequest;
use PicPay\Checkout\Helper\Data;
use Magento\Customer\Model\Session as CustomerSession;
use Magento\Framework\Event\ManagerInterface;
@@ -57,6 +58,10 @@ class PaymentsRequest
*/
protected $date;
+ /**
+ * @var AuthorizationRequest
+ */
+ protected $authorizationRequest;
/**
* @var DateTime
@@ -92,7 +97,8 @@ public function __construct(
CustomerSession $customerSession,
CategoryRepositoryInterface $categoryRepository,
ProductRepositoryInterface $productRepository,
- Api $api
+ Api $api,
+ AuthorizationRequest $authorizationRequest
) {
$this->eventManager = $eventManager;
$this->helper = $helper;
@@ -103,6 +109,7 @@ public function __construct(
$this->categoryRepository = $categoryRepository;
$this->productRepository = $productRepository;
$this->api = $api;
+ $this->authorizationRequest = $authorizationRequest;
}
protected function getTransactions(Order $order, float $amount): array
diff --git a/Gateway/Request/RefundRequest.php b/Gateway/Request/RefundRequest.php
index 95cc03b..9793234 100644
--- a/Gateway/Request/RefundRequest.php
+++ b/Gateway/Request/RefundRequest.php
@@ -71,7 +71,7 @@ public function build(array $buildSubject)
];
$clientConfig = [
- 'order_id' => $payment->getAdditionalInformation('merchantChargeId'),
+ 'order_id' => $payment->getAdditionalInformation('merchantChargeId') ?? $order->getPicpayMerchantId(),
'store_id' => $order->getStoreId()
];
diff --git a/Gateway/Request/Tds/AuthorizationRequest.php b/Gateway/Request/Tds/AuthorizationRequest.php
new file mode 100644
index 0000000..4c64ada
--- /dev/null
+++ b/Gateway/Request/Tds/AuthorizationRequest.php
@@ -0,0 +1,61 @@
+helper = $helper;
+ }
+
+ /**
+ * @param Order $order
+ * @return array
+ */
+ public function getRequest(Order $order): array
+ {
+ return [
+ 'chargeId' => $order->getPicpayChargeId(),
+ 'capture' => !$this->helper->isLateCapture(),
+ 'transactions' => $this->getAuthTransactionInfo($order)
+ ];
+ }
+
+ /**
+ * @param Order $order
+ * @return array
+ */
+ protected function getAuthTransactionInfo(Order $order): array
+ {
+ $installments = (int) $order->getPayment()->getAdditionalInformation('cc_installments') ?: 1;
+
+ $transactionInfo = [
+ 'installmentNumber' => $installments,
+ 'installmentType' => $installments > 1 ? 'MERCHANT' : 'NONE',
+ 'card' => $this->getCardData($order, $order->getPayment()),
+ ];
+ return [$transactionInfo];
+ }
+
+
+ protected function getCardData(Order $order, Payment $payment): array
+ {
+ return [
+ 'cvv' => $payment->getCcCid(),
+ 'cardholderAuthenticationId' => $order->getPicpayCardholderAuthId()
+ ];
+ }
+}
diff --git a/Gateway/Request/Tds/EnrollmentRequest.php b/Gateway/Request/Tds/EnrollmentRequest.php
new file mode 100644
index 0000000..e4a71f3
--- /dev/null
+++ b/Gateway/Request/Tds/EnrollmentRequest.php
@@ -0,0 +1,109 @@
+getEnrollmentTransactions($quote, $buildSubject, $payment->getAdditionalData());
+ return ['request' => $request, 'client_config' => ['store_id' => $quote->getStoreId()]];
+ }
+
+ /**
+ * @param Quote $quote
+ * @param $paymentData
+ * @param $additionalData
+ * @return array
+ */
+ protected function getEnrollmentTransactions(Quote $quote, $paymentData, $additionalData): array
+ {
+ return [
+ 'chargeId' => $paymentData['chargeId'],
+ 'customer' => $this->getTdsCustomerData($quote),
+ 'browser' => $this->getBrowserData($additionalData['browser_data']),
+ 'transactions' => $this->getTdsTransactionInfo($quote, $paymentData['amount'])
+ ];
+ }
+
+ /**
+ * @param Quote $quote
+ * @return array
+ */
+ protected function getTdsCustomerData(Quote $quote): array
+ {
+ $payment = $quote->getPayment();
+ $taxvat = (string) $payment->getAdditionalInformation('picpay_customer_taxvat');
+
+ $address = $quote->getBillingAddress();
+ $fullName = $this->getCustomerFullName($quote);
+ $phoneNumber = $this->helper->formatPhoneNumber($address->getTelephone());
+
+ $customerData = [
+ 'name' => $fullName,
+ 'email' => $quote->getCustomerEmail(),
+ 'documentType' => $this->getDocumentType($taxvat),
+ 'document' => $taxvat,
+ 'phone' => $phoneNumber,
+ ];
+
+ if ($quote->getCustomerDob()) {
+ $customerData['birth_date'] = $this->helper->formatDate($quote->getCustomerDob());
+ }
+
+ return $customerData;
+ }
+
+ /**
+ * @param $data
+ * @return array
+ */
+ protected function getBrowserData($data)
+ {
+ $browserData = [
+ 'httpAcceptBrowserValue' => $_SERVER['HTTP_ACCEPT'] ,
+ 'httpAcceptContent' => $_SERVER['HTTP_ACCEPT'] ,
+ ];
+ return array_merge($browserData, $data);
+ }
+
+ /**
+ * @param Quote $quote
+ * @param float $orderAmount
+ * @return array
+ */
+ protected function getTdsTransactionInfo(Quote $quote, float $orderAmount): array
+ {
+ $cardData = $this->getCardData($quote);
+ unset($cardData['cardType']);
+
+ $cardData['number'] = $cardData['cardNumber'];
+ unset($cardData['cardNumber']);
+
+ $transactionInfo = [
+ 'amount' => $orderAmount * 100,
+ 'card' => $cardData
+ ];
+ return [$transactionInfo];
+ }
+}
diff --git a/Gateway/Request/Tds/SetupRequest.php b/Gateway/Request/Tds/SetupRequest.php
new file mode 100644
index 0000000..ea6c43d
--- /dev/null
+++ b/Gateway/Request/Tds/SetupRequest.php
@@ -0,0 +1,59 @@
+getSetupTransactions($quote, $buildSubject['amount']);
+ return ['request' => $request, 'client_config' => ['store_id' => $quote->getStoreId()]];
+ }
+
+ protected function getSetupTransactions(Quote $quote, float $amount): array
+ {
+ return [
+ 'paymentSource' => 'GATEWAY',
+ 'transactions' => $this->getTdsTransactionInfo($quote, $amount)
+ ];
+ }
+
+ /**
+ * @param Quote $quote
+ * @param float $orderAmount
+ * @return array[]
+ * @throws \Exception
+ */
+ protected function getTdsTransactionInfo(Quote $quote, float $orderAmount): array
+ {
+ $cardData = $this->getCardData($quote);
+
+ unset($cardData['cardType']);
+ $transactionInfo = [
+ 'amount' => $orderAmount * 100,
+ 'paymentType' => 'CREDIT',
+ 'card' => $cardData
+ ];
+ return [$transactionInfo];
+ }
+}
diff --git a/Gateway/Request/Tds/TdsRequest.php b/Gateway/Request/Tds/TdsRequest.php
new file mode 100644
index 0000000..85d5c15
--- /dev/null
+++ b/Gateway/Request/Tds/TdsRequest.php
@@ -0,0 +1,85 @@
+getPayment();
+ $taxvat = (string) $payment->getAdditionalInformation('picpay_customer_taxvat');
+
+ return [
+ 'cardType' => 'CREDIT',
+ 'cardNumber' => $payment->getCcNumber(),
+ 'cvv' => $payment->getCcCid(),
+ 'brand' => $this->getCardType($payment->getCcType()),
+ 'cardholderName' => $payment->getCcOwner(),
+ 'cardholderDocument' => $this->helper->digits($taxvat),
+ 'expirationMonth' => (int) $payment->getCcExpMonth(),
+ 'expirationYear' => (int) $payment->getCcExpYear(),
+ 'billingAddress' => $this->getQuoteBillingAddress($quote)
+ ];
+ }
+
+ /**
+ * @param Quote $quote
+ * @return array
+ */
+ protected function getQuoteBillingAddress(Quote $quote): array
+ {
+ $billingAddress = $quote->getBillingAddress();
+ $number = $billingAddress->getStreetLine($this->getStreetField('number')) ?: 0;
+ $complement = $billingAddress->getStreetLine($this->getStreetField('complement'));
+ $address = [
+ 'street' => $billingAddress->getStreetLine($this->getStreetField('street')),
+ 'number' => $number,
+ 'neighborhood' => $billingAddress->getStreetLine($this->getStreetField('district')),
+ 'city' => $billingAddress->getCity(),
+ 'state' => $billingAddress->getRegionCode(),
+ 'country' => $billingAddress->getCountryId(),
+ 'zipCode' => $this->helper->clearNumber($billingAddress->getPostcode()),
+ ];
+
+ if ($complement) {
+ $address['complement'] = $complement;
+ }
+
+ return $address;
+ }
+
+ /**
+ * @param Quote $quote
+ * @return string
+ */
+ protected function getCustomerFullName(Quote $quote): string
+ {
+ $firstName = $quote->getCustomerFirstname();
+ $lastName = $quote->getCustomerLastname();
+ return $firstName . ' ' . $lastName;
+ }
+
+ /**
+ * @param $type
+ * @return string
+ */
+ protected function getCardType($type)
+ {
+ $types = [
+ 'MC' => 'MASTERCARD',
+ 'VI' => 'VISA',
+ 'ELO' => 'ELO',
+ ];
+
+ return $types[$type] ?? '';
+ }
+}
diff --git a/Gateway/Response/CreditCard/TransactionHandler.php b/Gateway/Response/CreditCard/TransactionHandler.php
index 49b6373..ea64de7 100644
--- a/Gateway/Response/CreditCard/TransactionHandler.php
+++ b/Gateway/Response/CreditCard/TransactionHandler.php
@@ -73,11 +73,15 @@ public function handle(array $handlingSubject, array $response)
$payment = $this->helperOrder->updateDefaultAdditionalInfo($payment, $transaction);
$payment = $this->helperOrder->updatePaymentAdditionalInfo($payment, $transaction['transactions'], 'credit');
- if ($transaction['chargeStatus'] == HelperOrder::STATUS_PRE_AUTHORIZED) {
+ if (
+ $transaction['chargeStatus'] == HelperOrder::STATUS_PRE_AUTHORIZED
+ || $transaction['chargeStatus'] == HelperOrder::STATUS_CHARGE_PRE_AUTHORIZED
+ ) {
$payment->getOrder()->setState('new');
$payment->setSkipOrderProcessing(true);
}
- $payment->getOrder()->setData('picpay_charge_id', $transaction['merchantChargeId']);
+ $merchantChargeId = $transaction['merchantChargeId'] ?? $payment->getOrder()->getPicpayMerchantId();
+ $payment->getOrder()->setData('picpay_charge_id', $merchantChargeId);
}
}
diff --git a/Gateway/Response/PaymentsHandler.php b/Gateway/Response/PaymentsHandler.php
index 5e21339..ed7c941 100644
--- a/Gateway/Response/PaymentsHandler.php
+++ b/Gateway/Response/PaymentsHandler.php
@@ -44,7 +44,10 @@ public function validateResponse(array $handlingSubject, array $response): array
}
$transaction = $response['transaction'];
- if (!isset($transaction['merchantChargeId']) || !isset($transaction['chargeStatus'])) {
+ if (
+ (!isset($transaction['merchantChargeId']) && !isset($transaction['id']))
+ || !isset($transaction['chargeStatus'])
+ ) {
throw new LocalizedException(__('There was an error processing your request.'));
}
return array($handlingSubject['payment'], $transaction);
diff --git a/Helper/Data.php b/Helper/Data.php
index 9b27971..655c6b3 100644
--- a/Helper/Data.php
+++ b/Helper/Data.php
@@ -14,6 +14,7 @@
namespace PicPay\Checkout\Helper;
+use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\HTTP\Header;
@@ -122,6 +123,9 @@ class Data extends \Magento\Payment\Helper\Data
/** @var SessionManager */
protected $sessionManager;
+ /** @var ResourceConnection */
+ protected $resourceConnection;
+
public function __construct(
Context $context,
LayoutFactory $layoutFactory,
@@ -141,6 +145,7 @@ public function __construct(
OrderInterface $order,
Header $httpHeader,
SessionManager $sessionManager,
+ ResourceConnection $resourceConnection,
ComponentRegistrar $componentRegistrar,
DateTime $dateTime,
DirectoryData $helperDirectory,
@@ -168,6 +173,7 @@ public function __construct(
$this->order = $order;
$this->httpHeader = $httpHeader;
$this->sessionManager = $sessionManager;
+ $this->resourceConnection = $resourceConnection;
$this->componentRegistrar = $componentRegistrar;
$this->dateTime = $dateTime;
$this->helperDirectory = $helperDirectory;
@@ -311,6 +317,7 @@ public function saveRequest(
$request = $this->serializeAndMask($request);
$response = $this->serializeAndMask($response);
+ $connection = $this->resourceConnection->getConnection();
$requestModel = $this->requestFactory->create();
$requestModel->setRequest($request);
$requestModel->setResponse($response);
@@ -318,6 +325,7 @@ public function saveRequest(
$requestModel->setStatusCode($statusCode);
$this->requestRepository->save($requestModel);
+ $connection->commit();
} catch (\Exception $e) {
$this->log($e->getMessage());
}
diff --git a/Helper/Order.php b/Helper/Order.php
index ddf2101..9736b7e 100644
--- a/Helper/Order.php
+++ b/Helper/Order.php
@@ -9,17 +9,11 @@
namespace PicPay\Checkout\Helper;
-use BaconQrCode\Renderer\ImageRenderer as QrCodeImageRenderer;
-use BaconQrCode\Renderer\Image\ImagickImageBackEnd as QrCodeImagickImageBackEnd;
-use BaconQrCode\Renderer\RendererStyle\RendererStyle as QrCodeRendererStyle;
-use BaconQrCode\Writer as QrCodeWritter;
use Magento\Framework\Exception\LocalizedException;
use PicPay\Checkout\Helper\Data as HelperData;
use PicPay\Checkout\Gateway\Http\Client;
use PicPay\Checkout\Gateway\Http\Client\Api;
-use PicPay\Checkout\Model\Ui\CreditCard\ConfigProvider as CcConfigProvider;
use Magento\Framework\App\Config\Initial;
-use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\Filesystem;
use Magento\Framework\Stdlib\DateTime\DateTime;
@@ -45,6 +39,8 @@ class Order extends \Magento\Payment\Helper\Data
public const STATUS_PRE_AUTHORIZED = 'PRE_AUTHORIZED';
+ public const STATUS_CHARGE_PRE_AUTHORIZED = 'PreAuthorized';
+
public const STATUS_PARTIAL = 'PARTIAL';
public const STATUS_ERROR = 'ERROR';
@@ -65,7 +61,7 @@ class Order extends \Magento\Payment\Helper\Data
protected $orderFactory;
/**
- * @var OrderFactory
+ * @var OrderRepository
*/
protected $orderRepository;
@@ -116,7 +112,6 @@ class Order extends \Magento\Payment\Helper\Data
protected $dateTime;
/**
- * Order constructor.
* @param Context $context
* @param LayoutFactory $layoutFactory
* @param Factory $paymentMethodFactory
@@ -428,13 +423,17 @@ public function getStatusState(string $status): string
return '';
}
- public function loadOrderByMerchantChargeId(string $chargeId): SalesOrder
+ /**
+ * @param string $chargeId
+ * @return SalesOrder|false
+ */
+ public function loadOrderByMerchantChargeId(string $chargeId): SalesOrder|false
{
$order = $this->orderFactory->create();
if ($chargeId) {
$order->loadByAttribute('picpay_charge_id', $chargeId);
}
- return $order;
+ return $order->getId() ? $order : false;
}
/**
diff --git a/Helper/Tds.php b/Helper/Tds.php
new file mode 100644
index 0000000..0a9519c
--- /dev/null
+++ b/Helper/Tds.php
@@ -0,0 +1,86 @@
+quoteRepository = $quoteRepository;
+ $this->quoteCollectionFactory = $quoteCollectionFactory;
+ $this->resourcePayment = $resourcePayment;
+ parent::__construct($context);
+ }
+
+
+ /**
+ * @param string $chargeId
+ * @return \Magento\Framework\DataObject
+ */
+ public function loadQuoteByChargeId(string $chargeId)
+ {
+ $collection = $this->quoteCollectionFactory->create();
+ $collection->addFieldToFilter('picpay_charge_id', $chargeId);
+ return $collection->getFirstItem();
+ }
+
+ /**
+ * @param $quote
+ * @param $content
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ */
+ public function updateQuote($quote, $content)
+ {
+ $quote->setPicpayChallengeStatus($content['status']);
+ $quote->setPicpayMerchantId($content['merchantChargeId']);
+ $this->quoteRepository->save($quote);
+ }
+
+}
diff --git a/Model/CheckoutTds.php b/Model/CheckoutTds.php
new file mode 100644
index 0000000..31a3e61
--- /dev/null
+++ b/Model/CheckoutTds.php
@@ -0,0 +1,196 @@
+checkoutSession = $checkoutSession;
+ $this->helperData = $helperData;
+ $this->enrollmentRequest = $enrollmentRequest;
+ $this->setupRequest = $setupRequest;
+ $this->eventManager = $eventManager;
+ $this->api = $api;
+ $this->quoteRepository = $quoteRepository;
+ }
+
+ /**
+ * @param $data
+ * @return mixed|void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ public function runTdsRequest($data)
+ {
+ $enrollment = [];
+ $paymentData = $this->getPaymentData($data);
+ $setup = $this->createSetup($paymentData);
+
+ if ($setup['response']['chargeId']) {
+ $enrollment = $this->runEnrollment($setup['response']['chargeId'], $paymentData);
+ $this->processEnrollment($enrollment, $setup['response']['transactions'][0]['cardholderAuthenticationId']);
+ }
+
+ return $enrollment;
+ }
+
+ /**
+ * @param $params
+ * @return \Magento\Framework\DataObject
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ protected function getPaymentData($params)
+ {
+ $paymentData = new \Magento\Framework\DataObject();
+ $paymentData->setData($params);
+
+ $this->eventManager->dispatch(
+ 'payment_method_assign_data_picpay_checkout_cc',
+ [
+ AbstractDataAssignObserver::METHOD_CODE => 'picpay_checkout_cc',
+ AbstractDataAssignObserver::MODEL_CODE => $this->checkoutSession->getQuote()->getPayment(),
+ AbstractDataAssignObserver::DATA_CODE => $paymentData
+ ]
+ );
+ return $paymentData;
+ }
+
+ /**
+ * @param $paymentData
+ * @return mixed
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ public function createSetup($paymentData)
+ {
+ $quote = $this->checkoutSession->getQuote();
+
+ $transaction = $this->setupRequest->build([
+ 'payment' => $paymentData,
+ 'quote' => $quote,
+ 'amount' => $quote->getGrandTotal()
+ ]);
+
+ $result = $this->api->tds()->setup($transaction['request']);
+
+ if ($result['status'] == 200) {
+ $this->checkoutSession->setPicPayTdsChargeId($result['response']['chargeId']);
+ $this->checkoutSession->setPicPayTdsSetupTransaction($result['response']['transactions']);
+ return $result;
+ }
+
+ throw new \Exception('Error trying to create 3DS setup on PicPay');
+ }
+
+ /**
+ * @param $chargeId
+ * @param $paymentData
+ * @return mixed
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ public function runEnrollment($chargeId, $paymentData)
+ {
+ $quote = $this->checkoutSession->getQuote();
+ $transaction = $this->enrollmentRequest->build([
+ 'payment' => $paymentData,
+ 'quote' => $quote,
+ 'amount' => $quote->getGrandTotal(),
+ 'chargeId' => $chargeId
+ ]);
+
+ $result = $this->api->tds()->enrollment($transaction['request']);
+
+ if ($result['status'] == 200) {
+ $this->checkoutSession->setPicPayTdsChargeStatus($result['response']['chargeStatus']);
+ $this->checkoutSession->setPicPayTdsEnrollmentTransaction($result['response']['transactions']);
+ return $result;
+ }
+
+ throw new \Exception('Error trying to create 3DS setup on PicPay');
+ }
+
+ /**
+ * @param mixed $enrollment
+ * @param $cardholderAuthenticationId
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ */
+ public function processEnrollment($enrollment, $cardholderAuthenticationId): void
+ {
+ if (isset($enrollment['response']['chargeId']) && isset($enrollment['response']['transactions'][0])) {
+ $transaction = $enrollment['response']['transactions'][0];
+ $this->checkoutSession->setPicPayTdsChallengeStatus($transaction['cardholderAuthenticationStatus']);
+
+ $quote = $this->checkoutSession->getQuote();
+ $quote->setPicpayChargeId($enrollment['response']['chargeId']);
+ $quote->setPicpayChallengeStatus($transaction['cardholderAuthenticationStatus']);
+ $quote->setPicpayMerchantId($cardholderAuthenticationId);
+ $quote->setPicpayCardholderAuthId($cardholderAuthenticationId);
+ $this->quoteRepository->save($quote);
+ }
+ }
+}
diff --git a/Model/Ui/CreditCard/ConfigProvider.php b/Model/Ui/CreditCard/ConfigProvider.php
index ca464fe..a8d20d4 100644
--- a/Model/Ui/CreditCard/ConfigProvider.php
+++ b/Model/Ui/CreditCard/ConfigProvider.php
@@ -86,7 +86,9 @@ public function getConfig()
'customer_taxvat' => $customerTaxvat,
'sandbox' => (int) $this->helper->getGeneralConfig('use_sandbox'),
'icons' => $this->getPaymentIcons(),
- 'availableTypes' => $this->getCcAvailableTypes($methodCode)
+ 'availableTypes' => $this->getCcAvailableTypes($methodCode),
+ 'use_tds' => (int) $this->canUseTds($grandTotal),
+ 'place_not_authenticated_order' => (int) $this->helper->getConfig('place_not_authenticated_tds'),
],
'ccform' => [
'grandTotal' => [$methodCode => $grandTotal],
@@ -104,6 +106,14 @@ public function getConfig()
];
}
+ public function canUseTds($amount)
+ {
+ $isActive = $this->helper->getConfig('tds_active');
+ $minAmount = $this->helper->getConfig('min_tds_order_total');
+
+ return $isActive && $minAmount <= $amount;
+ }
+
/**
* Get icons for available payment methods
*
diff --git a/Model/Ui/Pix/ConfigProvider.php b/Model/Ui/Pix/ConfigProvider.php
index 1802155..081b0e6 100644
--- a/Model/Ui/Pix/ConfigProvider.php
+++ b/Model/Ui/Pix/ConfigProvider.php
@@ -73,12 +73,16 @@ public function __construct(
*/
public function getConfig()
{
+ $customer = $this->customerSession->getCustomer();
+ $customerTaxvat = ($customer && $customer->getTaxvat()) ? $customer->getTaxvat() : '';
+
return [
'payment' => [
self::CODE => [
'grand_total' => $this->checkoutSession->getQuote()->getGrandTotal(),
'sandbox' => (int) $this->helper->getGeneralConfig('use_sandbox'),
- 'checkout_instructions' => $this->helper->getConfig('checkout_instructions', self::CODE)
+ 'checkout_instructions' => $this->helper->getConfig('checkout_instructions', self::CODE),
+ 'customer_taxvat' => $customerTaxvat,
]
]
];
diff --git a/Observer/CreditCardAssignObserver.php b/Observer/CreditCardAssignObserver.php
index 1e2bd47..25ccae4 100644
--- a/Observer/CreditCardAssignObserver.php
+++ b/Observer/CreditCardAssignObserver.php
@@ -88,7 +88,12 @@ public function execute(Observer $observer)
'cc_exp_year' => $ccExpYear
]);
- $extraInfo = ['installments' => $installments, 'cc_installments' => $installments, 'cc_bin' => $ccBin];
+ $extraInfo = [
+ 'installments' => $installments,
+ 'cc_installments' => $installments,
+ 'cc_bin' => $ccBin,
+ 'use_tds_authorization' => $additionalData['use_tds_authorization'] ?? 0,
+ ];
foreach ($extraInfo as $key => $value) {
$paymentInfo->setAdditionalInformation($key, $value);
}
diff --git a/composer.json b/composer.json
index 8b6697e..28d4978 100755
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "picpay/ecommerce-integration-magento2",
- "version": "1.2.2",
+ "version": "1.3.2",
"description": "N/A",
"type": "magento2-module",
"autoload": {
diff --git a/etc/adminhtml/system/credit_card.xml b/etc/adminhtml/system/credit_card.xml
index 3c277ff..e0c3dc7 100644
--- a/etc/adminhtml/system/credit_card.xml
+++ b/etc/adminhtml/system/credit_card.xml
@@ -217,5 +217,34 @@