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 "' . $date . ' > ' .
+ '' . $level . ' > ' . $message .
+ '
';
+ }
+ }
+ $logContent .= '' . $date . ' > ' .
- '' . $level . ' > ' . $message .
- '
';
- }
- }
- $logContent .= '