diff --git a/README.md b/README.md index 1fc0f94e..3f374290 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/transbankdevelopers/transbank-plugin-woocommerce-webpay)](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay/releases/latest) -[![GitHub](https://img.shields.io/github/license/transbankdevelopers/transbank-plugin-woocommerce-webpay)](LICENSE) -[![GitHub contributors](https://img.shields.io/github/contributors/transbankdevelopers/transbank-plugin-woocommerce-webpay)](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay/graphs/contributors) -[![Build Status](https://travis-ci.org/TransbankDevelopers/transbank-plugin-woocommerce-webpay.svg?branch=master)](https://travis-ci.org/TransbankDevelopers/transbank-plugin-woocommerce-webpay) +[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/transbankdevelopers/transbank-plugin-woocommerce-webpay-rest)](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest) +[![GitHub](https://img.shields.io/github/license/transbankdevelopers/transbank-plugin-woocommerce-webpay-rest)](LICENSE) +[![GitHub contributors](https://img.shields.io/github/contributors/transbankdevelopers/transbank-plugin-woocommerce-webpay-rest)](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/graphs/contributors) +[![Release](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/actions/workflows/release.yml/badge.svg)](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/actions/workflows/release.yml) # Transbank Woocommerce Webpay Plugin Plugin oficial de Webpay para WooCommerce @@ -45,11 +45,13 @@ Para cumplir estas dependencias, debes instalar [Composer](https://getcomposer.o Para apoyar el levantamiento rápido de un ambiente de desarrollo, hemos creado la especificación de contenedores a través de Docker Compose. -Para testear los ejemplos estos estan disponibles en: -- [WooCommerce 3.4.0 con php 7.1](./docker-woocommerce-php7.1) -- [WooCommerce 3.6.3 con php 7.2](./docker-woocommerce-php7.2) -- [WooCommerce 3.9.1 con php 7.3](./docker-woocommerce-php7.3) -- [WooCommerce 3.9.1 con php 7.4](./docker-woocommerce-php7.4) +Para probar el plugin, ponemos a disposición los siguientes contenedores: +- [WooCommerce 6.0 con php 7.4](./docker-woocommerce-php7.4-wp6.0.0-wc2.6.0-woo6.0.0) +- [WooCommerce 6.5 con php 7.4](./docker-woocommerce-php7.4-wp6.0.0-wc2.6.0-woo6.5.0) +- [WooCommerce 8.1 con php 8.2](./docker-woocommerce-php8.2-wp6.4.1-wc2.9.0-woo8.1.0) +- [WooCommerce 8.2 con php 8.2](./docker-woocommerce-php8.2-wp6.4.1-wc2.9.0-woo8.2.0) +- [WooCommerce 8.3 con php 8.2](./docker-woocommerce-php8.2-wp6.4.1-wc2.9.0-woo8.3.0) +- [WooCommerce 8.5 con php 8.2](./docker-woocommerce-php8.2-wp6.4.1-wc2.9.0-woo8.5.0) Si necesitas subir el plugin a Woocommerce y obtienes un error por que no se puede mover el archivo a `wp-contentent` entonces ejecuta @@ -116,7 +118,7 @@ Con eso Travis CI generará automáticamente una nueva versión del plugin y act 2️⃣ - El pr debe tener 2 o mas aprobaciones para hacer el merge -3️⃣ - si un commit revierte un commit anterior debera comenzar con "revert:" seguido con texto del commit anterior +3️⃣ - si un commit revierte un commit anterior deberá comenzar con "revert:" seguido con texto del commit anterior ## Pull Request diff --git a/plugin/css/tbk.css b/plugin/css/tbk.css index 51e4d490..e15ed8ce 100644 --- a/plugin/css/tbk.css +++ b/plugin/css/tbk.css @@ -282,7 +282,7 @@ display: grid; grid-template-columns: 20px 200px 1fr; grid-gap: 5px; - align-items: flex-start; + align-items: center; overflow: hidden; } diff --git a/plugin/readme.txt b/plugin/readme.txt index fb1ac1ac..3d799df4 100644 --- a/plugin/readme.txt +++ b/plugin/readme.txt @@ -2,7 +2,7 @@ Contributors: TransbankDevelopers Tags: transbank, webpay, oneclick, webpay plus, rest, chile Requires at least: 5.3 -Tested up to: 6.4 +Tested up to: 6.5.3 Requires PHP: 7.4 Stable tag: VERSION_REPLACE_HERE License: 3-Clause BSD License @@ -14,6 +14,15 @@ Recibe pagos en línea con tarjetas de crédito, débito y prepago en tu WooComm Recibe pagos en línea con tarjetas de crédito, débito y prepago en tu WooCommerce a través de Webpay Plus y Webpay Oneclick == Changelog == += 1.9.0 = +* Se agrega la opción de poder seleccionar el archivo log en la sección de registros del menú de configuración. +* Se agrega la funcionalidad para que se muestren las tarjetas registradas de Oneclick dependiendo del entorno. +* Se agrega el sufijo [Test] a las tarjetas registradas con Oneclick en entorno de integración. +* Se agrega como dependencia el plugin de WooCommerce. +* Se actualiza el título del producto Webpay pasando de Transbank Webpay Plus a Webpay Plus. +* Se arregla un problema que impedía capturar las excepciones cuando se autorizaba una suscripción. +* Se elimina un hook deprecado que provocaba errores de instalación en algunos entornos. + = 1.8.0 = * Se corrige un problema con el contenido del archivo log que provocaba que se desborde. * Se agrega la funcionalidad para cambiar la descripción de los medios de pago desde la configuración del plugin. @@ -154,6 +163,15 @@ Arreglado: * Initial release. == Upgrade Notice == += 1.9.0 = +* Se agrega la opción de poder seleccionar el archivo log en la sección de registros del menú de configuración. +* Se agrega la funcionalidad para que se muestren las tarjetas registradas de Oneclick dependiendo del entorno. +* Se agrega el sufijo [Test] a las tarjetas registradas con Oneclick en entorno de integración. +* Se agrega como dependencia el plugin de WooCommerce. +* Se actualiza el título del producto Webpay pasando de Transbank Webpay Plus a Webpay Plus. +* Se arregla un problema que impedía capturar las excepciones cuando se autorizaba una suscripción. +* Se elimina un hook deprecado que provocaba errores de instalación en algunos entornos. + = 1.8.0 = * Se corrige un problema con el contenido del archivo log que provocaba que se desborde. * Se agrega la funcionalidad para cambiar la descripción de los medios de pago desde la configuración del plugin. diff --git a/plugin/src/Controllers/LogController.php b/plugin/src/Controllers/LogController.php new file mode 100644 index 00000000..e2db45e8 --- /dev/null +++ b/plugin/src/Controllers/LogController.php @@ -0,0 +1,52 @@ +template = new Template(); + $this->log = TbkFactory::createLogger(); + } + public function show() + { + $summary = $this->log->getInfo(); + $logFile = basename($summary['last']); + + if (isset($_GET['log_file'])) { + $isLogFileNameValid = $this->validateLogFileName($_GET['log_file'], $summary['logs']); + + if ($isLogFileNameValid) { + $logFile = $_GET['log_file']; + } + } + + $logDetail = $this->log->getLogDetail($logFile); + $folderHasLogs = $summary['length'] > 0; + + $this->template->render('admin/log.php', [ + 'resume' => $summary, + 'lastLog' => $logDetail, + 'folderHasLogs' => $folderHasLogs + ]); + } + + private function validateLogFileName(String $logFileName, array $logFiles): bool + { + foreach ($logFiles as $logData) { + if (in_array($logFileName, $logData)) { + return true; + } + } + return false; + } +} diff --git a/plugin/src/PaymentGateways/WC_Gateway_Transbank_Oneclick_Mall_REST.php b/plugin/src/PaymentGateways/WC_Gateway_Transbank_Oneclick_Mall_REST.php index a483cb36..1fd12433 100644 --- a/plugin/src/PaymentGateways/WC_Gateway_Transbank_Oneclick_Mall_REST.php +++ b/plugin/src/PaymentGateways/WC_Gateway_Transbank_Oneclick_Mall_REST.php @@ -24,6 +24,7 @@ use Transbank\Webpay\Oneclick\Exceptions\MallTransactionAuthorizeException; use Transbank\Webpay\Oneclick\Exceptions\InscriptionStartException; use Transbank\Webpay\Oneclick\Responses\InscriptionStartResponse; +use Transbank\Webpay\Oneclick\Responses\MallTransactionAuthorizeResponse; use WC_Order; use WC_Payment_Gateway_CC; use WC_Payment_Tokens; @@ -51,6 +52,13 @@ class WC_Gateway_Transbank_Oneclick_Mall_REST extends WC_Payment_Gateway_CC */ protected $oneclickTransbankSdk; + /** + * Indicates if the exception message should be displayed in the notice when checkout block is enabled. + * + * @var bool + */ + private $shouldThrowException; + /** * WC_Gateway_Transbank_Oneclick_Mall_REST constructor. */ @@ -80,6 +88,7 @@ public function __construct() $this->get_option('oneclick_payment_gateway_description', self::PAYMENT_GW_DESCRIPTION); $this->icon = plugin_dir_url(dirname(dirname(__FILE__))) . 'images/oneclick.png'; + $this->shouldThrowException = false; $this->init_form_fields(); $this->init_settings(); @@ -101,26 +110,85 @@ public function __construct() ]); add_filter('woocommerce_payment_methods_list_item', [$this, 'methods_list_item_oneclick'], null, 2); - add_filter('woocommerce_payment_token_class', [$this, 'set_payment_token_class']); + add_filter('woocommerce_payment_token_class', [$this, 'getOneclickPaymentTokenClass']); add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']); + add_filter('woocommerce_saved_payment_methods_list', [$this, 'get_saved_payment_methods_list'], 10, 2); } - public function payment_fields() + /** + * Procesar pago y retornar resultado. + ** + * + * @throws MallTransactionAuthorizeException + */ + public function process_payment($order_id) { - $description = $this->get_description(); - if ($description) { - echo wpautop(wptexturize($description)); // @codingStandardsIgnoreLine. + try { + $order = new WC_Order($order_id); + + $this->checkOrderCanBePaid($order); + $this->checkUserIsLoggedIn(); + + return $this->handleOneclickPayment($_POST, $order); + } catch (Throwable $exception) { + $errorHookName = 'wc_gateway_transbank_process_payment_error_' . $this->id; + $errorMessage = ErrorHelper::getErrorMessageBasedOnTransbankSdkException($exception); + do_action($errorHookName, $exception, true); + BlocksHelper::addLegacyNotices($errorMessage, 'error'); + + return [ + 'result' => 'error', + 'redirect' => '' + ]; } - parent::payment_fields(); } - public function is_valid_for_use() + /** + * Processes a scheduled subscription payment. + * + * This method authorizes a scheduled subscription payment for the given renewal order. It retrieves the customer ID + * from the renewal order, obtains the customer's default payment token and authorizes the payment with Oneclick. + * + * @param float $amount_to_charge The amount to charge for the subscription payment. + * @param WC_Order $renewalOrder The renewal order object for the subscription. + * + * @throws EcommerceException If there is no customer ID on the renewal order. + */ + public function scheduled_subscription_payment($amount_to_charge, WC_Order $renewalOrder) { - return in_array( - get_woocommerce_currency(), - apply_filters('woocommerce_transbank_webpay_oneclick_supported_currencies', ['CLP']), - true - ); + try { + $this->logger->logInfo('Autorizando suscripción para la orden #' . $renewalOrder->get_id()); + $customerId = $renewalOrder->get_customer_id(); + + if (!$customerId) { + $this->logger->logError('No existe el ID de usuario en la suscripción.'); + throw new EcommerceException('There is no costumer id on the renewal order'); + } + + /** @var WC_Payment_Token_Oneclick $paymentToken */ + $paymentToken = WC_Payment_Tokens::get_customer_default_token($customerId); + + $authorizeResponse = $this->oneclickTransbankSdk->authorize( + $renewalOrder->get_id(), + $amount_to_charge, + $paymentToken->get_username(), + $paymentToken->get_token() + ); + + $renewalOrder->add_payment_token($paymentToken); + + $orderNotes = $this->getOrderNotesFromAuthorizeResponse($authorizeResponse, 'Oneclick: Pago de suscripción exitoso'); + $renewalOrder->add_order_note($orderNotes); + + do_action('wc_transbank_oneclick_transaction_approved', ['order' => $renewalOrder->get_data()]); + + $this->setOrderAsComplete($renewalOrder); + + $this->logger->logInfo('Suscripción autorizada correctamente para la orden #' . $renewalOrder->get_id()); + } catch (Throwable $ex) { + $this->logger->logError("Error al procesar suscripción: " . $ex->getMessage()); + $renewalOrder->add_order_note('Error al procesar suscripción, para más detalles revisar el archivo log.'); + } } public function process_refund($order_id, $amount = null, $reason = '') @@ -180,6 +248,15 @@ public function process_refund($order_id, $amount = null, $reason = '') } } + public function payment_fields() + { + $description = $this->get_description(); + if ($description) { + echo wpautop(wptexturize($description)); // @codingStandardsIgnoreLine. + } + parent::payment_fields(); + } + public function admin_options() { if ($this->is_valid_for_use()) { @@ -206,6 +283,31 @@ public function admin_options() } } + /** + * @throws \GuzzleHttp\Exception\GuzzleException + * @throws InscriptionStartException + */ + public function add_payment_method() + { + $response = $this->start(null, 'my_account'); + $redirectUrl = $response->getRedirectUrl(); + + return wp_redirect($redirectUrl); + } + + /** + * Outputs a checkbox for saving a new payment method to the database. + * + * @since 2.6.0 + */ + public function save_payment_method_checkbox() + { + $html = '

+ Esta tarjeta se guardará en tu cuenta para que puedas volver a usarla. +

'; + echo $html; + } + public function is_available() { if (!$this->is_valid_for_use()) { @@ -221,152 +323,164 @@ public function form() } /** - * @throws MallTransactionAuthorizeException + * Handles the request for processing a payment or initiating a new card inscription. + * + * This method determines whether to process a payment authorization or initiate a new card inscription + * based on the provided request data. If a new payment token ID is provided or if no token ID is provided, + * it initiates the inscription process. Otherwise, it handles the authorization process for the provided + * payment token ID. + * + * @param array $request The request data containing payment token information. + * @param WC_Order $order The WooCommerce order object associated with the request. + * + * @return array The result of the processing, including a success message and redirect URL. */ - public function scheduled_subscription_payment($amount_to_charge, WC_Order $renewalOrder) + private function handleOneclickPayment(array $request, WC_Order $order) { - $this->logger->logInfo('New scheduled_subscription_payment for Order #' . $renewalOrder->get_id()); - $customerId = $renewalOrder->get_customer_id(); - if (!$customerId) { - $this->logger->logError('There is no costumer id on the renewal order'); + $paymentTokenId = wc_clean($request["wc-{$this->id}-payment-token"]) ?? null; - throw new EcommerceException('There is no costumer id on the renewal order'); + if ($paymentTokenId === 'new' || is_null($paymentTokenId)) { + return $this->handleInscription($order); } - /** @var WC_Payment_Token_Oneclick $paymentToken */ - $paymentToken = WC_Payment_Tokens::get_customer_default_token($customerId); - $response = $this->authorizeTransaction($renewalOrder, $paymentToken, $amount_to_charge); - if ($response['result'] == 'error') { - throw new EcommerceException('Se produjo un error en la autorización'); - } - $this->setAfterPaymentOrderStatus($renewalOrder); + return $this->handleAuthorization($order, $paymentTokenId); } - public static function subscription_payment_method_updated() + /** + * Handles the inscription process for adding a new card. + * + * This method initiates the inscription process for adding a new card to the OneClick payment method. + * + * @param WC_Order $order The WooCommerce order object. + * + * @return array The result of the inscription process, including a success message and redirect URL. + */ + private function handleInscription(WC_Order $order) { - // Todo: check if we need something here. - } + $this->logger->logInfo('[Oneclick] Inicio de inscripción'); - public function methods_list_item_oneclick($item, $payment_token) - { - if ('oneclick' !== strtolower($payment_token->get_type())) { - return $item; - } - $item['method']['last4'] = $payment_token->get_last4(); - $item['method']['brand'] = $payment_token->get_card_type(); + $response = $this->start($order->get_id()); - return $item; - } + $this->logger->logInfo('[Oneclick] Respuesta de inscripción: '); + $this->logger->logInfo(json_encode($response)); + $order->add_order_note('El usuario inició inscripción de nueva tarjeta. Redirigiendo a formulario OneClick.'); - public function set_payment_token_class() - { - return WC_Payment_Token_Oneclick::class; + do_action('transbank_oneclick_adding_card_from_order', $order); + + return [ + 'result' => 'success', + 'redirect' => $response->getRedirectUrl(), + ]; } /** - * Procesar pago y retornar resultado. - ** + * Handles the authorization process for a OneClick payment. * - * @throws MallTransactionAuthorizeException + * This method performs the authorization process for a OneClick payment. + * + * @param WC_Order $order The WooCommerce order object. + * @param string $paymentTokenId The ID of the payment token associated with the order. + * + * @return array The result of the authorization process, including a success message and redirect URL. + * + * @throws CreateTransactionOneclickException If there are issues creating the transaction. + * @throws AuthorizeOneclickException If there are problems with authorization. + * @throws RejectedAuthorizeOneclickException If the authorization is rejected. + * @throws ConstraintsViolatedAuthorizeOneclickException If constraints are violated during authorization. */ - public function process_payment($order_id) + private function handleAuthorization(WC_Order $order, string $paymentTokenId) { - $errorHookName = 'wc_gateway_transbank_process_payment_error_' . $this->id; - $shouldThrowException = false; - try { - $order = new WC_Order($order_id); - - if (!$order->needs_payment() && !wcs_is_subscription($order_id)) { - $this->logger->logError('This order was already paid or does not need payment'); - $errorMessage = __( - 'Esta transacción puede ya estar pagada o encontrarse en un estado que no permite un nuevo pago. ', - 'transbank_wc_plugin' - ); - - throw new EcommerceException($errorMessage); - } + $orderNotes = ''; + $this->logger->logInfo('[Oneclick] Checkout: pagando con el token ID #' . $paymentTokenId); + $paymentToken = $this->getWcPaymentToken($paymentTokenId); + $amount = $this->getTotalAmountFromOrder($order); - $paymentMethodOption = $_POST["wc-{$this->id}-payment-token"] ?? null; - $addNewCard = 'new' === $paymentMethodOption || $paymentMethodOption === null; - $payWithSavedToken = $paymentMethodOption !== null && !$addNewCard; - - if (!get_current_user_id()) { - $order->add_order_note( - 'El usuario intentó pagar con oneclick pero no tiene (y no creó durante el checkout)' . - ' cuenta de usuario' - ); - $this->logger->logInfo('Checkout: The user should have an account to add a new card. '); - - $errorMessage = __( - 'Webpay Oneclick: Debes crear o tener una cuenta en el sitio para poder inscribir ' . - 'tu tarjeta y usar este método de pago.', - 'transbank_wc_plugin' - ); - - throw new EcommerceException($errorMessage); - } + $authorizeResponse = $this->oneclickTransbankSdk->authorize( + $order->get_id(), + $amount, + $paymentToken->get_username(), + $paymentToken->get_token() + ); - if ($addNewCard) { - $this->logger->logInfo('[Oneclick] Checkout: start inscription'); + $order->add_payment_token($paymentToken); + $this->setOrderAsComplete($order); + $this->emptyCart(); - $response = $this->start($order_id); + $orderNotes = $this->getOrderNotesFromAuthorizeResponse($authorizeResponse, 'Oneclick: Pago exitoso'); + $order->add_order_note($orderNotes); - $this->logger->logInfo('[Oneclick] Checkout: inscription response: '); - $this->logger->logInfo(json_encode($response)); - $order->add_order_note('El usuario inició inscripción de nueva tarjeta. Redirigiendo a ' . - 'formulario OneClick...'); + do_action('wc_transbank_oneclick_transaction_approved', ['order' => $order->get_data()]); - do_action('transbank_oneclick_adding_card_from_order', $order); + $this->logger->logInfo('Se ha autorizado el pago correctamente para la orden #' . $order->get_id()); - return [ - 'result' => 'success', - 'redirect' => $response->getRedirectUrl(), - ]; + return [ + 'result' => 'success', + 'redirect' => $this->get_return_url($order), + ]; + } catch (CreateTransactionOneclickException $e) { + $orderNotes = 'Transacción con problemas de autorización'; + } catch (AuthorizeOneclickException $e) { + $orderNotes = 'Problemas al crear el registro de Transacción'; + } catch (RejectedAuthorizeOneclickException $e) { + $response = $e->getAuthorizeResponse(); + $orderNotes = $this->getOrderNotesFromAuthorizeResponse( + $response, + 'Oneclick: Pago rechazado' + ); + $order->add_meta_data('transbank_response', json_encode($response)); + } catch (ConstraintsViolatedAuthorizeOneclickException $e) { + $response = $e->getAuthorizeResponse(); + $orderNotes = $this->getOrderNotesFromAuthorizeResponse( + $response, + 'Oneclick: Pago rechazado' + ); + $order->add_order_note($e->getMessage()); + $order->add_meta_data('transbank_response', json_encode($response)); + } finally { + if (isset($e)) { + $this->shouldThrowException = true; + $this->setOrderAsFailed($order, $orderNotes); + do_action('wc_transbank_oneclick_transaction_failed', ['order' => $order->get_data()]); + $this->logger->logError('Error al autorizar: ' . $e->getMessage()); + throw $e; } + } + } - if ($payWithSavedToken) { + public function get_saved_payment_methods_list($saved_methods) + { + $pluginEnvironment = $this->get_option('environment'); + $oneclickCards = $saved_methods['oneclick'] ?? []; + $filteredCards = []; - $shouldThrowException = true; - return $this->authorizeTransaction($order); + foreach ($oneclickCards as $card) { + if ($card['method']['environment'] === $pluginEnvironment) { + $filteredCards[] = $card; } - $errorMessage = __('Error interno: no se pudo procesar el pago', 'transbank_wc_plugin'); - throw new EcommerceException($errorMessage); - } catch (\Throwable $exception) { - $errorMessage = ErrorHelper::getErrorMessageBasedOnTransbankSdkException($exception); - do_action($errorHookName, $exception, $shouldThrowException); - BlocksHelper::addLegacyNotices($errorMessage, 'error'); + } - return [ - 'result' => 'error', - 'redirect' => '' - ]; + if (count($oneclickCards) > 0) { + $saved_methods['oneclick'] = $filteredCards; } + + return $saved_methods; } - /** - * @throws \GuzzleHttp\Exception\GuzzleException - * @throws InscriptionStartException - */ - public function add_payment_method() + public function methods_list_item_oneclick($item, $payment_token) { - $response = $this->start(null, 'my_account'); - $redirectUrl = $response->getRedirectUrl(); + if ('oneclick' !== strtolower($payment_token->get_type())) { + return $item; + } - return wp_redirect($redirectUrl); - } + $cardEnvironment = $payment_token->get_environment(); + $environmentSuffix = $cardEnvironment === Options::ENVIRONMENT_INTEGRATION ? ' [Test]' : ''; - /** - * Outputs a checkbox for saving a new payment method to the database. - * - * @since 2.6.0 - */ - public function save_payment_method_checkbox() - { - $html = '

- Esta tarjeta se guardará en tu cuenta para que puedas volver a usarla. -

'; - echo $html; + $item['method']['last4'] = $payment_token->get_last4() . $environmentSuffix; + $item['method']['brand'] = $payment_token->get_card_type(); + $item['method']['environment'] = $cardEnvironment; + + return $item; } /** @@ -464,7 +578,7 @@ public function init_form_fields() ]; } - protected function add_order_notes(WC_Order $wooCommerceOrder, $response, $message) + protected function getOrderNotesFromAuthorizeResponse(MallTransactionAuthorizeResponse $response, string $orderNotesTitle) { $firstDetail = $response->getDetails()[0]; $formattedAmount = TbkResponseUtil::getAmountFormatted($firstDetail->getAmount()); @@ -476,9 +590,9 @@ protected function add_order_notes(WC_Order $wooCommerceOrder, $response, $messa $installmentAmount = $firstDetail->getInstallmentsAmount() ?? 0; $formattedInstallmentAmount = TbkResponseUtil::getAmountFormatted($installmentAmount); - $transactionDetails = " + return "
-

{$message}

+

{$orderNotesTitle}

Estado: {$status}
Orden de compra mall: {$response->getBuyOrder()}
@@ -495,8 +609,6 @@ protected function add_order_notes(WC_Order $wooCommerceOrder, $response, $messa Fecha contable: {$formattedAccountingDate}
"; - $wooCommerceOrder->add_order_note($transactionDetails); - $wooCommerceOrder->add_meta_data('transbank_response', json_encode($response)); } /** @@ -520,84 +632,89 @@ public function start( } /** - * @param WC_Payment_Token_Oneclick $paymentToken + * Checks if the order can be paid. + * + * This method verifies whether an order requires payment or if it's already paid. + * It logs an error and throws an EcommerceException if the order does not need payment or if it cannot be paid again. * - * @return WC_Payment_Token_Oneclick + * @param int $order_id The ID of the order to check. + * @throws EcommerceException If the order does not need payment or is in a state that does not allow a new payment. */ - private function getWcPaymentToken(WC_Payment_Token_Oneclick $paymentToken = null) + private function checkOrderCanBePaid(WC_Order $order) { - if ($paymentToken) { - return $paymentToken; - } else { - $tokenId = wc_clean($_POST["wc-{$this->id}-payment-token"]); - /** @var WC_Payment_Token_Oneclick $token */ - return \WC_Payment_Tokens::get($tokenId); + if (!$order->needs_payment() && !wcs_is_subscription($order->get_id())) { + $this->logger->logError('La orden se encuentra en un estado en la que no puede ser pagada.'); + $errorMessage = __( + 'Esta transacción puede ya estar pagada o encontrarse en un estado que no permite un nuevo pago. ', + 'transbank_wc_plugin' + ); + + throw new EcommerceException($errorMessage); } } - private function getAmountForAuthorize($amount, $order) + /** + * Checks if the user is logged in before allowing card registration. + * + * This method verifies whether the user is logged in before allowing them to add a new card. + * It logs an informational message and throws an EcommerceException if the user is not logged in. + * + * @throws EcommerceException If the user is not logged in. + */ + private function checkUserIsLoggedIn() { - if ($amount == null) { - $amount = (int) number_format($order->get_total(), 0, ',', ''); + // Check if the user is logged in + if (!is_user_logged_in()) { + $this->logger->logInfo('El usuario debe tener una cuenta creada para poder inscribir una tarjeta.'); + $errorMessage = __( + 'Webpay Oneclick: Debes crear o tener una cuenta en el sitio para poder inscribir ' . + 'tu tarjeta y usar este método de pago.', + 'transbank_wc_plugin' + ); + + throw new EcommerceException($errorMessage); } - return $amount; } /** - * @param WC_Order $order + * Retrieves a WC_Payment_Token_Oneclick object by its token ID. * - * @throws Transbank\Webpay\Oneclick\Exceptions\MallTransactionAuthorizeException + * This method retrieves a payment token of type WC_Payment_Token_Oneclick using its ID. * - * @return array + * @param string $paymentTokenId The ID of the payment token to retrieve. + * @return WC_Payment_Token_Oneclick Returns the payment token object. */ - public function authorizeTransaction( - WC_Order $order, - WC_Payment_Token_Oneclick $paymentToken = null, - $amount = null - ): array { - - try { - - $token = $this->getWcPaymentToken($paymentToken); - $this->logger->logInfo('[Oneclick] Checkout: paying with token ID #' . $token->get_id()); + private function getWcPaymentToken(string $paymentTokenId): WC_Payment_Token_Oneclick + { + return WC_Payment_Tokens::get($paymentTokenId); + } - $amount = $this->getAmountForAuthorize($amount, $order); - $authorizeResponse = - $this->oneclickTransbankSdk->authorize( - $order->get_id(), - $amount, $token->get_username(), - $token->get_token() - ); + /** + * Retrieves the total amount from an order as an integer. + * + * This method takes a WC_Order object, gets its total amount, formats it to remove any decimal places, + * and then converts it to an integer. + * + * @param WC_Order $order The order object from which to retrieve the total amount. + * @return int The total amount of the order as an integer. + */ + private function getTotalAmountFromOrder(WC_Order $order): int + { + return (int) number_format($order->get_total(), 0, ',', ''); + } - $order->add_payment_token($token); - $this->setAfterPaymentOrderStatus($order); - if (wc()->cart) { - wc()->cart->empty_cart(); - } - $this->add_order_notes($order, $authorizeResponse, 'Oneclick: Pago exitoso'); - do_action('wc_transbank_oneclick_transaction_approved', ['order' => $order->get_data()]); - return [ - 'result' => 'success', - 'redirect' => $this->get_return_url($order), - ]; - } catch (CreateTransactionOneclickException $e) { - $order->update_status('failed'); - $order->add_order_note('Problemas al crear el registro de Transacción'); - } catch (AuthorizeOneclickException $e) { - $order->update_status('failed'); - $order->add_order_note('Transacción con problemas de autorización'); - } catch (RejectedAuthorizeOneclickException $e) { - $order->update_status('failed'); - $this->add_order_notes($order, $e->getAuthorizeResponse(), 'Oneclick: Pago rechazado'); - $order->add_order_note('Transacción rechazada'); - } catch (ConstraintsViolatedAuthorizeOneclickException $e) { - $order->update_status('failed'); - $this->add_order_notes($order, $e->getAuthorizeResponse(), 'Oneclick: Pago rechazado'); - $order->add_order_note('CONSTRAINTS_VIOLATED: ' . $e->getMessage()); - } + public function getOneclickPaymentTokenClass() + { + return WC_Payment_Token_Oneclick::class; + } - do_action('wc_transbank_oneclick_transaction_failed', ['order' => $order->get_data()]); - throw $e; + public function is_valid_for_use() + { + return in_array( + get_woocommerce_currency(), + apply_filters('woocommerce_transbank_webpay_oneclick_supported_currencies', ['CLP']), + true + ); } /** @@ -614,16 +731,49 @@ protected function failedRefund(WC_Order $order, string $message) } /** - * @param WC_Order $order + * Marks the given order as complete and updates its status if specified. + * + * This method sets the order's payment status to complete and then updates + * the order status based on the configured option 'oneclick_after_payment_order_status'. + * If no status is specified, the order is marked as complete without changing the status. + * + * @param WC_Order $order The order object to update. */ - private function setAfterPaymentOrderStatus(WC_Order $order) + private function setOrderAsComplete(WC_Order $order) { $status = $this->get_option('oneclick_after_payment_order_status'); - if ($status == '') { + if (empty($status)) { $order->payment_complete(); } else { $order->payment_complete(); $order->update_status($status); } } + + /** + * Sets the given order as failed and adds a note to the order. + * + * This method updates the status of the provided WC_Order object to 'failed' and adds a custom note to the order. + * + * @param WC_Order $order The order object to update. + * @param string $orderNotes The custom note to add to the order. + */ + private function setOrderAsFailed(WC_Order $order, string $orderNotes) + { + $order->update_status('failed'); + $order->add_order_note($orderNotes); + } + + /** + * Empties the WooCommerce cart. + * + * This method checks if the WooCommerce cart exists and then empties it. + * If the cart exists, all items in the cart are removed. + */ + private function emptyCart() + { + if (wc()->cart) { + wc()->cart->empty_cart(); + } + } } 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 43b3692a..3fdbe9d2 100644 --- a/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php +++ b/plugin/src/PaymentGateways/WC_Gateway_Transbank_Webpay_Plus_REST.php @@ -46,7 +46,7 @@ public function __construct() $this->id = self::ID; $this->icon = plugin_dir_url(dirname(dirname(__FILE__))) . 'images/webpay.png'; $this->method_title = __('Transbank Webpay Plus', 'transbank_webpay_plus_rest'); - $this->title = 'Transbank Webpay Plus'; + $this->title = 'Webpay Plus'; $this->description = $this->get_option('webpay_rest_payment_gateway_description', self::PAYMENT_GW_DESCRIPTION); $this->method_description = $this->get_option('webpay_rest_payment_gateway_description', self::PAYMENT_GW_DESCRIPTION); diff --git a/plugin/templates/admin/log.php b/plugin/templates/admin/log.php new file mode 100644 index 00000000..03d38e09 --- /dev/null +++ b/plugin/templates/admin/log.php @@ -0,0 +1,117 @@ + + +
+

Información de Registros

+
+
+
?
+
+
+ Directorio de registros: +
+
+ + + +
+
+
+
+
? +
+
+
+ Lista de logs: +
+
+
+ + + + + + value="Ver"> +
+
+
+ +

Información del archivo

+
+
+
+
? +
+
+
+ Peso del Documento: +
+
+ + + +
+
+
+
+
?
+
+
+ Cantidad de Líneas: +
+
+ + + +
+
+
+ + '; + + $logLines = explode("\n", $lastLog['content']); + + foreach ($logLines as $line) { + $chunks = explode(' > ', $line); + + $date = $chunks[0]; + $level = $chunks[1] ?? null; + $message = $chunks[2] ?? null; + + if (!is_null($date) && !is_null($level) && !is_null($message)) { + $logContent .= '
' . $date . ' > ' .
+                    '' . $level . ' > ' . $message .
+                    '
'; + } + } + $logContent .= '
'; + echo $logContent; + } + ?> + diff --git a/plugin/views/admin/logs.php b/plugin/views/admin/logs.php deleted file mode 100644 index 62fc7c15..00000000 --- a/plugin/views/admin/logs.php +++ /dev/null @@ -1,153 +0,0 @@ -getInfo(); -$lastLog = $log->getLogDetail(basename($resume['last'])); -$folderHasLogs = $resume['length'] > 0; -?> -
-
-

Información de Registros

-
-
-
-
?
-
-
- Estado de Registros: -
-
- Registro activado -
-
-
-
-
? -
-
-
- Directorio de registros: -
-
- - - -
-
-
-
-
?
-
-
- Cantidad de Registros en Directorio: -
-
- - - -
-
- -
-
-
?
-
-
- Listado de Registros Disponibles: -
-
- - ' . $index['filename'] . ''; - echo $str; - } - ?> - -
-
- -
- - -

Últimos Registros

-
-
-
-
? -
-
-
- Último Documento: -
-
- - - -
-
-
-
-
? -
-
-
- Peso del Documento: -
-
- - - -
-
-
-
-
?
-
-
- Cantidad de Líneas: -
-
- - - -
-
-
- - '; - - $logLines = explode("\n", $lastLog['content']); - - foreach ($logLines as $line) { - $chunks = explode(' > ', $line); - - $date = $chunks[0]; - $level = $chunks[1] ?? null; - $message = $chunks[2] ?? null; - - if (!is_null($date) && !is_null($level) && !is_null($message)) { - $logContent .= '
' . $date . ' > ' .
-                            '' . $level . ' > ' . $message .
-                            '
'; - } - } - $logContent .= '
'; - echo $logContent; - } - ?> - -
- diff --git a/plugin/views/admin/options-tabs.php b/plugin/views/admin/options-tabs.php index 2a4687cf..1491f04a 100644 --- a/plugin/views/admin/options-tabs.php +++ b/plugin/views/admin/options-tabs.php @@ -4,6 +4,7 @@ return; } +use Transbank\WooCommerce\WebpayRest\Controllers\LogController; function tbk_is_nav_active($tab, $val) { if ($tab === $val) { @@ -45,7 +46,7 @@ function tbk_is_nav_active($tab, $val) } elseif ($tab === 'options_oneclick') { include_once __DIR__.'/oneclick-admin-options.php'; } elseif ($tab === 'logs') { - include_once __DIR__.'/logs.php'; + (new LogController)->show(); } elseif ($tab === 'transactions') { include_once __DIR__.'/transactions.php'; } else { diff --git a/plugin/webpay-rest.php b/plugin/webpay-rest.php index ca085628..4e836094 100644 --- a/plugin/webpay-rest.php +++ b/plugin/webpay-rest.php @@ -28,10 +28,11 @@ * Plugin URI: https://www.transbankdevelopers.cl/plugin/woocommerce/webpay * Description: Recibe pagos en línea con Tarjetas de Crédito y Redcompra en tu WooCommerce a través de Webpay Plus y Webpay Oneclick. * Version: VERSION_REPLACE_HERE + * Requires Plugins: woocommerce * Author: TransbankDevelopers * Author URI: https://www.transbank.cl * WC requires at least: 7.0 - * WC tested up to: 8.5.1 + * WC tested up to: 8.9.1 */ require_once plugin_dir_path(__FILE__).'vendor/autoload.php'; @@ -45,8 +46,6 @@ add_action('wp_ajax_get_transaction_status', TransactionStatusController::class.'::getStatus'); add_action('woocommerce_before_cart', 'transbank_rest_before_cart'); -add_action('woocommerce_subscription_failing_payment_method_updated_transbank_oneclick_mall_rest', [WC_Gateway_Transbank_Oneclick_Mall_REST::class, 'subscription_payment_method_updated'], 10, 3); - add_action('woocommerce_before_checkout_form', 'transbank_rest_check_cancelled_checkout'); add_action('admin_enqueue_scripts', function () { wp_enqueue_style('tbk-styles', plugins_url('/css/tbk.css', __FILE__), [], '1.1');