diff --git a/plugin/src/Controllers/ResponseController.php b/plugin/src/Controllers/ResponseController.php index e5322dc..f1ccdda 100644 --- a/plugin/src/Controllers/ResponseController.php +++ b/plugin/src/Controllers/ResponseController.php @@ -4,7 +4,9 @@ use DateTime; use DateTimeZone; +use Transbank\Plugin\Helpers\PluginLogger; use Transbank\WooCommerce\WebpayRest\WebpayplusTransbankSdk; +use Transbank\WooCommerce\WebpayRest\Helpers\TransactionResponseHandler; use Transbank\Webpay\WebpayPlus\Responses\TransactionCommitResponse; use Transbank\WooCommerce\WebpayRest\Models\Transaction; use Transbank\WooCommerce\WebpayRest\Helpers\HposHelper; @@ -24,14 +26,14 @@ class ResponseController { /** * @var array - */ - protected $pluginConfig; - protected $logger; - - /** + * @var PluginLogger * @var WebpayplusTransbankSdk + * @var TransactionResponseHandler */ - protected $webpayplusTransbankSdk; + protected array $pluginConfig; + protected PluginLogger $logger; + protected WebpayplusTransbankSdk $webpayplusTransbankSdk; + protected TransactionResponseHandler $transactionResponseHandler; /** * ResponseController constructor. @@ -43,6 +45,7 @@ public function __construct(array $pluginConfig) $this->logger = TbkFactory::createLogger(); $this->pluginConfig = $pluginConfig; $this->webpayplusTransbankSdk = TbkFactory::createWebpayplusTransbankSdk(); + $this->transactionResponseHandler = new TransactionResponseHandler(); } /** @@ -57,7 +60,7 @@ public function response($requestMethod, $params) $this->logger->logInfo('Request: payload -> ' . json_encode($params)); try { - $transaction = $this->webpayplusTransbankSdk->handleRequestFromTbkReturn($params); + $transaction = $this->transactionResponseHandler->handleRequestFromTbkReturn($params); $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); $commitResponse = $this->webpayplusTransbankSdk->commitTransaction($transaction->order_id, $transaction->token); $this->completeWooCommerceOrder($wooCommerceOrder, $commitResponse, $transaction); @@ -66,13 +69,12 @@ public function response($requestMethod, $params) 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $transaction ]); - return wp_redirect($wooCommerceOrder->get_checkout_order_received_url()); + $redirectUrl = $wooCommerceOrder->get_checkout_order_received_url(); } catch (TimeoutWebpayException $e) { $this->throwError($e->getMessage()); do_action('transbank_webpay_plus_timeout_on_form'); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_TIMEOUT); - return wp_redirect($urlWithErrorCode); + $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_TIMEOUT); } catch (UserCancelWebpayException $e) { $params = ['transbank_webpayplus_cancelled_order' => 1]; $redirectUrl = add_query_arg($params, wc_get_checkout_url()); @@ -81,14 +83,12 @@ public function response($requestMethod, $params) $this->setOrderAsCancelledByUser($wooCommerceOrder, $transaction); do_action('transbank_webpay_plus_transaction_cancelled_by_user', $wooCommerceOrder, $transaction); - $urlWithErrorCode = $this->addErrorQueryParams($redirectUrl, BlocksHelper::WEBPAY_USER_CANCELED); - return wp_safe_redirect($urlWithErrorCode); + $redirectUrl = $this->addErrorQueryParams($redirectUrl, BlocksHelper::WEBPAY_USER_CANCELED); } catch (DoubleTokenWebpayException $e) { $this->throwError($e->getMessage()); do_action('transbank_webpay_plus_unexpected_error'); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_DOUBLE_TOKEN); - return wp_redirect($urlWithErrorCode); + $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_DOUBLE_TOKEN); } catch (InvalidStatusWebpayException $e) { $errorMessage = 'No se puede confirmar la transacción, estado de transacción invalido.'; $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); @@ -98,8 +98,7 @@ public function response($requestMethod, $params) 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $e->getTransaction() ]); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_INVALID_STATUS); - return wp_redirect($urlWithErrorCode); + $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_INVALID_STATUS); } catch (RejectedCommitWebpayException $e) { $transaction = $e->getTransaction(); $commitResponse = $e->getCommitResponse(); @@ -111,7 +110,7 @@ public function response($requestMethod, $params) 'transbankTransaction' => $transaction, 'transbankResponse' => $commitResponse ]); - return wp_redirect($wooCommerceOrder->get_checkout_order_received_url()); + $redirectUrl = $wooCommerceOrder->get_checkout_order_received_url(); } catch (CommitWebpayException $e) { $errorMessage = 'Error al confirmar la transacción de Transbank'; $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); @@ -121,8 +120,7 @@ public function response($requestMethod, $params) 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $e->getTransaction() ]); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_COMMIT_ERROR); - return wp_redirect($urlWithErrorCode); + $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_COMMIT_ERROR); } catch (AlreadyProcessedException $e) { $errorMessage = 'Error al confirmar la transacción, ya fue procesada anteriormente'; $transaction = $e->getTransaction(); @@ -130,34 +128,16 @@ public function response($requestMethod, $params) $wooCommerceOrder = $this->getWooCommerceOrderById($orderId); $wooCommerceOrder->add_order_note($errorMessage); - if ($e->getFlow() == WebpayplusTransbankSdk::WEBPAY_NORMAL_FLOW) { - return wp_redirect($wooCommerceOrder->get_checkout_order_received_url()); - } - - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_ALREADY_PROCESSED); - return wp_redirect($urlWithErrorCode); + $e->getFlow() == TransactionResponseHandler::WEBPAY_NORMAL_FLOW + ? $redirectUrl = $wooCommerceOrder->get_checkout_order_received_url() + : $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_ALREADY_PROCESSED); } catch (\Exception $e) { $this->throwError($e->getMessage()); do_action('transbank_webpay_plus_unexpected_error'); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_EXCEPTION); - wp_redirect($urlWithErrorCode); - } - } - - /** - * @param $data - * - * @return |null - */ - protected function getTokenWs($data) - { - $token_ws = isset($data['token_ws']) ? $data['token_ws'] : (isset($data['TBK_TOKEN']) ? $data['TBK_TOKEN'] : null); - if (!isset($token_ws)) { - $this->throwError('No se encontró el token'); - wp_redirect(wc_get_checkout_url()); + $redirectUrl = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_EXCEPTION); } - return $token_ws; + return wp_redirect($redirectUrl); } /** diff --git a/plugin/src/Helpers/TransactionResponseHandler.php b/plugin/src/Helpers/TransactionResponseHandler.php new file mode 100644 index 0000000..94c8983 --- /dev/null +++ b/plugin/src/Helpers/TransactionResponseHandler.php @@ -0,0 +1,174 @@ +webpayPlusTransaction = TbkFactory::createWebpayplusTransbankSdk(); + } + + private function isTransactionProcessed(string $token): bool + { + $transaction = Transaction::getByToken($token); + $status = $transaction->status; + + return $status != Transaction::STATUS_INITIALIZED; + } + + private function handleProcessedTransaction(string $token) + { + $transaction = get_object_vars(Transaction::getByToken($token)) ?? null; + $buyOrder = $transaction['buy_order'] ?? null; + $status = $transaction['status'] ?? null; + $logMessage = self::WEBPAY_ALREADY_PROCESSED_MESSAGE; + + if ($status == Transaction::STATUS_APPROVED) { + $this->webpayPlusTransaction->logInfoData($buyOrder, $logMessage, $transaction); + throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_NORMAL_FLOW); + } + + if ($status == Transaction::STATUS_TIMEOUT) { + $logMessage = self::WEBPAY_TIMEOUT_FLOW_MESSAGE; + $this->webpayPlusTransaction->logInfoData($buyOrder, $logMessage, $transaction); + throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_TIMEOUT_FLOW); + } + + if ($status == Transaction::STATUS_ABORTED_BY_USER) { + $logMessage = self::WEBPAY_ABORTED_FLOW_MESSAGE; + $this->webpayPlusTransaction->logInfoData($buyOrder, $logMessage, $transaction); + throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_ABORTED_FLOW); + } + + if ($status == Transaction::STATUS_FAILED) { + $logMessage = self::WEBPAY_FAILED_FLOW_MESSAGE; + $this->webpayPlusTransaction->logInfoData($buyOrder, $logMessage, $transaction); + throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_ERROR_FLOW); + } + } + + private function detectFlow(array $params): string + { + $tokenWs = $params['token_ws'] ?? null; + $tbkToken = $params['TBK_TOKEN'] ?? null; + $tbkSessionId = $params['TBK_ID_SESION'] ?? null; + + $flow = self::WEBPAY_ERROR_FLOW; + + if ($tokenWs && !$tbkToken && !$tbkSessionId) { + $flow = self::WEBPAY_NORMAL_FLOW; + } + if ($tbkSessionId && !$tbkToken && !$tokenWs) { + $flow = self::WEBPAY_TIMEOUT_FLOW; + } + if ($tbkToken && $tbkSessionId && !$tokenWs) { + $flow = self::WEBPAY_ABORTED_FLOW; + } + return $flow; + } + + public function handleRequestFromTbkReturn(array $params) + { + $tokenWs = $params['token_ws'] ?? null; + $tbkToken = $params['TBK_TOKEN'] ?? null; + $sessionId = $params['TBK_ID_SESION'] ?? null; + $buyOrder = $params['TBK_ORDEN_COMPRA'] ?? null; + $flow = $this->detectFlow($params); + + switch ($flow) { + case self::WEBPAY_NORMAL_FLOW: + return $this->handleNormalFlow($tokenWs); + case self::WEBPAY_TIMEOUT_FLOW: + $this->handleTimeoutFlow($sessionId, $buyOrder); + break; + case self::WEBPAY_ABORTED_FLOW: + $this->handleAbortedFlow($tbkToken); + break; + default: + $this->handleErrorFlow($tokenWs, $tbkToken); + break; + } + } + + private function handleNormalFlow(string $token) + { + $this->webpayPlusTransaction->logInfo("Flujo normal detectado, token: $token"); + + if ($this->isTransactionProcessed($token)) { + $this->handleProcessedTransaction($token); + } + + return Transaction::getByToken($token); + } + + private function handleTimeoutFlow(string $sessionId, string $buyOrder) + { + $this->webpayPlusTransaction->logInfo("Flujo de timeout detectado, sessionId: $sessionId, buyOrder: $buyOrder"); + $transaction = Transaction::getByBuyOrderAndSessionId($buyOrder, $sessionId) ?? null; + $token = $transaction->token ?? null; + + if ($this->isTransactionProcessed($token)) { + $this->handleProcessedTransaction($token); + } + + $errorMessage = self::WEBPAY_TIMEOUT_FLOW_MESSAGE; + $orderId = $transaction->order_id ?? 0; + $data = [ + 'TBK_ID_SESION' => $sessionId, + 'TBK_ORDEN_COMPRA' => $buyOrder + ]; + $this->webpayPlusTransaction->errorExecution($orderId, 'commit', $data, 'TimeoutWebpayException', $errorMessage, $errorMessage); + $this->webpayPlusTransaction->saveTransactionWithErrorByTransaction($transaction, 'TimeoutWebpayException', $errorMessage); + throw new TimeoutWebpayException($errorMessage, $buyOrder, $sessionId, $transaction); + } + + private function handleAbortedFlow(string $token) + { + $this->webpayPlusTransaction->logInfo("Flujo de pago abortado detectado, token: $token"); + + if ($this->isTransactionProcessed($token)) { + $this->handleProcessedTransaction($token); + } + + $errorMessage = self::WEBPAY_ABORTED_FLOW_MESSAGE; + $transaction = $this->webpayPlusTransaction->saveTransactionWithErrorByToken($token, 'UserCancelWebpayException', $errorMessage); + $this->webpayPlusTransaction->errorExecution($transaction->order_id, 'commit', $token, 'UserCancelWebpayException', $errorMessage, $errorMessage); + throw new UserCancelWebpayException($errorMessage, $token, $transaction); + } + + private function handleErrorFlow(string $token, string $tbkToken) + { + $this->webpayPlusTransaction->logInfo("Flujo con error en el formulario detectado, token: $token"); + + if ($this->isTransactionProcessed($token)) { + $this->handleProcessedTransaction($token); + } + + $errorMessage = self::WEBPAY_ERROR_FLOW_MESSAGE; + $transaction = $this->webpayPlusTransaction->saveTransactionWithErrorByToken($tbkToken, 'DoubleTokenWebpayException', $errorMessage); + $this->webpayPlusTransaction->errorExecution($transaction->order_id, 'commit', $token, 'DoubleTokenWebpayException', $errorMessage, $errorMessage); + throw new DoubleTokenWebpayException($errorMessage, $tbkToken, $token, $transaction); + } +} diff --git a/plugin/src/WebpayplusTransbankSdk.php b/plugin/src/WebpayplusTransbankSdk.php index fa7f36a..8103913 100644 --- a/plugin/src/WebpayplusTransbankSdk.php +++ b/plugin/src/WebpayplusTransbankSdk.php @@ -8,10 +8,6 @@ use Transbank\WooCommerce\WebpayRest\Helpers\ErrorUtil; use Transbank\WooCommerce\WebpayRest\Helpers\MaskData; use Transbank\Webpay\WebpayPlus\Transaction as WebpayPlusTransaction; -use Transbank\Plugin\Exceptions\Webpay\AlreadyProcessedException; -use Transbank\Plugin\Exceptions\Webpay\TimeoutWebpayException; -use Transbank\Plugin\Exceptions\Webpay\UserCancelWebpayException; -use Transbank\Plugin\Exceptions\Webpay\DoubleTokenWebpayException; use Transbank\Plugin\Exceptions\Webpay\CommitWebpayException; use Transbank\Plugin\Exceptions\Webpay\InvalidStatusWebpayException; use Transbank\Plugin\Exceptions\Webpay\RejectedCommitWebpayException; @@ -31,17 +27,6 @@ class WebpayplusTransbankSdk extends TransbankSdk const OPTION_KEY = 'woocommerce_transbank_webpay_plus_rest_settings'; - const WEBPAY_NORMAL_FLOW = 'Normal'; - const WEBPAY_TIMEOUT_FLOW = 'Timeout'; - const WEBPAY_ABORTED_FLOW = 'Aborted'; - const WEBPAY_ERROR_FLOW = 'Error'; - - const WEBPAY_ALREADY_PROCESSED_MESSAGE = 'La transacción fue procesada anteriormente.'; - const WEBPAY_FAILED_FLOW_MESSAGE = 'Transacción no autorizada.'; - const WEBPAY_TIMEOUT_FLOW_MESSAGE = 'Tiempo excedido en el formulario de Webpay.'; - const WEBPAY_ABORTED_FLOW_MESSAGE = 'Orden anulada por el usuario.'; - const WEBPAY_ERROR_FLOW_MESSAGE = 'Orden cancelada por un error en el formulario de pago.'; - /** * @var WebpayPlusTransaction */ @@ -90,7 +75,7 @@ protected function errorExecutionTbkApi($orderId, $service, $input, $error, $ori ); } - protected function errorExecution($orderId, $service, $data, $error, $originalError, $customError) + public function errorExecution($orderId, $service, $data, $error, $originalError, $customError) { $this->logErrorWithOrderId($orderId, $service, $data, $error, $originalError, $customError); $this->createTransbankExecutionErrorLogBase( @@ -380,144 +365,5 @@ public function saveTransactionWithErrorByToken($token, $error, $detailError) $this->saveTransactionWithErrorByTransaction($transaction, $error, $detailError); return $transaction; } - - private function isTransactionProcessed(string $token): bool - { - $transaction = Transaction::getByToken($token); - $status = $transaction->status; - - return $status != Transaction::STATUS_INITIALIZED; - } - - private function handleProcessedTransaction(string $token) - { - $transaction = get_object_vars(Transaction::getByToken($token)) ?? null; - $buyOrder = $transaction['buy_order'] ?? null; - $status = $transaction['status'] ?? null; - $logMessage = self::WEBPAY_ALREADY_PROCESSED_MESSAGE; - - if ($status == Transaction::STATUS_APPROVED) { - $this->logInfoData($buyOrder, $logMessage, $transaction); - throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_NORMAL_FLOW); - } - - if ($status == Transaction::STATUS_TIMEOUT) { - $logMessage = self::WEBPAY_TIMEOUT_FLOW_MESSAGE; - $this->logInfoData($buyOrder, $logMessage, $transaction); - throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_TIMEOUT_FLOW); - } - - if ($status == Transaction::STATUS_ABORTED_BY_USER) { - $logMessage = self::WEBPAY_ABORTED_FLOW_MESSAGE; - $this->logInfoData($buyOrder, $logMessage, $transaction); - throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_ABORTED_FLOW); - } - - if ($status == Transaction::STATUS_FAILED) { - $logMessage = self::WEBPAY_FAILED_FLOW_MESSAGE; - $this->logInfoData($buyOrder, $logMessage, $transaction); - throw new AlreadyProcessedException($logMessage, $transaction, self::WEBPAY_ERROR_FLOW); - } - } - - private function detectFlow(array $params): string - { - $tokenWs = $params['token_ws'] ?? null; - $tbkToken = $params['TBK_TOKEN'] ?? null; - $tbkSessionId = $params['TBK_ID_SESION'] ?? null; - - if ($tokenWs && !$tbkToken && !$tbkSessionId) { - return self::WEBPAY_NORMAL_FLOW; - } - if ($tbkSessionId && !$tbkToken && !$tokenWs) { - return self::WEBPAY_TIMEOUT_FLOW; - } - if ($tbkToken && $tbkSessionId && !$tokenWs) { - return self::WEBPAY_ABORTED_FLOW; - } - return self::WEBPAY_ERROR_FLOW; - } - - public function handleRequestFromTbkReturn(array $params) - { - $tokenWs = $params['token_ws'] ?? null; - $tbkToken = $params['TBK_TOKEN'] ?? null; - $sessionId = $params['TBK_ID_SESION'] ?? null; - $buyOrder = $params['TBK_ORDEN_COMPRA'] ?? null; - $flow = $this->detectFlow($params); - - if ($flow == self::WEBPAY_NORMAL_FLOW) { - return $this->handleNormalFlow($tokenWs); - } - if ($flow == self::WEBPAY_TIMEOUT_FLOW) { - return $this->handleTimeoutFlow($sessionId, $buyOrder); - } - if ($flow == self::WEBPAY_ABORTED_FLOW) { - return $this->handleAbortedFlow($tbkToken); - } - return $this->handleErrorFlow($tokenWs, $tbkToken); - } - - private function handleNormalFlow(string $token) - { - $this->logInfo("Flujo normal detectado, token: $token"); - - if ($this->isTransactionProcessed($token)) { - return $this->handleProcessedTransaction($token); - } - - return Transaction::getByToken($token); - } - - private function handleTimeoutFlow(string $sessionId, string $buyOrder) - { - $this->logInfo("Flujo de timeout detectado, sessionId: $sessionId, buyOrder: $buyOrder"); - $transaction = Transaction::getByBuyOrderAndSessionId($buyOrder, $sessionId) ?? null; - $token = $transaction->token ?? null; - - if ($this->isTransactionProcessed($token)) { - return $this->handleProcessedTransaction($token); - } - - $errorMessage = self::WEBPAY_TIMEOUT_FLOW_MESSAGE; - $orderId = $transaction->order_id ?? 0; - $data = [ - 'TBK_ID_SESION' => $sessionId, - 'TBK_ORDEN_COMPRA' => $buyOrder - ]; - $this->errorExecution($orderId, 'commit', $data, 'TimeoutWebpayException', $errorMessage, $errorMessage); - $this->saveTransactionWithErrorByTransaction($transaction, 'TimeoutWebpayException', $errorMessage); - throw new TimeoutWebpayException($errorMessage, $buyOrder, $sessionId, $transaction); - } - - private function handleAbortedFlow(string $token) - { - $this->logInfo("Flujo de pago abortado detectado, token: $token"); - - if ($this->isTransactionProcessed($token)) { - return $this->handleProcessedTransaction($token); - } - - $errorMessage = self::WEBPAY_ABORTED_FLOW_MESSAGE; - $transaction = $this->saveTransactionWithErrorByToken($token, 'UserCancelWebpayException', $errorMessage); - $this->errorExecution($transaction->order_id, 'commit', $token, 'UserCancelWebpayException', $errorMessage, $errorMessage); - throw new UserCancelWebpayException($errorMessage, $token, $transaction); - } - - private function handleErrorFlow(string $token, string $tbkToken) - { - $this->logInfo("Flujo con error en el formulario detectado, token: $token"); - - if ($this->isTransactionProcessed($token)) { - return $this->handleProcessedTransaction($token); - } - - $errorMessage = self::WEBPAY_ERROR_FLOW_MESSAGE; - $transaction = $this->saveTransactionWithErrorByToken($tbkToken, 'DoubleTokenWebpayException', $errorMessage); - $this->errorExecution($transaction->order_id, 'commit', $token, 'DoubleTokenWebpayException', $errorMessage, $errorMessage); - throw new DoubleTokenWebpayException($errorMessage, $tbkToken, $token, $transaction); - } - - }