diff --git a/plugin/shared/Exceptions/Webpay/AlreadyProcessedException.php b/plugin/shared/Exceptions/Webpay/AlreadyProcessedException.php new file mode 100644 index 00000000..65c0d411 --- /dev/null +++ b/plugin/shared/Exceptions/Webpay/AlreadyProcessedException.php @@ -0,0 +1,32 @@ +transaction = $transaction; + $this->flow = $flow; + parent::__construct($message, $previous); + } + + public function getTransaction() + { + return $this->transaction; + } + + public function getFlow() + { + return $this->flow; + } +} diff --git a/plugin/shared/Exceptions/Webpay/WithoutTokenWebpayException.php b/plugin/shared/Exceptions/Webpay/WithoutTokenWebpayException.php deleted file mode 100644 index 3314c615..00000000 --- a/plugin/shared/Exceptions/Webpay/WithoutTokenWebpayException.php +++ /dev/null @@ -1,10 +0,0 @@ - { const noticeMessage = productNoticeData[statusCode]['message']; const notificationType = productNoticeData[statusCode]['type']; switch (notificationType){ - case noticeTypes.SUCESS: + case noticeTypes.SUCCESS: wp.data.dispatch('core/notices').createSuccessNotice( noticeMessage, { context: 'wc/checkout' } ); break; case noticeTypes.ERROR: diff --git a/plugin/src/Controllers/ResponseController.php b/plugin/src/Controllers/ResponseController.php index 83cb1e6a..e5322dc8 100644 --- a/plugin/src/Controllers/ResponseController.php +++ b/plugin/src/Controllers/ResponseController.php @@ -4,10 +4,12 @@ use DateTime; use DateTimeZone; +use Transbank\WooCommerce\WebpayRest\WebpayplusTransbankSdk; use Transbank\Webpay\WebpayPlus\Responses\TransactionCommitResponse; use Transbank\WooCommerce\WebpayRest\Models\Transaction; use Transbank\WooCommerce\WebpayRest\Helpers\HposHelper; use Transbank\WooCommerce\WebpayRest\Helpers\BlocksHelper; +use Transbank\Plugin\Exceptions\Webpay\AlreadyProcessedException; use Transbank\Plugin\Exceptions\Webpay\TimeoutWebpayException; use Transbank\Plugin\Exceptions\Webpay\UserCancelWebpayException; use Transbank\Plugin\Exceptions\Webpay\DoubleTokenWebpayException; @@ -24,11 +26,10 @@ class ResponseController * @var array */ protected $pluginConfig; - protected $logger; /** - * @var Transbank\WooCommerce\WebpayRest\WebpayplusTransbankSdk + * @var WebpayplusTransbankSdk */ protected $webpayplusTransbankSdk; @@ -48,64 +49,46 @@ public function __construct(array $pluginConfig) * @throws \GuzzleHttp\Exception\GuzzleException * @throws \Transbank\Plugin\Exceptions\TokenNotFoundOnDatabaseException */ - public function response($postData) + + public function response($requestMethod, $params) { + $this->logger->logInfo('Procesando retorno desde formulario de Webpay.'); + $this->logger->logInfo("Request: method -> $requestMethod"); + $this->logger->logInfo('Request: payload -> ' . json_encode($params)); + try { - $transaction = $this->webpayplusTransbankSdk->processRequestFromTbkReturn($_SERVER, $_GET, $_POST); + $transaction = $this->webpayplusTransbankSdk->handleRequestFromTbkReturn($params); $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); - if ($wooCommerceOrder->is_paid()) { - // TODO: Revisar porqué no se muestra el mensaje de abajo. H4x - //SessionMessageHelper::set('Orden ya ha sido pagada.', 'notice'); - $errorMessage = 'El usuario intentó pagar esta orden nuevamente, cuando esta ya estaba pagada.'; - $this->webpayplusTransbankSdk->logError($errorMessage); - $this->webpayplusTransbankSdk->saveTransactionWithErrorByTransaction($transaction, 'transbank_webpay_plus_already_paid_transaction', $errorMessage); - $wooCommerceOrder->add_order_note($errorMessage); - do_action('transbank_webpay_plus_already_paid_transaction', $wooCommerceOrder); - return wp_safe_redirect($wooCommerceOrder->get_checkout_order_received_url()); - } - if (!$wooCommerceOrder->needs_payment()) { - // TODO: Revisar porqué no se muestra el mensaje de abajo. - //SessionMessageHelper::set('El estado de la orden no permite que sea pagada. Comuníquese con la tienda.', 'error'); - $errorMessage = 'El usuario intentó pagar la orden cuando estaba en estado: '.$wooCommerceOrder->get_status().".\n".'No se ejecutó captura del pago de esta solicitud.'; - $this->webpayplusTransbankSdk->logError($errorMessage); - $this->webpayplusTransbankSdk->saveTransactionWithErrorByTransaction($transaction, 'transbank_webpay_plus_paying_transaction_that_does_not_needs_payment', $errorMessage); - $wooCommerceOrder->add_order_note($errorMessage); - do_action('transbank_webpay_plus_paying_transaction_that_does_not_needs_payment', $wooCommerceOrder); - return wp_safe_redirect($wooCommerceOrder->get_checkout_order_received_url()); - } $commitResponse = $this->webpayplusTransbankSdk->commitTransaction($transaction->order_id, $transaction->token); $this->completeWooCommerceOrder($wooCommerceOrder, $commitResponse, $transaction); + do_action('wc_transbank_webpay_plus_transaction_approved', [ 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $transaction ]); return wp_redirect($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); - wp_redirect($urlWithErrorCode); + return wp_redirect($urlWithErrorCode); } catch (UserCancelWebpayException $e) { $params = ['transbank_webpayplus_cancelled_order' => 1]; $redirectUrl = add_query_arg($params, wc_get_checkout_url()); $transaction = $e->getTransaction(); $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); - if ($transaction->status !== Transaction::STATUS_INITIALIZED || $wooCommerceOrder->is_paid()) { - $wooCommerceOrder->add_order_note('El usuario canceló la transacción en el formulario de pago, pero esta orden ya estaba pagada o en un estado diferente a INICIALIZADO'); - wp_safe_redirect($redirectUrl); - return; - } $this->setOrderAsCancelledByUser($wooCommerceOrder, $transaction); + do_action('transbank_webpay_plus_transaction_cancelled_by_user', $wooCommerceOrder, $transaction); $urlWithErrorCode = $this->addErrorQueryParams($redirectUrl, BlocksHelper::WEBPAY_USER_CANCELED); - wp_safe_redirect($urlWithErrorCode); - return; + return wp_safe_redirect($urlWithErrorCode); } 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); - wp_redirect($urlWithErrorCode); + return wp_redirect($urlWithErrorCode); } catch (InvalidStatusWebpayException $e) { $errorMessage = 'No se puede confirmar la transacción, estado de transacción invalido.'; $wooCommerceOrder = $this->getWooCommerceOrderById($transaction->order_id); @@ -115,7 +98,6 @@ public function response($postData) 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $e->getTransaction() ]); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_INVALID_STATUS); return wp_redirect($urlWithErrorCode); } catch (RejectedCommitWebpayException $e) { @@ -129,7 +111,6 @@ public function response($postData) 'transbankTransaction' => $transaction, 'transbankResponse' => $commitResponse ]); - return wp_redirect($wooCommerceOrder->get_checkout_order_received_url()); } catch (CommitWebpayException $e) { $errorMessage = 'Error al confirmar la transacción de Transbank'; @@ -140,16 +121,27 @@ public function response($postData) 'order' => $wooCommerceOrder->get_data(), 'transbankTransaction' => $e->getTransaction() ]); - $urlWithErrorCode = $this->addErrorQueryParams(wc_get_checkout_url(), BlocksHelper::WEBPAY_COMMIT_ERROR); return wp_redirect($urlWithErrorCode); + } catch (AlreadyProcessedException $e) { + $errorMessage = 'Error al confirmar la transacción, ya fue procesada anteriormente'; + $transaction = $e->getTransaction(); + $orderId = $transaction['order_id']; + $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); } 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); } - return ""; } /** @@ -189,8 +181,7 @@ protected function completeWooCommerceOrder( WC_Order $wooCommerceOrder, TransactionCommitResponse $commitResponse, $webpayTransaction - ) - { + ) { $status = TbkResponseUtil::getStatus($commitResponse->getStatus()); $paymentType = TbkResponseUtil::getPaymentType($commitResponse->getPaymentTypeCode()); $date_accepted = new DateTime($commitResponse->getTransactionDate(), new DateTimeZone('UTC')); @@ -221,7 +212,8 @@ protected function completeWooCommerceOrder( $maskedBuyOrder = $this->webpayplusTransbankSdk->dataMasker->maskBuyOrder($commitResponse->getBuyOrder()); $this->logger->logInfo( - 'C.5. Transacción con commit exitoso en Transbank y guardado => OC: '.$maskedBuyOrder); + 'C.5. Transacción con commit exitoso en Transbank y guardado => OC: ' . $maskedBuyOrder + ); $this->setAfterPaymentOrderStatus($wooCommerceOrder); } @@ -235,8 +227,7 @@ protected function setWooCommerceOrderAsFailed( WC_Order $wooCommerceOrder, $webpayTransaction, TransactionCommitResponse $commitResponse - ) - { + ) { $_SESSION['woocommerce_order_failed'] = true; $wooCommerceOrder->update_status('failed'); if ($commitResponse !== null) { @@ -249,14 +240,14 @@ protected function setWooCommerceOrderAsFailed( $webpayTransaction->token ); - $this->logger->logError('C.5. Respuesta de tbk commit fallido => token: '.$webpayTransaction->token); + $this->logger->logError('C.5. Respuesta de tbk commit fallido => token: ' . $webpayTransaction->token); $this->logger->logError(json_encode($commitResponse)); } Transaction::update( $webpayTransaction->id, [ - 'status' => Transaction::STATUS_FAILED, + 'status' => Transaction::STATUS_FAILED, 'transbank_response' => json_encode($commitResponse), ] ); @@ -329,18 +320,19 @@ protected function throwError(string $msg) /** * @param WC_Order $order */ - private function setAfterPaymentOrderStatus(WC_Order $order){ + private function setAfterPaymentOrderStatus(WC_Order $order) + { $status = $this->pluginConfig['STATUS_AFTER_PAYMENT']; - if ($status == ''){ + if ($status == '') { $order->payment_complete(); - } - else{ + } else { $order->payment_complete(); $order->update_status($status); } } - protected function addErrorQueryParams($url, $errorCode) { + protected function addErrorQueryParams($url, $errorCode) + { $params = ['transbank_status' => $errorCode]; return add_query_arg($params, $url); } diff --git a/plugin/src/Helpers/BlocksHelper.php b/plugin/src/Helpers/BlocksHelper.php index eee10b79..3b8e6154 100644 --- a/plugin/src/Helpers/BlocksHelper.php +++ b/plugin/src/Helpers/BlocksHelper.php @@ -13,7 +13,7 @@ class BlocksHelper const ONECLICK_FINISH_ERROR = 5; const ONECLICK_REJECTED_INSCRIPTION = 6; const WEBPAY_APPROVED = 7; - const WEBPAY_ALREADY_PAID = 8; + const WEBPAY_ALREADY_PROCESSED = 8; const WEBPAY_INVALID_ORDER_STATUS = 9; const WEBPAY_TIMEOUT = 10; const WEBPAY_USER_CANCELED_ALREADY_PAID = 11; @@ -24,14 +24,16 @@ class BlocksHelper const WEBPAY_COMMIT_ERROR = 16; const WEBPAY_EXCEPTION = 17; - public static function checkBlocksEnabled() { + public static function checkBlocksEnabled() + { $checkout_page = wc_get_page_id('checkout'); return has_block('woocommerce/checkout', $checkout_page); } - public static function addLegacyNotices($message, $type) { + public static function addLegacyNotices($message, $type) + { if (self::checkBlocksEnabled()) { return; } diff --git a/plugin/src/Models/Transaction.php b/plugin/src/Models/Transaction.php index 58e7a250..32114df3 100644 --- a/plugin/src/Models/Transaction.php +++ b/plugin/src/Models/Transaction.php @@ -10,9 +10,10 @@ class Transaction extends BaseModel const STATUS_PREPARED = 'prepared'; const STATUS_INITIALIZED = 'initialized'; - const STATUS_FAILED = 'failed'; - const STATUS_ABORTED_BY_USER = 'aborted_by_user'; const STATUS_APPROVED = 'approved'; + const STATUS_TIMEOUT = 'timeout'; + const STATUS_ABORTED_BY_USER = 'aborted_by_user'; + const STATUS_FAILED = 'failed'; const PRODUCT_WEBPAY_PLUS = 'webpay_plus'; const PRODUCT_WEBPAY_ONECLICK = 'webpay_oneclick'; diff --git a/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php b/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php index 3fdbe9d2..c8335fbd 100644 --- a/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php +++ b/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php @@ -60,12 +60,12 @@ public function __construct() ]; $this->config = [ - 'MODO' => trim($this->get_option('webpay_rest_environment', 'TEST')), - 'COMMERCE_CODE' => trim( + 'MODO' => trim($this->get_option('webpay_rest_environment', 'TEST')), + 'COMMERCE_CODE' => trim( $this->get_option('webpay_rest_commerce_code', WebpayPlus::DEFAULT_COMMERCE_CODE) ), - 'API_KEY' => $this->get_option('webpay_rest_api_key', WebpayPlus::DEFAULT_API_KEY), - 'ECOMMERCE' => 'woocommerce', + 'API_KEY' => $this->get_option('webpay_rest_api_key', WebpayPlus::DEFAULT_API_KEY), + 'ECOMMERCE' => 'woocommerce', 'STATUS_AFTER_PAYMENT' => $this->get_option('webpay_rest_after_payment_order_status', ''), ]; @@ -166,14 +166,14 @@ public function init_form_fields() $this->form_fields = [ 'enabled' => [ - 'title' => __('Activar/Desactivar', 'transbank_webpay_plus_rest'), - 'type' => 'checkbox', + 'title' => __('Activar/Desactivar', 'transbank_webpay_plus_rest'), + 'type' => 'checkbox', 'default' => 'yes', ], 'webpay_rest_environment' => [ - 'title' => __('Ambiente', 'transbank_webpay_plus_rest'), - 'type' => 'select', - 'desc_tip' => $environmentDescription, + 'title' => __('Ambiente', 'transbank_webpay_plus_rest'), + 'type' => 'select', + 'desc_tip' => $environmentDescription, 'options' => [ 'TEST' => __('Integración', 'transbank_webpay_plus_rest'), 'LIVE' => __('Producción', 'transbank_webpay_plus_rest'), @@ -181,34 +181,34 @@ public function init_form_fields() 'default' => 'TEST', ], 'webpay_rest_commerce_code' => [ - 'title' => __('Código de Comercio Producción', 'transbank_webpay_plus_rest'), + 'title' => __('Código de Comercio Producción', 'transbank_webpay_plus_rest'), 'placeholder' => 'Ej: 597012345678', - 'desc_tip' => $commerceCodeDescription, - 'type' => 'text', - 'default' => '', + 'desc_tip' => $commerceCodeDescription, + 'type' => 'text', + 'default' => '', ], 'webpay_rest_api_key' => [ - 'title' => __('API Key (llave secreta) producción', 'transbank_webpay_plus_rest'), - 'type' => 'password', + 'title' => __('API Key (llave secreta) producción', 'transbank_webpay_plus_rest'), + 'type' => 'password', 'placeholder' => 'Ej: XXXXXXXXXXXXXXXXXXXXXXXXXXXX', - 'desc_tip' => $apiKeyDescription, - 'default' => '', + 'desc_tip' => $apiKeyDescription, + 'default' => '', ], 'webpay_rest_after_payment_order_status' => [ - 'title' => __('Order Status', 'transbank_webpay_plus_rest'), - 'type' => 'select', - 'desc_tip' => 'Define el estado de la orden luego del pago exitoso.', + 'title' => __('Order Status', 'transbank_webpay_plus_rest'), + 'type' => 'select', + 'desc_tip' => 'Define el estado de la orden luego del pago exitoso.', 'options' => [ '' => 'Default', 'processing' => 'Processing', - 'completed' => 'Completed', + 'completed' => 'Completed', ], 'default' => '', ], 'webpay_rest_payment_gateway_description' => [ - 'title' => __('Descripción', 'transbank_webpay_plus_rest'), - 'type' => 'textarea', - 'desc_tip' => 'Define la descripción del medio de pago.', + 'title' => __('Descripción', 'transbank_webpay_plus_rest'), + 'type' => 'textarea', + 'desc_tip' => 'Define la descripción del medio de pago.', 'default' => self::PAYMENT_GW_DESCRIPTION, 'class' => 'admin-textarea' ] @@ -221,14 +221,11 @@ public function init_form_fields() public function check_ipn_response() { ob_clean(); - if (isset($_POST)) { - header('HTTP/1.1 200 OK'); - $data = ($_SERVER['REQUEST_METHOD'] === 'GET') ? $_GET : $_POST; + header('HTTP/1.1 200 OK'); + $requestMethod = $_SERVER['REQUEST_METHOD']; + $params = ($requestMethod === 'GET') ? $_GET : $_POST; - return (new ResponseController($this->config))->response($data); - } else { - echo 'Ocurrió un error al procesar su compra'; - } + return (new ResponseController($this->config))->response($requestMethod, $params); } @@ -248,7 +245,7 @@ public function process_payment($order_id) $createResponse = $this->webpayplusTransbankSdk->createTransaction($order->get_id(), $amount, $returnUrl); do_action('transbank_webpay_plus_transaction_started', $order, $createResponse->token); return [ - 'result' => 'success', + 'result' => 'success', 'redirect' => $createResponse->url . '?token_ws=' . $createResponse->token, ]; } catch (CreateWebpayException $e) { diff --git a/plugin/src/WebpayplusTransbankSdk.php b/plugin/src/WebpayplusTransbankSdk.php index cf9c89eb..fa7f36a2 100644 --- a/plugin/src/WebpayplusTransbankSdk.php +++ b/plugin/src/WebpayplusTransbankSdk.php @@ -7,6 +7,8 @@ use Transbank\WooCommerce\WebpayRest\Models\Transaction; 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; @@ -29,8 +31,19 @@ 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 \Transbank\Webpay\WebpayPlus\Transaction + * @var WebpayPlusTransaction */ protected $webpayplusTransaction; @@ -38,7 +51,7 @@ public function __construct($log, $environment, $commerceCode, $apiKey) { $this->log = $log; $this->options = $this->createOptions($environment, $commerceCode, $apiKey); - $this->webpayplusTransaction = new \Transbank\Webpay\WebpayPlus\Transaction($this->options); + $this->webpayplusTransaction = new WebpayPlusTransaction($this->options); $this->dataMasker = new MaskData($this->getEnviroment()); } @@ -47,7 +60,7 @@ public function __construct($log, $environment, $commerceCode, $apiKey) */ private function createOptions($environment, $commerceCode, $apiKey) { - $options = \Transbank\Webpay\WebpayPlus\Transaction::getDefaultOptions(); + $options = WebpayPlusTransaction::getDefaultOptions(); if ($environment == Options::ENVIRONMENT_PRODUCTION) { $options = Options::forProduction($commerceCode, $apiKey); } @@ -286,53 +299,6 @@ public function refundTransaction($orderId, $amount)//NotFoundRefundTransactionW /* Metodo COMMIT */ - - public function processRequestFromTbkReturn($server, $get, $post) - { - $method = $server['REQUEST_METHOD']; - $params = $method === 'GET' ? $get : $post; - $tbkToken = isset($params["TBK_TOKEN"]) ? $params['TBK_TOKEN'] : null; - $tbkSessionId = isset($params["TBK_ID_SESION"]) ? $params['TBK_ID_SESION'] : null; - $tbkOrdenCompra = isset($params["TBK_ORDEN_COMPRA"]) ? $params['TBK_ORDEN_COMPRA'] : null; - $tokenWs = isset($params["token_ws"]) ? $params['token_ws'] : null; - - $params1 = [ - 'method' => $method, - 'params' => $params - ]; - - $this->logInfoData('', 'Retornando desde el sitio de Transbank para realizar el commit', $params1); - - if (!isset($tokenWs) && !isset($tbkToken)) { - $errorMessage = 'La transacción fue cancelada automáticamente por estar inactiva mucho tiempo en el formulario de pago de Webpay. Puede reintentar el pago'; - $transaction = null; - if (isset($tbkOrdenCompra) && isset($tbkSessionId)) { - $transaction = Transaction::getByBuyOrderAndSessionId($tbkOrdenCompra, $tbkSessionId); - $this->errorExecution(isset($transaction) ? $transaction->order_id : 0, 'commit', $params1, 'TimeoutWebpayException', $errorMessage, $errorMessage); - $this->saveTransactionWithErrorByTransaction($transaction, 'TimeoutWebpayException', $errorMessage); - } else { - $this->errorExecution(0, 'commit', $params1, 'TimeoutWebpayException', $errorMessage, $errorMessage); - } - throw new TimeoutWebpayException($errorMessage, $tbkOrdenCompra, $tbkSessionId, $transaction); - } - - if (!isset($tokenWs) && isset($tbkToken)) { - $errorMessage = 'La transacción fue anulada por el usuario.'; - $transaction = $this->saveTransactionWithErrorByToken($tbkToken, 'UserCancelWebpayException', $errorMessage); - $this->errorExecution($transaction->order_id, 'commit', $params1, 'UserCancelWebpayException', $errorMessage, $errorMessage); - throw new UserCancelWebpayException($errorMessage, $tbkToken, $transaction); - } - - if (isset($tbkToken) && isset($tokenWs)) { - $errorMessage = 'El pago es inválido.'; - $transaction = $this->saveTransactionWithErrorByToken($tbkToken, 'DoubleTokenWebpayException', $errorMessage); - $this->errorExecution($transaction->order_id, 'commit', $params1, 'DoubleTokenWebpayException', $errorMessage, $errorMessage); - throw new DoubleTokenWebpayException($errorMessage, $tbkToken, $tokenWs, $transaction); - } - - return Transaction::getByToken($tokenWs); - } - public function commitInner($orderId, $token, $transaction) { $params = ['token' => $token]; @@ -415,5 +381,143 @@ public function saveTransactionWithErrorByToken($token, $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); + } + + }