├── docs
├── img
│ ├── demo1.png
│ ├── demo2.png
│ ├── demo3.png
│ ├── demo4.png
│ ├── demo5.png
│ ├── demo6.png
│ ├── demo7.png
│ ├── demo8.png
│ ├── demo9.png
│ ├── paso1.png
│ ├── paso2.png
│ ├── paso3.png
│ ├── paso4.png
│ ├── paso5.png
│ ├── paso6.png
│ ├── order1.png
│ └── order2.png
├── INSTALLATION.pdf
└── INSTALLATION.md
├── plugin
├── images
│ ├── oneclick.png
│ ├── tbk-logo.png
│ ├── webpay.png
│ ├── webpay-new.png
│ └── oneclick-banner.jpg
├── css
│ ├── webfonts
│ │ ├── fa-solid-900.eot
│ │ ├── fa-solid-900.ttf
│ │ ├── fa-brands-400.eot
│ │ ├── fa-brands-400.ttf
│ │ ├── fa-brands-400.woff
│ │ ├── fa-regular-400.eot
│ │ ├── fa-regular-400.ttf
│ │ ├── fa-solid-900.woff
│ │ ├── fa-solid-900.woff2
│ │ ├── fa-brands-400.woff2
│ │ ├── fa-regular-400.woff
│ │ └── fa-regular-400.woff2
│ ├── font-awesome
│ │ ├── solid.min.css
│ │ ├── brands.min.css
│ │ ├── regular.min.css
│ │ ├── brands.css
│ │ ├── solid.css
│ │ ├── regular.css
│ │ └── svg-with-js.min.css
│ └── bootstrap-switch.css
├── shared
│ ├── Exceptions
│ │ ├── EcommerceException.php
│ │ ├── InvalidOrderException.php
│ │ ├── TableNotExistOnDatabaseException.php
│ │ ├── TokenNotFoundOnDatabaseException.php
│ │ ├── Webpay
│ │ │ ├── CreateWebpayException.php
│ │ │ ├── CreateTransactionWebpayException.php
│ │ │ ├── StatusWebpayException.php
│ │ │ ├── GetTransactionWebpayException.php
│ │ │ ├── NotFoundTransactionWebpayException.php
│ │ │ ├── RefundWebpayException.php
│ │ │ ├── CommitWebpayException.php
│ │ │ ├── InvalidStatusWebpayException.php
│ │ │ ├── UserCancelWebpayException.php
│ │ │ ├── AlreadyProcessedException.php
│ │ │ ├── TimeoutWebpayException.php
│ │ │ ├── DoubleTokenWebpayException.php
│ │ │ ├── RejectedRefundWebpayException.php
│ │ │ └── RejectedCommitWebpayException.php
│ │ ├── Oneclick
│ │ │ ├── StartOneclickException.php
│ │ │ ├── AuthorizeOneclickException.php
│ │ │ ├── GetInscriptionOneclickException.php
│ │ │ ├── StartInscriptionOneclickException.php
│ │ │ ├── CreateTransactionOneclickException.php
│ │ │ ├── WithoutTokenInscriptionOneclickException.php
│ │ │ ├── StatusOneclickException.php
│ │ │ ├── GetTransactionOneclickException.php
│ │ │ ├── NotFoundTransactionOneclickException.php
│ │ │ ├── RejectedAuthorizeOneclickException.php
│ │ │ ├── ConstraintsViolatedAuthorizeOneclickException.php
│ │ │ ├── FinishInscriptionOneclickException.php
│ │ │ ├── TimeoutInscriptionOneclickException.php
│ │ │ ├── UserCancelInscriptionOneclickException.php
│ │ │ ├── InvalidStatusInscriptionOneclickException.php
│ │ │ ├── RefundOneclickException.php
│ │ │ ├── RejectedInscriptionOneclickException.php
│ │ │ └── RejectedRefundOneclickException.php
│ │ └── BaseException.php
│ ├── Helpers
│ │ ├── ExceptionConstants.php
│ │ ├── DateUtils.php
│ │ ├── ArrayUtils.php
│ │ ├── ILogger.php
│ │ ├── ObjectUtil.php
│ │ ├── TbkDatabaseConstants.php
│ │ ├── StringUtils.php
│ │ ├── GitHubUtil.php
│ │ ├── WoocommerceInfoUtil.php
│ │ ├── TbkValidationUtil.php
│ │ ├── InfoUtil.php
│ │ ├── TbkConstants.php
│ │ └── PluginLogger.php
│ └── Model
│ │ ├── OneclickConfig.php
│ │ ├── WebpayplusConfig.php
│ │ ├── LogConfig.php
│ │ └── ProductConfig.php
├── src
│ ├── Utils
│ │ ├── Template.php
│ │ ├── ConnectionCheck.php
│ │ └── TableCheck.php
│ ├── Helpers
│ │ ├── WordpressPluginVersion.php
│ │ ├── RedirectorHelper.php
│ │ ├── HposHelper.php
│ │ ├── BlocksHelper.php
│ │ ├── ErrorHelper.php
│ │ ├── SessionMessageHelper.php
│ │ ├── PluginInfoHelper.php
│ │ ├── NoticeHelper.php
│ │ ├── ErrorUtil.php
│ │ ├── TbkFactory.php
│ │ ├── BuyOrderHelper.php
│ │ └── WebpayTransactionsTable.php
│ ├── Blocks
│ │ ├── WC_Gateway_Transbank_Webpay_Blocks.php
│ │ ├── WC_Gateway_Transbank_Oneclick_Blocks.php
│ │ ├── js
│ │ │ ├── webpay_checkout.js
│ │ │ ├── oneclick_checkout.js
│ │ │ └── notice_handler.js
│ │ └── WCGatewayTransbankBlocks.php
│ ├── Models
│ │ ├── TransbankExecutionErrorLog.php
│ │ ├── TransbankApiServiceLog.php
│ │ ├── BaseModel.php
│ │ ├── Inscription.php
│ │ └── Transaction.php
│ ├── Controllers
│ │ ├── LogController.php
│ │ ├── ThankYouPageController.php
│ │ ├── TransactionStatusController.php
│ │ └── OneclickInscriptionResponseController.php
│ ├── PaymentGateways
│ │ └── TransbankRESTPaymentGateway.php
│ ├── TransbankSdk.php
│ └── Tokenization
│ │ └── WC_Payment_Token_Oneclick.php
├── views
│ └── admin
│ │ ├── transactions.php
│ │ ├── components
│ │ ├── notice-missing-woocommerce.php
│ │ ├── credenciales-box.php
│ │ ├── info-validacion-webpay-plus-box.php
│ │ └── info-validacion-webpay-oneclick-box.php
│ │ ├── options-tabs.php
│ │ ├── admin-options.php
│ │ └── oneclick-admin-options.php
├── composer.json
├── package.json
├── templates
│ ├── public
│ │ ├── notices
│ │ │ └── review-notice.php
│ │ └── order
│ │ │ └── order-summary.php
│ └── admin
│ │ ├── order
│ │ └── transaction-status.php
│ │ └── log.php
└── webpack.config.js
├── sonar-project.properties
├── .editorconfig
├── .github
├── workflows
│ ├── build.yml
│ └── release.yml
└── ISSUE_TEMPLATE
│ └── reporte-de-error.md
├── .gitignore
├── LICENSE
├── docker-woocommerce-php8.2-wp6.7.1-wc2.11.0-woo9.4.2
├── README.md
└── docker-compose.yml
├── package.sh
├── scripts
└── deploy.sh
└── README.md
/docs/img/demo1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo1.png
--------------------------------------------------------------------------------
/docs/img/demo2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo2.png
--------------------------------------------------------------------------------
/docs/img/demo3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo3.png
--------------------------------------------------------------------------------
/docs/img/demo4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo4.png
--------------------------------------------------------------------------------
/docs/img/demo5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo5.png
--------------------------------------------------------------------------------
/docs/img/demo6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo6.png
--------------------------------------------------------------------------------
/docs/img/demo7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo7.png
--------------------------------------------------------------------------------
/docs/img/demo8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo8.png
--------------------------------------------------------------------------------
/docs/img/demo9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/demo9.png
--------------------------------------------------------------------------------
/docs/img/paso1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso1.png
--------------------------------------------------------------------------------
/docs/img/paso2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso2.png
--------------------------------------------------------------------------------
/docs/img/paso3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso3.png
--------------------------------------------------------------------------------
/docs/img/paso4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso4.png
--------------------------------------------------------------------------------
/docs/img/paso5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso5.png
--------------------------------------------------------------------------------
/docs/img/paso6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/paso6.png
--------------------------------------------------------------------------------
/docs/INSTALLATION.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/INSTALLATION.pdf
--------------------------------------------------------------------------------
/docs/img/order1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/order1.png
--------------------------------------------------------------------------------
/docs/img/order2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/docs/img/order2.png
--------------------------------------------------------------------------------
/plugin/images/oneclick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/images/oneclick.png
--------------------------------------------------------------------------------
/plugin/images/tbk-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/images/tbk-logo.png
--------------------------------------------------------------------------------
/plugin/images/webpay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/images/webpay.png
--------------------------------------------------------------------------------
/plugin/images/webpay-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/images/webpay-new.png
--------------------------------------------------------------------------------
/plugin/images/oneclick-banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/images/oneclick-banner.jpg
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/plugin/css/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/HEAD/plugin/css/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/EcommerceException.php:
--------------------------------------------------------------------------------
1 | $value) {
9 | $to->$property = $value;
10 | }
11 | return $to;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/plugin/src/Utils/Template.php:
--------------------------------------------------------------------------------
1 | logDir = $logDir;
10 | }
11 |
12 | public function getLogDir()
13 | {
14 | return $this->logDir;
15 | }
16 |
17 | public function setLogDir($logDir)
18 | {
19 | $this->logDir = $logDir;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/TbkDatabaseConstants.php:
--------------------------------------------------------------------------------
1 |
2 |
Lista de transacciones Transbank
3 | En esta lista encontrarás el listado de transacciones que Transbank ha procesado.
4 | Se incluyen transacciones desde el momento en que se inicia el intento de pago tanto en Webpay Plus como Webpay Oneclick.
5 | prepare_items();
8 | $table->display();
9 | ?>
10 |
11 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/StatusWebpayException.php:
--------------------------------------------------------------------------------
1 | token = $token;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getToken() {
17 | return $this->token;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/StatusOneclickException.php:
--------------------------------------------------------------------------------
1 | buyOrder = $buyOrder;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getBuyOrder() {
17 | return $this->buyOrder;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/GetTransactionWebpayException.php:
--------------------------------------------------------------------------------
1 | orderId = $orderId;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getOrderId() {
17 | return $this->orderId;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/views/admin/components/notice-missing-woocommerce.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/plugin/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": {
3 | "transbank/transbank-sdk": "4.0",
4 | "ext-json": "*",
5 | "php": ">=7.4",
6 | "monolog/monolog": "^2.10"
7 | },
8 | "config": {
9 | "platform": {
10 | "php": "7.4"
11 | }
12 | },
13 | "autoload": {
14 | "psr-4": {
15 | "Transbank\\WooCommerce\\WebpayRest\\": "src/",
16 | "Transbank\\Plugin\\": "shared/"
17 | }
18 | },
19 | "description": "Transbank WooCommerce Plugin",
20 | "name": "transbank/woocommerce-plugin"
21 | }
22 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/GetTransactionOneclickException.php:
--------------------------------------------------------------------------------
1 | orderId = $orderId;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getOrderId() {
17 | return $this->orderId;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/NotFoundTransactionWebpayException.php:
--------------------------------------------------------------------------------
1 | orderId = $orderId;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getOrderId() {
17 | return $this->orderId;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/NotFoundTransactionOneclickException.php:
--------------------------------------------------------------------------------
1 | orderId = $orderId;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getOrderId() {
17 | return $this->orderId;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "transbank-woocommerce-gateway",
3 | "title": "WooCommerce Webpay Rest",
4 | "version": "1.0.0",
5 | "author": "Transbank Developers",
6 | "license": "BSD-3-Clause",
7 | "keywords": [],
8 | "engines": {
9 | "node": "^20",
10 | "npm": ">=1.1.0"
11 | },
12 | "devDependencies": {
13 | "@woocommerce/dependency-extraction-webpack-plugin": "^3.1.0",
14 | "@wordpress/scripts": "^30.14.0",
15 | "cross-env": "7.0.3"
16 | },
17 | "scripts": {
18 | "start": "wp-scripts start",
19 | "build": "wp-scripts build",
20 | "check-engines": "wp-scripts check-engines"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/RejectedAuthorizeOneclickException.php:
--------------------------------------------------------------------------------
1 | authorizeResponse = $authorizeResponse;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getAuthorizeResponse() {
17 | return $this->authorizeResponse;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/WordpressPluginVersion.php:
--------------------------------------------------------------------------------
1 | includeWordpressPluginFunctions();
18 | $pluginData = get_plugin_data(__DIR__.'/../../webpay-rest.php');
19 |
20 | return $pluginData['Version'];
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/ConstraintsViolatedAuthorizeOneclickException.php:
--------------------------------------------------------------------------------
1 | authorizeResponse = $authorizeResponse;
13 | parent::__construct($message, $previous);
14 | }
15 |
16 | public function getAuthorizeResponse() {
17 | return $this->authorizeResponse;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/solid.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}
--------------------------------------------------------------------------------
/plugin/views/admin/components/credenciales-box.php:
--------------------------------------------------------------------------------
1 |
2 |
Credenciales de prueba
3 | En el ambiente de integración debes probar usando tarjetas de crédito y débito de prueba.
4 |
Encuentra las tarjeta de prueba acá
5 |
6 |
7 | Después de seleccionar el método de pago (en una compra de prueba), llegarás a una página de un Banco de prueba. Debes ingresar estas credenciales:
8 |
9 | Rut: 11.111.111-1
10 | Clave: 123
11 |
12 |
13 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/brands.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands";font-weight:400}
--------------------------------------------------------------------------------
/plugin/css/font-awesome/regular.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400}
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | workflow_dispatch:
4 | pull_request:
5 | types: [opened, synchronize, reopened]
6 | push:
7 | branches:
8 | - 'master'
9 | jobs:
10 | sonarcloud:
11 | name: SonarCloud
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v3
15 | with:
16 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
17 | - name: SonarCloud Scan
18 | uses: SonarSource/sonarcloud-github-action@master
19 | env:
20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
21 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
22 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/WC_Gateway_Transbank_Webpay_Blocks.php:
--------------------------------------------------------------------------------
1 | scriptInfo = require_once $scriptPath . 'webpay_blocks.asset.php';
15 | $this->paymentId = $this->name;
16 | $this->productName = 'webpay';
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/WC_Gateway_Transbank_Oneclick_Blocks.php:
--------------------------------------------------------------------------------
1 | scriptInfo = require_once $scriptPath . 'oneclick_blocks.asset.php';
15 | $this->paymentId = $this->name;
16 | $this->productName = 'oneclick';
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/RefundWebpayException.php:
--------------------------------------------------------------------------------
1 | token = $token;
14 | $this->transaction = $transaction;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getToken() {
19 | return $this->token;
20 | }
21 |
22 | public function getTransaction() {
23 | return $this->transaction;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .idea
3 | builds/
4 |
5 | ## OSX
6 | # General
7 | .DS_Store
8 | .AppleDouble
9 | .LSOverride
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | ## Linux
15 | *~
16 |
17 | ## Windows
18 | # Windows thumbnail cache files
19 | Thumbs.db
20 | ehthumbs.db
21 | ehthumbs_vista.db
22 |
23 | # Dump file
24 | *.stackdump
25 |
26 | # Folder config file
27 | [Dd]esktop.ini
28 |
29 | # Dependencies
30 | vendor
31 | node_modules
32 | composer.lock
33 | package-lock.json
34 |
35 | transbank-webpay-plus-rest.zip
36 | transbank-webpay-plus-rest-guzzle7.zip
37 |
38 | docker-woocommerce-*/wp_data
39 | docker-woocommerce-*/db_data
40 | docker-woocommerce-*/transbank-webpay-plus-rest
41 |
42 | # Woocoomerce blocks genereted files
43 | plugin/js/front/
44 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/CommitWebpayException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
14 | $this->transaction = $transaction;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTbkToken() {
19 | return $this->tbkToken;
20 | }
21 |
22 | public function getTransaction() {
23 | return $this->transaction;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/InvalidStatusWebpayException.php:
--------------------------------------------------------------------------------
1 | tokenWs = $tokenWs;
14 | $this->transaction = $transaction;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTokenWs() {
19 | return $this->tokenWs;
20 | }
21 |
22 | public function getTransaction() {
23 | return $this->transaction;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/UserCancelWebpayException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
15 | $this->transaction = $transaction;
16 | parent::__construct($message, $previous);
17 | }
18 |
19 | public function getTbkToken() {
20 | return $this->tbkToken;
21 | }
22 |
23 | public function getTransaction() {
24 | return $this->transaction;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/FinishInscriptionOneclickException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
14 | $this->inscription = $inscription;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTbkToken() {
19 | return $this->tbkToken;
20 | }
21 |
22 | public function getInscription() {
23 | return $this->inscription;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/TimeoutInscriptionOneclickException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
14 | $this->inscription = $inscription;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTbkToken() {
19 | return $this->tbkToken;
20 | }
21 |
22 | public function getInscription() {
23 | return $this->inscription;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/UserCancelInscriptionOneclickException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
14 | $this->inscription = $inscription;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTbkToken() {
19 | return $this->tbkToken;
20 | }
21 |
22 | public function getInscription() {
23 | return $this->inscription;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/InvalidStatusInscriptionOneclickException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
14 | $this->inscription = $inscription;
15 | parent::__construct($message, $previous);
16 | }
17 |
18 | public function getTbkToken() {
19 | return $this->tbkToken;
20 | }
21 |
22 | public function getInscription() {
23 | return $this->inscription;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/brands.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Brands';
7 | font-style: normal;
8 | font-weight: 400;
9 | font-display: block;
10 | src: url("../webfonts/fa-brands-400.eot");
11 | src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); }
12 |
13 | .fab {
14 | font-family: 'Font Awesome 5 Brands';
15 | font-weight: 400; }
16 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/solid.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 900;
9 | font-display: block;
10 | src: url("../webfonts/fa-solid-900.eot");
11 | src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
12 |
13 | .fa,
14 | .fas {
15 | font-family: 'Font Awesome 5 Free';
16 | font-weight: 900; }
17 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/RedirectorHelper.php:
--------------------------------------------------------------------------------
1 | ";
13 | foreach ($data as $name => $value) {
14 | $msg .= " ";
15 | }
16 | $msg .= ''.'';
17 |
18 | return $msg;
19 | }
20 |
21 | public static function redirect($url, array $data)
22 | {
23 | echo static::getRedirectForm($url, $data);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/regular.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | @font-face {
6 | font-family: 'Font Awesome 5 Free';
7 | font-style: normal;
8 | font-weight: 400;
9 | font-display: block;
10 | src: url("../webfonts/fa-regular-400.eot");
11 | src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); }
12 |
13 | .far {
14 | font-family: 'Font Awesome 5 Free';
15 | font-weight: 400; }
16 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/AlreadyProcessedException.php:
--------------------------------------------------------------------------------
1 | transaction = $transaction;
19 | $this->flow = $flow;
20 | parent::__construct($message, $previous);
21 | }
22 |
23 | public function getTransaction()
24 | {
25 | return $this->transaction;
26 | }
27 |
28 | public function getFlow()
29 | {
30 | return $this->flow;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/StringUtils.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Tu opinión es importante para nosotros
8 |
¿Podrías tomarte un momento para dejarnos una reseña en el repositorio de WordPress?
9 | Solo te tomará un par de minutos
10 | y nos ayudará a seguir mejorando y llegar a más personas como tú.
11 |
12 |
Dejar reseña
16 |
17 |
18 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/TimeoutWebpayException.php:
--------------------------------------------------------------------------------
1 | buyOrder = $buyOrder;
16 | $this->sessionId = $sessionId;
17 | $this->transaction = $transaction;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getBuyOrder() {
22 | return $this->buyOrder;
23 | }
24 |
25 | public function getSessionId() {
26 | return $this->sessionId;
27 | }
28 |
29 | public function getTransaction() {
30 | return $this->transaction;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/DoubleTokenWebpayException.php:
--------------------------------------------------------------------------------
1 | tbkToken1 = $tbkToken1;
16 | $this->tbkToken2 = $tbkToken2;
17 | $this->transaction = $transaction;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getTbkToken1() {
22 | return $this->tbkToken1;
23 | }
24 |
25 | public function getTbkToken2() {
26 | return $this->tbkToken2;
27 | }
28 |
29 | public function getTransaction() {
30 | return $this->transaction;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/templates/admin/order/transaction-status.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
24 |
25 |
26 |
27 |
= $infoMessage ?>
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/RejectedRefundWebpayException.php:
--------------------------------------------------------------------------------
1 | token = $token;
16 | $this->transaction = $transaction;
17 | $this->refundResponse = $refundResponse;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getToken() {
22 | return $this->token;
23 | }
24 |
25 | public function getTransaction() {
26 | return $this->transaction;
27 | }
28 |
29 | public function getRefundResponse() {
30 | return $this->refundResponse;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/RefundOneclickException.php:
--------------------------------------------------------------------------------
1 | buyOrder = $buyOrder;
16 | $this->childBuyOrder = $childBuyOrder;
17 | $this->transaction = $transaction;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getBuyOrder() {
22 | return $this->buyOrder;
23 | }
24 |
25 | public function getChildBuyOrder() {
26 | return $this->childBuyOrder;
27 | }
28 |
29 | public function getTransaction() {
30 | return $this->transaction;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Webpay/RejectedCommitWebpayException.php:
--------------------------------------------------------------------------------
1 | tokenWs = $tokenWs;
16 | $this->transaction = $transaction;
17 | $this->commitResponse = $commitResponse;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getTokenWs() {
22 | return $this->tokenWs;
23 | }
24 |
25 | public function getTransaction() {
26 | return $this->transaction;
27 | }
28 |
29 | public function getCommitResponse() {
30 | return $this->commitResponse;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/HposHelper.php:
--------------------------------------------------------------------------------
1 | wooCommerceVersion = get_option('woocommerce_version');
15 | $this->isHposAvailable = $this->checkIfHposExists();
16 | }
17 | public function checkIfHposExists()
18 | {
19 | return version_compare( $this->wooCommerceVersion, HposHelper::WC_VERSION_SINCE_HPOS, '>=');
20 | }
21 |
22 | public function updateMeta(WC_Order $wooCommerceOrder, $key, $value)
23 | {
24 | if($this->isHposAvailable) {
25 | $wooCommerceOrder->update_meta_data($key, $value);
26 | }
27 | else {
28 | update_post_meta($wooCommerceOrder->get_id(), $key, $value);
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/reporte-de-error.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Reporte de Error
3 | about: Crea un reporte para ayudarnos a mejorar
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe el bug**
11 |
12 | Una descripción concisa sobre el bug.
13 |
14 | **Para reproducir**
15 |
16 | 1. Configura '...'
17 | 2. Haz click en '...'
18 | 3. Baja hasta '...'
19 | 4. Se ve el error en '...'
20 |
21 | **Comportamiento observado**
22 |
23 | Describe de forma concisa lo que observaste siguiendo los pasos para reproducir el error.
24 |
25 | **Comportamiento esperado**
26 |
27 | Una explicación concisa y clara de qué es lo que esperas que ocurra.
28 |
29 | **Capturas de pantalla**
30 |
31 | Si aplica, agrega aquí capturas de pantalla que ayuden a explicar tu problema.
32 |
33 | **Versiones (por favor agrega aquí la siguiente información):**
34 | - Plugin: [ej. 2.2.4]
35 | - Woocommerce: [ej. 3.4]
36 | - PHP: [ej. 7.1]
37 |
38 | **Contexto adicional**
39 |
40 | Agrega cualquier otro información sobre el problema aquí.
41 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/RejectedInscriptionOneclickException.php:
--------------------------------------------------------------------------------
1 | tbkToken = $tbkToken;
16 | $this->inscription = $inscription;
17 | $this->finishInscriptionResponse = $finishInscriptionResponse;
18 | parent::__construct($message, $previous);
19 | }
20 |
21 | public function getTbkToken() {
22 | return $this->tbkToken;
23 | }
24 |
25 | public function getInscription() {
26 | return $this->inscription;
27 | }
28 |
29 | public function getFinishInscriptionResponse() {
30 | return $this->finishInscriptionResponse;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/src/Models/TransbankExecutionErrorLog.php:
--------------------------------------------------------------------------------
1 | $orderId,
21 | 'service' => $service,
22 | 'product' => $product,
23 | 'enviroment' => $enviroment,
24 | 'commerce_code' => $commerceCode,
25 | 'data' => $data,
26 | 'error' => $error,
27 | 'original_error' => $originalError,
28 | 'custom_error' => $customError
29 | ]);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/js/webpay_checkout.js:
--------------------------------------------------------------------------------
1 | import { registerPaymentMethod } from '@woocommerce/blocks-registry';
2 | import { decodeEntities } from '@wordpress/html-entities';
3 | import { getSetting } from '@woocommerce/settings';
4 | import { noticeHandler } from './notice_handler';
5 |
6 | const settings = getSetting( 'transbank_webpay_plus_rest_data', {} );
7 | const label = decodeEntities( settings.title );
8 |
9 | noticeHandler(settings.id);
10 |
11 | const Content = () => {
12 | return decodeEntities( settings.description );
13 | };
14 |
15 | const Label = () => {
16 | const title = decodeEntities( settings.title );
17 | const imagePath = settings.icon;
18 | const paymentImage = (
19 |
20 | );
21 | return (
22 |
23 | {title}
24 | {paymentImage}
25 |
26 | );
27 | };
28 |
29 | const TransbankWebpayBlocks = {
30 | name: settings.id,
31 | label: ,
32 | content: ,
33 | edit: ,
34 | canMakePayment: () => true,
35 | ariaLabel: label,
36 | supports: {
37 | features: settings.supports
38 | }
39 | };
40 |
41 | registerPaymentMethod( TransbankWebpayBlocks );
42 |
--------------------------------------------------------------------------------
/plugin/shared/Exceptions/Oneclick/RejectedRefundOneclickException.php:
--------------------------------------------------------------------------------
1 | buyOrder = $buyOrder;
17 | $this->childBuyOrder = $childBuyOrder;
18 | $this->transaction = $transaction;
19 | $this->refundResponse = $refundResponse;
20 | parent::__construct($message, $previous);
21 | }
22 |
23 | public function getBuyOrder() {
24 | return $this->buyOrder;
25 | }
26 |
27 | public function getChildBuyOrder() {
28 | return $this->childBuyOrder;
29 | }
30 |
31 | public function getTransaction() {
32 | return $this->transaction;
33 | }
34 |
35 | public function getRefundResponse() {
36 | return $this->refundResponse;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/plugin/views/admin/components/info-validacion-webpay-plus-box.php:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/plugin/views/admin/components/info-validacion-webpay-oneclick-box.php:
--------------------------------------------------------------------------------
1 |
2 |
¿Quieres operar en producción?
3 | Para operar en el ambiente productivo, con dinero real, debes tener tu
código de comercio Mall ,
código de comercio Tienda y tu
Api Key (llave secreta) .
4 |
5 |
Código de comercio Mall y código de comercio Tienda
6 | Los obtendrás al contratar el producto Oneclick.
7 |
8 |
Tu Api Key: Proceso de validación
9 | Si ya tienes tus códigos de comercio, lo único que te faltaría es tu Api Key. Para obtenerla, debes completar el siguiente formulario:
10 |
11 |
Comenzar proceso de validación
12 |
13 |
14 |
15 | Si quieres, puedes revisar
las instrucciones detalladas de cómo pasar a producción
16 |
17 |
18 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/GitHubUtil.php:
--------------------------------------------------------------------------------
1 | createInner(0, $buyOrder, $sessionId, $amount, $returnUrl);
29 | $status = 'OK';
30 |
31 | } catch (\Exception $e) {
32 | $status = 'Error';
33 | $result = [
34 | 'error' => 'Error al crear la transacción',
35 | 'detail' => $e->getMessage()
36 | ];
37 | }
38 |
39 | return [
40 | 'status' => ['string' => $status],
41 | 'response' => $result
42 | ];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/plugin/src/Utils/TableCheck.php:
--------------------------------------------------------------------------------
1 | logInfo("Error ejecutando comprobación. Exception "."{$e->getMessage()}");
30 | $resp = array('ok' => false, 'error' => "Error ejecutando comprobación.", 'exception' => "{$e->getMessage()}");
31 | }
32 |
33 | header('Content-Type: application/json');
34 | ob_clean();
35 | echo json_encode($resp);
36 | wp_die();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | release:
4 | types: [created]
5 |
6 | jobs:
7 | release:
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v4
13 | with:
14 | fetch-depth: 0
15 | - name: Setup PHP
16 | uses: shivammathur/setup-php@v2
17 | with:
18 | php-version: "7.4"
19 | - name: Setup Node
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version: "16"
23 | - name: Install SVN
24 | run: |
25 | sudo apt-get update
26 | sudo apt-get install -y subversion
27 | - name: Release
28 | run: |
29 | chmod +x package.sh
30 | chmod +x scripts/deploy.sh
31 | ./package.sh
32 | ./scripts/deploy.sh
33 | env:
34 | WP_ORG_PASSWORD: ${{ secrets.WP_ORG_PASSWORD }}
35 | TAG: ${{ github.event.release.tag_name }}
36 | - name: Upload transbank-webpay-plus-rest.zip
37 | uses: actions/upload-release-asset@v1
38 | env:
39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 | with:
41 | upload_url: ${{ github.event.release.upload_url }}
42 | asset_path: transbank-webpay-plus-rest.zip
43 | asset_name: transbank-webpay-plus-rest.zip
44 | asset_content_type: application/zip
45 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/ErrorHelper.php:
--------------------------------------------------------------------------------
1 | getMessage(), 'choose_handler');
10 | }
11 |
12 | public static function getGuzzleError()
13 | {
14 | return 'Error: otro plugin instalado en este sitio está provocando errores con la librería Guzzle.
15 | Si eres el administrador, intenta desactivar otros plugins hasta que ya no se muestre este error,
16 | para así reconocer cual está generando el problema. También puedes instalar una versión alternativa del
17 | plugin de Transbank que usa otra versión de Guzzle, lo que podría resolver el problema: Entra a
18 | https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest y descarga
19 | el archivo transbank-webpay-plus-rest-guzzle7.zip, desactiva el plugin de Transbank y sube este nuevo plugin
20 | como archivo zip. Si te pide reemplazar el que ya tienes, selecciona que si. ';
21 | }
22 |
23 | public static function getErrorMessageBasedOnTransbankSdkException(\Throwable $e)
24 | {
25 | if (strpos($e->getMessage(), 'choose_handler') !== false) {
26 | return ErrorHelper::getGuzzleError();
27 | }
28 |
29 | return 'Error: '.$e->getMessage();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/SessionMessageHelper.php:
--------------------------------------------------------------------------------
1 | {
16 | if (wcDepMap[request]) {
17 | return wcDepMap[request];
18 | }
19 | };
20 |
21 | const requestToHandle = (request) => {
22 | if (wcHandleMap[request]) {
23 | return wcHandleMap[request];
24 | }
25 | };
26 |
27 | // Export configuration.
28 | module.exports = {
29 | ...defaultConfig,
30 | entry:
31 | {'webpay_blocks': '/src/Blocks/js/webpay_checkout.js',
32 | 'oneclick_blocks': '/src/Blocks/js/oneclick_checkout.js',
33 | 'notice_handler': '/src/Blocks/js/notice_handler.js'
34 | }
35 | ,
36 | output: {
37 | path: path.resolve( __dirname, 'js/front' ),
38 | filename: '[name].js'
39 | },
40 | plugins: [
41 | ...defaultConfig.plugins.filter(
42 | (plugin) =>
43 | plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
44 | ),
45 | new WooCommerceDependencyExtractionWebpackPlugin({
46 | requestToExternal,
47 | requestToHandle
48 | })
49 | ]
50 | };
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2018, Transbank Developers
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | * Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | * Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | * Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/plugin/src/Controllers/LogController.php:
--------------------------------------------------------------------------------
1 | template = new Template();
18 | $this->log = TbkFactory::createLogger();
19 | }
20 | public function show()
21 | {
22 | $summary = $this->log->getInfo();
23 | $logFile = basename($summary['last']);
24 |
25 | if (isset($_GET['log_file'])) {
26 | $isLogFileNameValid = $this->validateLogFileName($_GET['log_file'], $summary['logs']);
27 |
28 | if ($isLogFileNameValid) {
29 | $logFile = $_GET['log_file'];
30 | }
31 | }
32 |
33 | $logDetail = $this->log->getLogDetail($logFile);
34 | $folderHasLogs = $summary['length'] > 0;
35 |
36 | $this->template->render('admin/log.php', [
37 | 'resume' => $summary,
38 | 'lastLog' => $logDetail,
39 | 'folderHasLogs' => $folderHasLogs
40 | ]);
41 | }
42 |
43 | private function validateLogFileName(String $logFileName, array $logFiles): bool
44 | {
45 | foreach ($logFiles as $logData) {
46 | if (in_array($logFileName, $logData)) {
47 | return true;
48 | }
49 | }
50 | return false;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/docker-woocommerce-php8.2-wp6.7.1-wc2.11.0-woo9.4.2/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Woocommerce Docker para desarrollo
4 |
5 | ### PHP 8.2 + WordPress 6.7.1 + WordPress Cli 2.11.0 + Mysql 5.7 + Woocommerce 9.4.2
6 |
7 | ### Requerimientos
8 |
9 | **MacOS:**
10 |
11 | Instalar [Docker](https://docs.docker.com/docker-for-mac/install/), [Docker-compose](https://docs.docker.com/compose/install/#install-compose) y [Docker-sync](https://github.com/EugenMayer/docker-sync/wiki/docker-sync-on-OSX).
12 |
13 | **Windows:**
14 |
15 | Instalar [Docker](https://docs.docker.com/docker-for-windows/install/), [Docker-compose](https://docs.docker.com/compose/install/#install-compose) y [Docker-sync](https://github.com/EugenMayer/docker-sync/wiki/docker-sync-on-Windows).
16 |
17 | **Linux:**
18 |
19 | Instalar [Docker](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/) y [Docker-compose](https://docs.docker.com/compose/install/#install-compose).
20 |
21 | ### Como usar
22 |
23 | De forma automática se creará una imagen WordPress y WordPress Cli, se instalará WooCommerce con el tema Storefront y se creará un producto de ejemplo.
24 |
25 | Para instalar Woocommerce, hacer lo siguiente y esperar 5 minutos:
26 |
27 | ```
28 | docker compose up
29 | ```
30 |
31 | Para Eliminar ejecutar y borrar las carpetas 'db_data' y 'wp_data':
32 |
33 | ```
34 | docker compose down
35 | ```
36 |
37 | ### Paneles
38 |
39 | **Web server:** http://localhost:8000
40 |
41 | **Admin:** http://localhost:8000/wp-admin
42 |
43 | user: admin
44 | password: admin
45 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/PluginInfoHelper.php:
--------------------------------------------------------------------------------
1 | get_option('webpay_rest_environment');
15 | $webpayPlusCommerceCode = $webpayPlus->get_option('webpay_rest_commerce_code');
16 |
17 | $oneclick = new WC_Gateway_Transbank_Oneclick_Mall_REST();
18 | $oneclickEnvironment = $oneclick->get_option('environment');
19 | $oneclickCommerceCode = $oneclick->get_option('commerce_code');
20 | $oneclickMaxAmount = $oneclick->get_option('max_amount');
21 |
22 | if ($transbankPluginData) {
23 | $pluginVersion = $transbankPluginData['Version'] ?? '0';
24 | }
25 |
26 | return [
27 | 'plugin' => 'wc',
28 | 'version' => $pluginVersion ?? null,
29 | 'wpcommerce' => $webpayPlusCommerceCode,
30 | 'wpenv' => $webpayPlusEnvironment,
31 | 'oneclickenv' => $oneclickEnvironment,
32 | 'oneclickcommerce' => $oneclickCommerceCode,
33 | 'oneclickmaxamount' => $oneclickMaxAmount,
34 | ];
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/plugin/src/Models/TransbankApiServiceLog.php:
--------------------------------------------------------------------------------
1 | $orderId,
21 | 'service' => $service,
22 | 'product' => $product,
23 | 'enviroment' => $enviroment,
24 | 'commerce_code' => $commerceCode,
25 | 'input' => $input,
26 | 'response' => $response
27 | ]);
28 | }
29 |
30 | public static function createError($orderId, $service, $product, $enviroment, $commerceCode, $input, $error, $originalError, $customError)
31 | {
32 | return static::insertBase(static::getTableName(), [
33 | 'order_id' => $orderId,
34 | 'service' => $service,
35 | 'product' => $product,
36 | 'enviroment' => $enviroment,
37 | 'commerce_code' => $commerceCode,
38 | 'input' => $input,
39 | 'error' => $error,
40 | 'original_error' => $originalError,
41 | 'custom_error' => $customError
42 | ]);
43 | }
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/plugin/src/Models/BaseModel.php:
--------------------------------------------------------------------------------
1 | base_prefix.$baseName;
15 | } else {
16 | return $wpdb->prefix.$baseName;
17 | }
18 | }
19 |
20 | public static function insertBase($tableName, array $data)
21 | {
22 | global $wpdb;
23 | return $wpdb->insert($tableName, $data);
24 | }
25 |
26 | public static function updateBase($tableName, $id, array $data)
27 | {
28 | global $wpdb;
29 |
30 | return $wpdb->update($tableName, $data, ['id' => $id]);
31 | }
32 |
33 | public static function checkExistTableBase($tableName)
34 | {
35 | global $wpdb;
36 | $sql = "SELECT COUNT(1) FROM ".$tableName;
37 | try {
38 | $wpdb->get_results($sql);
39 | $success = empty($wpdb->last_error);
40 | if (!$success) {
41 | return array('ok' => false,
42 | 'error' => "La tabla '{$tableName}' no se encontró en la base de datos.",
43 | 'exception' => "{$wpdb->last_error}");
44 | }
45 | } catch (\Exception $e) {
46 | return array('ok' => false,
47 | 'error' => "La tabla '{$tableName}' no se encontró en la base de datos.",
48 | 'exception' => "{$e->getMessage()}");
49 | }
50 | return array('ok' => true, 'msg' => "La tabla '{$tableName}' existe.");
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/plugin/src/PaymentGateways/TransbankRESTPaymentGateway.php:
--------------------------------------------------------------------------------
1 | getType() === 'REVERSED' ? 'Reversa' : 'Anulación';
18 | $amountFormatted = '$'.number_format($amount, 0, ',', '.');
19 | $commonFields = "
20 |
Reembolso exitoso
21 | Tipo: {$type}
22 | Monto reembolso: {$amountFormatted}";
23 |
24 | if($type === 'Reversa') {
25 | $note = "{$commonFields}
26 | ";
27 | }
28 | else {
29 | $balanceFormatted = '$'.number_format($response->getBalance(), 0, ',', '.');
30 | $transactionDate = $response->getAuthorizationDate();
31 | $formattedDate = TbkResponseUtil::transactionDateToLocalDate($transactionDate);
32 |
33 | $note = "{$commonFields}
34 | Saldo: {$balanceFormatted}
35 | Fecha: {$formattedDate}
36 | Código autorización: {$response->getAuthorizationCode()}
37 | Código de respuesta: {$response->getResponseCode()}
38 | ";
39 | }
40 |
41 | $order->add_order_note($note);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/WoocommerceInfoUtil.php:
--------------------------------------------------------------------------------
1 | prepare("SELECT * FROM $inscriptionTableName WHERE `token` = '%s'", $token);
40 | $sqlResult = $wpdb->get_results($sql);
41 | if (!is_array($sqlResult) || count($sqlResult) <= 0) {
42 | throw new TokenNotFoundOnDatabaseException("Token '{$token}' no se encontró en la base de datos de transacciones, por lo que no se puede completar el proceso");
43 | }
44 |
45 | return $sqlResult[0] ?? null;
46 | }
47 |
48 | public static function checkExistTable()
49 | {
50 | return static::checkExistTableBase(static::getTableName());
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/js/oneclick_checkout.js:
--------------------------------------------------------------------------------
1 | import { registerPaymentMethod } from '@woocommerce/blocks-registry';
2 | import { decodeEntities } from '@wordpress/html-entities';
3 | import { getSetting } from '@woocommerce/settings';
4 | import { noticeHandler } from './notice_handler';
5 | const { useEffect } = window.wp.element;
6 |
7 | const settings = getSetting( 'transbank_oneclick_mall_rest_data', {} );
8 | const label = decodeEntities( settings.title );
9 |
10 | noticeHandler(settings.id);
11 |
12 | const Content = ( props ) => {
13 |
14 | const {eventRegistration, emitResponse} = props;
15 | const { onCheckoutFail } = eventRegistration;
16 | useEffect( () => {
17 | const onError = ( { processingResponse } ) => {
18 | if ( processingResponse.paymentDetails.errorMessage ) {
19 | return {
20 | type: emitResponse.responseTypes.ERROR,
21 | message: processingResponse.paymentDetails.errorMessage,
22 | messageContext: emitResponse.noticeContexts.PAYMENTS
23 | };
24 | }
25 | return true;
26 | };
27 | const unsubscribe = onCheckoutFail( onError );
28 | return unsubscribe;
29 | }, [ onCheckoutFail ] );
30 |
31 | return decodeEntities( settings.description );
32 | };
33 |
34 | const Label = () => {
35 | const title = decodeEntities( settings.title );
36 | const imagePath = settings.icon;
37 | const paymentImage = (
38 |
39 | );
40 | return (
41 |
42 | {title}
43 | {paymentImage}
44 |
45 | );
46 | };
47 |
48 | const TransbankOneclickBlocks = {
49 | name: settings.id,
50 | label: ,
51 | content: ,
52 | edit: ,
53 | canMakePayment: () => true,
54 | ariaLabel: label,
55 | supports: {
56 | features: settings.supports
57 | }
58 | };
59 |
60 | registerPaymentMethod( TransbankOneclickBlocks );
61 |
--------------------------------------------------------------------------------
/package.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | SRC_DIR="plugin"
4 | MAIN_FILE="webpay-rest.php"
5 | README_FILE="readme.txt"
6 | COMPOSER_FILE="composer.json"
7 | COMPOSER_LOCK_FILE="composer.lock"
8 |
9 | package_plugin() {
10 | echo "Packaging plugin."
11 | check_tag
12 |
13 | cd $SRC_DIR
14 |
15 | composer install --no-dev > /dev/null 2>&1
16 |
17 | npm install --no-audit --no-fund --no-optional > /dev/null 2>&1
18 | npm run build > /dev/null 2>&1
19 |
20 | if [ $? -ne 0 ]; then
21 | echo "Command npm run build finished with error" 1>&2
22 | exit 1
23 | fi
24 |
25 | rm -rf node_modules/
26 |
27 | set_plugin_tag
28 |
29 | create_zip
30 |
31 | cd ..
32 |
33 | restore_files
34 |
35 | echo "\\nPlugin created, the detail is:"
36 | echo "- Version: $TAG"
37 | echo "- File name: $PLUGIN_FILE"
38 | }
39 |
40 | check_tag() {
41 | if [ "$TAG" = "" ]
42 | then
43 | echo "No Tag found. Using default Tag 1.0.0"
44 | TAG='1.0.0'
45 | fi
46 |
47 | echo "Tag: $TAG"
48 | }
49 |
50 | set_plugin_tag() {
51 | echo "Setting tag ${TAG#"v"} in readme and main file."
52 |
53 | sed -i.bkp "s/Version: VERSION_REPLACE_HERE/Version: ${TAG#"v"}/g" $MAIN_FILE
54 | sed -i.bkp "s/VERSION_REPLACE_HERE/${TAG#"v"}/g" $README_FILE
55 | }
56 |
57 | create_zip() {
58 | echo "Creating zip file."
59 |
60 | EXCLUSIONS="webpack.config.js *.lock *.json *.bkp"
61 | PLUGIN_FILE="transbank-webpay-plus-rest.zip"
62 |
63 | zip -FSr ../$PLUGIN_FILE . -x $EXCLUSIONS > /dev/null
64 | }
65 |
66 | restore_files() {
67 | echo "Restoring readme and main file."
68 |
69 | cp "$SRC_DIR/$MAIN_FILE.bkp" "$SRC_DIR/$MAIN_FILE"
70 | rm "$SRC_DIR/$MAIN_FILE.bkp"
71 | cp "$SRC_DIR/$README_FILE.bkp" "$SRC_DIR/$README_FILE"
72 | rm "$SRC_DIR/$README_FILE.bkp"
73 | }
74 |
75 | package_plugin
76 |
77 |
--------------------------------------------------------------------------------
/plugin/templates/public/order/order-summary.php:
--------------------------------------------------------------------------------
1 |
6 | Detalles del pago
7 |
8 |
9 |
10 | Orden de Compra:
11 |
12 |
13 |
14 | Código de autorización:
15 |
16 |
17 |
18 | Fecha transacción:
19 |
20 |
21 |
22 | Hora transacción:
23 |
24 |
25 |
26 | Número de tarjeta:
27 |
28 |
29 |
30 | Tipo de pago:
31 |
32 |
33 |
34 | Tipo de cuota:
35 |
36 |
37 |
38 | Monto compra:
39 |
40 |
41 |
42 | Número de cuotas:
43 |
44 |
45 | 0) { ?>
46 |
47 | Monto de cada cuota:
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/NoticeHelper.php:
--------------------------------------------------------------------------------
1 | render('public/notices/review-notice.php', [
26 | 'tbkLogo' => esc_url($tbkLogo)
27 | ]);
28 | }
29 | );
30 | }
31 |
32 | public static function dismissNoticesHandler()
33 | {
34 | $noticeId = $_POST['notice_id'] ?? '';
35 |
36 | if ($noticeId == self::NOTICE_REVIEW_ID) {
37 | $success = update_site_option('tbk_review_notice_showed', true);
38 | }
39 | }
40 |
41 | public static function registerNoticesDismissHook()
42 | {
43 | add_action('wp_ajax_dismiss_notice', NoticeHelper::class.'::dismissNoticesHandler');
44 | }
45 |
46 | /**
47 | * determines if the review notice should be displayed
48 | * @return boolean `true` when notice need to be showed, `false` otherwise
49 | */
50 | private static function shouldShowReviewNotice(): bool
51 | {
52 | $reviewNoticeShowed = get_site_option('tbk_review_notice_showed');
53 | if ($reviewNoticeShowed) {
54 | return false;
55 | }
56 |
57 | if (isset($_GET['page']) && isset($_GET['section'])) {
58 | return $_GET['page'] == 'wc-settings' && strstr($_GET['section'], 'transbank');
59 | }
60 |
61 | return false;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/ErrorUtil.php:
--------------------------------------------------------------------------------
1 | "error_message": "Not Authorized"
9 | status 422 => "error_message": "Api mismatch error, required version is 1.2"
10 | status 422 => "error_message": "Invalid value for parameter: token"
11 | status 422 => "error_message": "The transactions's date has passed max time (7 days) to recover the status"
12 | status 422 => "error_message": "Invalid value for parameter: transaction not found"
13 | */
14 |
15 | const DEFAULT_STATUS_ERROR_MESSAGE = 'Ocurrió un error al tratar de obtener el estado de la transacción.';
16 | const EXPIRED_TRANSACTION_ERROR_MESSAGE = 'La transacción supera los 7 días y ya no es posible consultarla por este medio.';
17 | const API_MISMATCH_ERROR_MESSAGE = 'La versión de API es distinta a la utilizada para crear la transacción.';
18 |
19 | public static function isApiMismatchError(\Throwable $e)
20 | {
21 | $error = $e->getMessage();
22 | $position = strpos($error, 'Api mismatch error');
23 | return $position !== false;
24 | }
25 |
26 | public static function getVersionFromApiMismatchError(\Throwable $e)
27 | {
28 | /* Estraemos la version del error 'Api mismatch error, required version is 1.3' */
29 | if (ErrorUtil::isApiMismatchError($e)){
30 | $pattern = '/\d+\.\d+/';
31 | if (preg_match($pattern, $e->getMessage(), $matches)) {
32 | return $matches[0];
33 | }
34 | }
35 | return null;
36 | }
37 |
38 | public static function isNotAuthorizedError(\Throwable $e)
39 | {
40 | $error = $e->getMessage();
41 | $position = strpos($error, 'Not Authorized');
42 | return $position !== false;
43 | }
44 |
45 | public static function isMaxTimeError(\Throwable $e)
46 | {
47 | $error = $e->getMessage();
48 | $position = strpos($error, 'date has passed max time');
49 | return $position !== false;
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/plugin/shared/Model/ProductConfig.php:
--------------------------------------------------------------------------------
1 | setActive($data['active']);
15 | $this->setProduction($data['production']);
16 | $this->setCommerceCode($data['commerceCode']);
17 | $this->setApikey($data['apikey']);
18 | $this->setOrderStatusAfterPayment($data['orderStatusAfterPayment']);
19 | }
20 | }
21 |
22 | /**
23 | * @return bool
24 | */
25 | public function isActive()
26 | {
27 | return $this->active;
28 | }
29 |
30 | /**
31 | * @param bool $active
32 | */
33 | public function setActive($active)
34 | {
35 | $this->active = $active;
36 | }
37 |
38 | /**
39 | * @return bool
40 | */
41 | public function isProduction()
42 | {
43 | return $this->production;
44 | }
45 |
46 | /**
47 | * @param bool $production
48 | */
49 | public function setProduction($production)
50 | {
51 | $this->production = $production;
52 | }
53 |
54 | public function getApikey()
55 | {
56 | return $this->apikey;
57 | }
58 |
59 | public function setApikey($apikey)
60 | {
61 | $this->apikey = $apikey;
62 | }
63 |
64 | public function getCommerceCode()
65 | {
66 | return $this->commerceCode;
67 | }
68 |
69 | public function setCommerceCode($commerceCode)
70 | {
71 | $this->commerceCode = $commerceCode;
72 | }
73 |
74 | public function getOrderStatusAfterPayment()
75 | {
76 | return $this->orderStatusAfterPayment;
77 | }
78 |
79 | public function setOrderStatusAfterPayment($orderStatusAfterPayment)
80 | {
81 | $this->orderStatusAfterPayment = $orderStatusAfterPayment;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/plugin/src/Controllers/ThankYouPageController.php:
--------------------------------------------------------------------------------
1 | isValidPaymentGateway($woocommerceOrder->get_payment_method())) {
20 | TbkFactory::createLogger()->logDebug(
21 | "La pasarela de pago no es válida, se ha pagado con {$woocommerceOrder->get_payment_method_title()}"
22 | );
23 | return;
24 | }
25 |
26 | $webpayTransaction = Transaction::getApprovedByOrderId($orderId);
27 |
28 | if (is_null($webpayTransaction)) {
29 | wc_print_notice('Transacción fallida . Puedes volver a intentar el pago', 'error');
30 | return;
31 | }
32 |
33 | wc_print_notice(__('Transacción aprobada', 'transbank_wc_plugin'), 'success');
34 | $transactionResponse = json_decode($webpayTransaction->transbank_response);
35 |
36 | $formattedResponse = [];
37 | if ($webpayTransaction->product == Transaction::PRODUCT_WEBPAY_ONECLICK) {
38 | $formattedResponse = TbkResponseUtil::getOneclickFormattedResponse($transactionResponse);
39 | } else {
40 | $formattedResponse = TbkResponseUtil::getWebpayFormattedResponse($transactionResponse);
41 | }
42 |
43 | (new Template())->render('public/order/order-summary.php', $formattedResponse);
44 | }
45 |
46 | private function isValidPaymentGateway($paymentMethod): bool
47 | {
48 | $paymentGateways = [
49 | WC_Gateway_Transbank_Webpay_Plus_REST::ID,
50 | WC_Gateway_Transbank_Oneclick_Mall_REST::ID
51 | ];
52 | return in_array($paymentMethod, $paymentGateways);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/WCGatewayTransbankBlocks.php:
--------------------------------------------------------------------------------
1 | settings = get_option( $this->paymentId . '_settings', []);
17 | $this->gateway = $this->get_gateway();
18 | add_action( 'woocommerce_rest_checkout_process_payment_with_context', [$this, 'processErrorPayment'], 10, 2 );
19 | }
20 |
21 | public function get_payment_method_script_handles() {
22 | wp_register_script(
23 | 'wc_transbank_'. $this->productName .'_payment',
24 | dirname(dirname(plugins_url('/', __FILE__))) . '/js/front/'. $this->productName .'_blocks.js',
25 | $this->scriptInfo['dependencies'],
26 | $this->scriptInfo['version'],
27 | true
28 | );
29 |
30 | return['wc_transbank_'. $this->productName .'_payment'];
31 | }
32 |
33 | public function get_payment_method_data() {
34 | return [
35 | 'title' => $this->gateway->title,
36 | 'description' => $this->gateway->description,
37 | 'supports' => $this->gateway->supports,
38 | 'icon' => $this->gateway->icon,
39 | 'id' => $this->gateway->id
40 | ];
41 | }
42 |
43 | private function get_gateway() {
44 | $gateways = WC()->payment_gateways->get_available_payment_gateways();
45 | if(isset($gateways[$this->paymentId])) {
46 | return $gateways[$this->paymentId];
47 | }
48 | return null;
49 | }
50 |
51 | public function processErrorPayment(PaymentContext $context, PaymentResult &$result) {
52 | add_action(
53 | 'wc_gateway_transbank_process_payment_error_' . $this->paymentId,
54 | function( $error, $shouldThrowError = false ) use ( &$result ) {
55 | $payment_details = $result->payment_details;
56 | $payment_details['errorMessage'] = wp_strip_all_tags( $error->getMessage() );
57 | $result->set_payment_details( $payment_details );
58 | $result->set_status('failure');
59 | if ($shouldThrowError) {
60 | throw $error;
61 | }
62 | }, 10, 2
63 | );
64 | }
65 |
66 | public function is_active() {
67 | if(isset($this->gateway)) {
68 | return $this->gateway->enabled == 'yes';
69 | }
70 | return false;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/TbkValidationUtil.php:
--------------------------------------------------------------------------------
1 | "error_message": "Not Authorized"
11 | * status 422 => "error_message": "Api mismatch error, required version is 1.2"
12 | * status 422 => "error_message": "Invalid value for parameter: token"
13 | * status 422 => "error_message":
14 | * "The transactions's date has passed max time (7 days) to recover the status"
15 | * status 422 => "error_message": "Invalid value for parameter: transaction not found"
16 | *
17 | */
18 | class TbkValidationUtil {
19 |
20 | /**
21 | * Este método recibe una excepción, y valida que sea del tipo:
22 | * status 422 => "error_message": "Api mismatch error, required version is 1.2"
23 | *
24 | * @param Throwable $e
25 | */
26 | public static function isApiMismatchError(Throwable $e)
27 | {
28 | $error = $e->getMessage();
29 | $position = strpos($error, 'Api mismatch error');
30 | return $position !== false;
31 | }
32 |
33 | /**
34 | * Este método recibe una excepción por uso de versión de api incorrecto
35 | * y extrae la versión del api usado.
36 | * El mensaje recibido tiene este formato 'Api mismatch error, required version is 1.3'
37 | *
38 | * @param Throwable $e
39 | */
40 | public static function getVersionFromApiMismatchError(Throwable $e)
41 | {
42 | if (TbkValidationUtil::isApiMismatchError($e)){
43 | $pattern = '/\d+\.\d+/';
44 | if (preg_match($pattern, $e->getMessage(), $matches)) {
45 | return $matches[0];
46 | }
47 | }
48 | return null;
49 | }
50 |
51 | /**
52 | * Este método recibe una excepción, y valida que sea del tipo:
53 | * status 401 => "error_message": "Not Authorized"
54 | *
55 | * @param Throwable $e
56 | */
57 | public static function isNotAuthorizedError(Throwable $e)
58 | {
59 | $error = $e->getMessage();
60 | $position = strpos($error, 'Not Authorized');
61 | return $position !== false;
62 | }
63 |
64 | /**
65 | * Este método recibe una excepción, y valida que sea del tipo:
66 | * status 422 => "error_message":
67 | * "The transactions's date has passed max time (7 days) to recover the status"
68 | *
69 | * @param Throwable $e
70 | */
71 | public static function isMaxTimeError(Throwable $e)
72 | {
73 | $error = $e->getMessage();
74 | $position = strpos($error, 'date has passed max time');
75 | return $position !== false;
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/TbkFactory.php:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Configuración
23 |
40 |
41 |
42 |
43 | show();
50 | } elseif ($tab === 'transactions') {
51 | include_once __DIR__.'/transactions.php';
52 | } else {
53 | include_once __DIR__.'/healthcheck.php';
54 | }
55 | ?>
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/InfoUtil.php:
--------------------------------------------------------------------------------
1 | =')) {
16 | return [
17 | 'status' => 'OK',
18 | 'version' => phpversion(),
19 | ];
20 | } else {
21 | return [
22 | 'status' => 'WARN: El plugin no ha sido testeado con esta version',
23 | 'version' => phpversion(),
24 | ];
25 | }
26 | }
27 |
28 | /**
29 | * Este método comprueba que la extensión se encuentre instalada.
30 | *
31 | * @param string $extension Es el nombre de la extensión a validar.
32 | * @return array
33 | */
34 | public static function getCheckExtension($extension)
35 | {
36 | if (extension_loaded($extension)) {
37 | if ($extension == 'openssl') {
38 | $version = OPENSSL_VERSION_TEXT;
39 | } else {
40 | $version = phpversion($extension);
41 | if (empty($version) || $version == null
42 | || $version === false || $version == ' ' || $version == '') {
43 | $version = 'PHP Extension Compiled. ver:'.phpversion();
44 | }
45 | }
46 | $status = 'OK';
47 | $result = [
48 | 'status' => $status,
49 | 'version' => $version,
50 | ];
51 | } else {
52 | $result = [
53 | 'status' => 'Error!',
54 | 'version' => 'No Disponible',
55 | ];
56 | }
57 |
58 | return $result;
59 | }
60 |
61 | /**
62 | * Este método obtiene un resumen del estado de las extensiones necesarias para el plugin
63 | *
64 | * @return array
65 | */
66 | public static function getExtensionsValidate()
67 | {
68 | $result = [];
69 | $extensions = [
70 | 'curl',
71 | 'json',
72 | 'dom',
73 | ];
74 | foreach ($extensions as $value) {
75 | $result[$value] = InfoUtil::getCheckExtension($value);
76 | }
77 |
78 | return $result;
79 | }
80 |
81 | /**
82 | * Este método obtiene informacion relevante del servidor.
83 | *
84 | * @return array
85 | */
86 | public static function getServerResume()
87 | {
88 | return $_SERVER['SERVER_SOFTWARE'];
89 | }
90 |
91 | public static function getSummary(){
92 | return [
93 | 'server' => InfoUtil::getServerResume(),
94 | 'phpExtensions' => InfoUtil::getExtensionsValidate(),
95 | 'php' => InfoUtil::getValidatephp()
96 | ];
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [[ -z "$GITHUB_ACTIONS" ]]; then
4 | echo "Script is only to be run by GitHub Actions" 1>&2
5 | exit 1
6 | fi
7 |
8 | if [[ -z "$WP_ORG_PASSWORD" ]]; then
9 | echo "WordPress.org password not set" 1>&2
10 | exit 1
11 | fi
12 |
13 | if [[ -z "$TAG" ]]; then
14 | echo "Build branch is required and must be a tag" 1>&2
15 | exit 0
16 | fi
17 |
18 | WP_ORG_USERNAME="transbankdevelopers"
19 | PLUGIN="transbank-webpay-plus-rest"
20 | PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
21 | PLUGIN_BUILDS_PATH="$PROJECT_ROOT/builds"
22 | PLUGIN_BUILD_CONFIG_PATH="$PROJECT_ROOT/build-cfg"
23 | VERSION=$TAG
24 | ZIP_FILE="$PROJECT_ROOT/$PLUGIN.zip"
25 |
26 | # Ensure the zip file for the current version has been built
27 | if [ ! -f "$ZIP_FILE" ]; then
28 | echo "Built zip file $ZIP_FILE does not exist" 1>&2
29 | exit 1
30 | fi
31 |
32 | mkdir -p $PLUGIN_BUILDS_PATH
33 |
34 | # Check if the tag exists for the version we are building
35 | TAG=$(svn ls "https://plugins.svn.wordpress.org/$PLUGIN/tags/$VERSION")
36 | error=$?
37 | if [ $error == 0 ]; then
38 | # Tag exists, don't deploy
39 | echo "Tag already exists for version $VERSION, aborting deployment"
40 | exit 1
41 | fi
42 |
43 | cd "$PLUGIN_BUILDS_PATH"
44 | # Remove any unzipped dir so we start from scratch
45 | rm -fR "$PLUGIN"
46 | # Unzip the built plugin
47 | unzip -q -o "$ZIP_FILE" -d $PLUGIN
48 |
49 | # Clean up any previous svn dir
50 | rm -fR svn
51 |
52 | # Checkout the SVN repo
53 | svn co -q "http://svn.wp-plugins.org/$PLUGIN" svn
54 |
55 | # Move out the trunk directory to a temp location
56 | mv svn/trunk ./svn-trunk
57 | # Create trunk directory
58 | mkdir svn/trunk
59 | # Copy our new version of the plugin into trunk
60 | rsync -r -p $PLUGIN/* svn/trunk
61 |
62 | # Copy all the .svn folders from the checked out copy of trunk to the new trunk.
63 | # This is necessary as the Travis container runs Subversion 1.6 which has .svn dirs in every sub dir
64 | cd svn/trunk/
65 | TARGET=$(pwd)
66 | cd ../../svn-trunk/
67 |
68 | # Find all .svn dirs in sub dirs
69 | SVN_DIRS=`find . -type d -iname .svn`
70 |
71 | for SVN_DIR in $SVN_DIRS; do
72 | SOURCE_DIR=${SVN_DIR/.}
73 | TARGET_DIR=$TARGET${SOURCE_DIR/.svn}
74 | TARGET_SVN_DIR=$TARGET${SVN_DIR/.}
75 | if [ -d "$TARGET_DIR" ]; then
76 | # Copy the .svn directory to trunk dir
77 | cp -r $SVN_DIR $TARGET_SVN_DIR
78 | fi
79 | done
80 |
81 | # Back to builds dir
82 | cd ../
83 |
84 | # Remove checked out dir
85 | rm -fR svn-trunk
86 |
87 | # Add new version tag
88 | mkdir svn/tags/$VERSION
89 | rsync -r -p $PLUGIN/* svn/tags/$VERSION
90 |
91 | # Add new files to SVN
92 | svn stat svn | grep '^?' | awk '{print $2}' | xargs -I x svn add x@
93 | # Remove deleted files from SVN
94 | svn stat svn | grep '^!' | awk '{print $2}' | xargs -I x svn rm --force x@
95 | svn stat svn
96 |
97 | # Commit to SVN
98 | svn ci --no-auth-cache --username $WP_ORG_USERNAME --password $WP_ORG_PASSWORD svn -m "Deploy version $VERSION"
99 |
100 | # Remove SVN temp dir
101 | rm -fR svn
102 |
--------------------------------------------------------------------------------
/plugin/shared/Helpers/TbkConstants.php:
--------------------------------------------------------------------------------
1 | "Venta Débito",
53 | "VN" => "Venta Normal",
54 | "VC" => "Venta en cuotas",
55 | "SI" => "3 cuotas sin interés",
56 | "S2" => "2 cuotas sin interés",
57 | "NC" => "N cuotas sin interés",
58 | "VP" => "Venta Prepago"
59 | ];
60 |
61 | const PAYMENT_TYPE_CREDIT = "Crédito";
62 | const PAYMENT_TYPE_DEBIT = "Débito";
63 | const PAYMENT_TYPE_PREPAID = "Prepago";
64 |
65 | const PAYMENT_TYPE = [
66 | "VD" => self::PAYMENT_TYPE_DEBIT,
67 | "VN" => self::PAYMENT_TYPE_CREDIT,
68 | "VC" => self::PAYMENT_TYPE_CREDIT,
69 | "SI" => self::PAYMENT_TYPE_CREDIT,
70 | "S2" => self::PAYMENT_TYPE_CREDIT,
71 | "NC" => self::PAYMENT_TYPE_CREDIT,
72 | "VP" => self::PAYMENT_TYPE_PREPAID
73 | ];
74 |
75 | const INSTALLMENT_TYPE = [
76 | "VC" => "Venta en cuotas",
77 | "SI" => "3 cuotas sin interés",
78 | "S2" => "2 cuotas sin interés",
79 | "NC" => "N cuotas sin interés"
80 | ];
81 |
82 | const STATUS_DESCRIPTION = [
83 | 'INITIALIZED' => 'Inicializada',
84 | 'AUTHORIZED' => 'Autorizada',
85 | 'REVERSED' => 'Reversada',
86 | 'FAILED' => 'Fallida',
87 | 'NULLIFIED' => 'Anulada',
88 | 'PARTIALLY_NULLIFIED' => 'Parcialmente anulada',
89 | 'CAPTURED' => 'Capturada',
90 | ];
91 |
92 | const ECOMMERCE_WOOCOMMERCE = 'woocommerce';
93 |
94 | const REPO_WOOCOMMERCE = 'TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest';
95 | const REPO_OFFICIAL_WOOCOMMERCE = 'woocommerce/woocommerce';
96 |
97 | const RETURN_URL_PARAM = 'plugin';
98 | }
99 |
--------------------------------------------------------------------------------
/plugin/src/Blocks/js/notice_handler.js:
--------------------------------------------------------------------------------
1 | const oneClickId = "transbank_oneclick_mall_rest";
2 | const url = new URL(window.location.href);
3 | const params = new URLSearchParams(url.search);
4 | const hasTbkData = params.has("transbank_status");
5 |
6 | const noticeTypes = {
7 | SUCCESS: "success",
8 | ERROR: "error"
9 | };
10 |
11 | const oneClickNoticeData = {
12 | 0: {
13 | message:
14 | "La tarjeta ha sido inscrita satisfactoriamente. Aún no se realiza ningún cobro. Ahora puedes realizar el pago.",
15 | type: noticeTypes.SUCCESS
16 | },
17 | 1: {
18 | message:
19 | "La inscripción fue cancelada automáticamente por estar inactiva mucho tiempo.",
20 | type: noticeTypes.ERROR
21 | },
22 | 2: {
23 | message: "No se recibió el token de la inscripción.",
24 | type: noticeTypes.ERROR
25 | },
26 | 3: {
27 | message: "El usuario canceló la inscripción en el formulario de pago.",
28 | type: noticeTypes.ERROR
29 | },
30 | 4: {
31 | message: "La inscripción no se encuentra en estado inicializada.",
32 | type: noticeTypes.ERROR
33 | },
34 | 5: {
35 | message: "Ocurrió un error al ejecutar la inscripción.",
36 | type: noticeTypes.ERROR
37 | },
38 | 6: {
39 | message: "La inscripción de la tarjeta ha sido rechazada.",
40 | type: noticeTypes.ERROR
41 | }
42 | };
43 |
44 | const webPayNoticeNoticeData = {
45 | 7: { message: "Transacción aprobada", type: noticeTypes.SUCCESS },
46 | 8: {
47 | message:
48 | "Ocurrió un error al confirmar la transacción, ya se encontraba procesada.",
49 | type: noticeTypes.ERROR
50 | },
51 | 9: {
52 | message: "El usuario intentó pagar una orden con estado inválido.",
53 | type: noticeTypes.ERROR
54 | },
55 | 10: {
56 | message:
57 | "La transacción fue cancelada por exceder el tiempo en el formulario de Webpay.",
58 | type: noticeTypes.ERROR
59 | },
60 | 11: {
61 | message:
62 | "El usuario canceló la transacción en el formulario de pago, pero esta orden ya estaba pagada o en un estado diferente a INICIALIZADO",
63 | type: noticeTypes.ERROR
64 | },
65 | 12: {
66 | message: "Cancelaste la transacción durante el formulario de Webpay Plus.",
67 | type: noticeTypes.ERROR
68 | },
69 | 13: { message: "El pago es inválido.", type: noticeTypes.ERROR },
70 | 14: {
71 | message: "La transacción no se encuentra en estado inicializada.",
72 | type: noticeTypes.ERROR
73 | },
74 | 15: {
75 | message: "El commit de la transacción ha sido rechazada en Transbank",
76 | type: noticeTypes.ERROR
77 | },
78 | 16: {
79 | message:
80 | "Ocurrió un error al confirmar la transacción, favor intente nuevamente.",
81 | type: noticeTypes.ERROR
82 | },
83 | 17: {
84 | message:
85 | "No se pudo procesar el pago. Si el problema persiste, contacte al comercio.",
86 | type: noticeTypes.ERROR
87 | }
88 | };
89 |
90 | export const noticeHandler = (productId) => {
91 | if (hasTbkData) {
92 | const productNoticeData =
93 | productId == oneClickId ? oneClickNoticeData : webPayNoticeNoticeData;
94 | const statusCode = params.get("transbank_status");
95 | if (!productNoticeData.hasOwnProperty(statusCode)) {
96 | return;
97 | }
98 | const noticeMessage = productNoticeData[statusCode]["message"];
99 | const notificationType = productNoticeData[statusCode]["type"];
100 | switch (notificationType) {
101 | case noticeTypes.SUCCESS:
102 | wp.data
103 | .dispatch("core/notices")
104 | .createSuccessNotice(noticeMessage, { context: "wc/checkout" });
105 | break;
106 | case noticeTypes.ERROR:
107 | wp.data
108 | .dispatch("core/notices")
109 | .createErrorNotice(noticeMessage, { context: "wc/checkout" });
110 | break;
111 | }
112 | }
113 | };
114 |
--------------------------------------------------------------------------------
/plugin/src/TransbankSdk.php:
--------------------------------------------------------------------------------
1 | log->logInfo($str);
33 | }
34 |
35 | public function logError($str)
36 | {
37 | $this->log->logError($str);
38 | }
39 |
40 | public function getEnviroment() {
41 | return $this->options->getIntegrationType();
42 | }
43 |
44 | public function getCommerceCode() {
45 | return $this->options->getCommerceCode();
46 | }
47 |
48 | public function logInfoData($buyOrder, $msg, $param)
49 | {
50 | $maskedBuyOrder = $this->dataMasker->maskBuyOrder($buyOrder);
51 | $param['environment'] = $this->getEnviroment();
52 | $param['commerceCode'] = $this->getCommerceCode();
53 | $maskedParams = $this->dataMasker->maskData($param);
54 | $this->logInfo('BUY_ORDER: '.$maskedBuyOrder.' => '.$msg.' => data: '.json_encode($maskedParams));
55 | }
56 |
57 | public function logErrorData($buyOrder, $errorMsg, $param)
58 | {
59 | $param['environment'] = $this->getEnviroment();
60 | $param['commerceCode'] = $this->getCommerceCode();
61 | $this->logError('BUY_ORDER: '.$buyOrder.' => '.$errorMsg.' => data: '.json_encode($param));
62 | }
63 |
64 | protected function logErrorWithOrderId($orderId, $service, $input, $error, $originalError, $customError){
65 | $maskedInput = $this->dataMasker->maskData($input);
66 | $messageError = (isset($customError) ? $customError : $originalError);
67 | $this->logError('ORDER_ID: '.$orderId.', SERVICE: '.$service);
68 | $this->logError('INPUT: '.json_encode($maskedInput).' => EXCEPTION: '.$error.' , ERROR: '.$messageError);
69 | }
70 |
71 | protected function logInfoWithOrderId($orderId, $service, $message, $data){
72 | $maskedData = $this->dataMasker->maskData($data);
73 | $this->logInfo('ORDER_ID: '.$orderId.', SERVICE: '.$service);
74 | $this->logInfo('message: '.$message.', DATA: '.json_encode($maskedData));
75 | }
76 |
77 | protected function createApiServiceLogBase($orderId, $service, $product, $input, $response)
78 | {
79 | TransbankApiServiceLog::create($orderId, $service, $product, $this->getEnviroment(), $this->getCommerceCode(), json_encode($input), json_encode($response));
80 | }
81 |
82 | protected function createErrorApiServiceLogBase($orderId, $service, $product, $input, $error, $originalError, $customError)
83 | {
84 | TransbankApiServiceLog::createError($orderId, $service, $product, $this->getEnviroment(), $this->getCommerceCode(), json_encode($input), $error, $originalError, $customError);
85 | $this->createTransbankExecutionErrorLogBase($orderId, $service, $product, $input, $error, $originalError, $customError);
86 | }
87 |
88 | protected function createTransbankExecutionErrorLogBase($orderId, $service, $product, $data, $error, $originalError, $customError)
89 | {
90 | TransbankExecutionErrorLog::create($orderId, $service, $product, $this->getEnviroment(), $this->getCommerceCode(), json_encode($data), $error, $originalError, $customError);
91 | }
92 |
93 | protected function generateBuyOrder($orderId){
94 | return BuyOrderHelper::generateFromFormat($this->buyOrderFormat, $orderId);
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/plugin/views/admin/admin-options.php:
--------------------------------------------------------------------------------
1 |
12 |
13 |
18 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
38 |
39 |
¡Excelente!
40 |
41 |
42 |
Ahora que ya tienes el plugin instalado, tu sitio ya está habilitado para que tus clientes puedan pagar usando Webpay Plus.
43 | Asegúrate de que tu tienda esté
44 | configurada para aceptar pesos chilenos
45 |
46 |
47 |
48 |
49 |
50 |
Notarás que el plugin viene configurado en modo Integración, por lo que opera en un ambiente de pruebas, con dinero y tarjetas de prueba.
51 |
52 |
¿Que hago ahora?
53 |
Verifica que todo funcione correctamente. Realiza algunas compras con tarjetas de crédito y de débito, además de probar con transacciones aprobadas y rechazadas.
54 |
55 |
56 |
Documentación
57 |
Encuentra más detalles y funcionalidades en la documentación oficial del plugin
58 |
59 |
60 |
61 |
62 | Ver mensaje de bienvenida nuevamente
63 |
64 |
82 |
99 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/BuyOrderHelper.php:
--------------------------------------------------------------------------------
1 |
52 | /bin/sh -c '
53 | sleep 40;
54 | sed -i "s|# END WordPress|php_value upload_max_filesize 5000M \\n php_value post_max_size 5000M \\n php_value memory_limit 256M \\n php_value max_execution_time 300 \\n php_value max_input_time 300 \\n |g" /var/www/html/.htaccess;
55 | wp core install --path="/var/www/html" --url="http://localhost:8000" --title="Transbank Store" --admin_user=admin --admin_password=admin --admin_email=transbankdevelopers@continuum.cl;
56 | wp --allow-root plugin install woocommerce --version=9.4.2 --activate;
57 | wp --allow-root theme install storefront --activate;
58 | wp --allow-root wc tool run install_pages --user=admin;
59 | wp --allow-root wc product create --name="Zapatos deportivos" --sku=1 --regular_price=1000 --status=publish --user=admin;
60 | wp --allow-root db query "UPDATE wp_options SET option_value=\"CLP\" WHERE option_name=\"woocommerce_currency\";";
61 | wp --allow-root db query "UPDATE wp_options SET option_value=\"General Bustamante 24\" WHERE option_name=\"woocommerce_store_address\";";
62 | wp --allow-root db query "UPDATE wp_options SET option_value=\"Of M, Piso 7\" WHERE option_name=\"woocommerce_store_address_2\";";
63 | wp --allow-root db query "UPDATE wp_options SET option_value=\"Providencia\" WHERE option_name=\"woocommerce_store_city\";";
64 | wp --allow-root db query "UPDATE wp_options SET option_value=\"CL\" WHERE option_name=\"woocommerce_default_country\";";
65 | wp --allow-root db query "UPDATE wp_options SET option_value=\"7500000\" WHERE option_name=\"woocommerce_store_postcode\";";
66 | wp --allow-root db query "UPDATE wp_options SET option_value=0 WHERE option_name=\"woocommerce_price_num_decimals\";";
67 | wp --allow-root db query "UPDATE wp_options SET option_value=\".\" WHERE option_name=\"woocommerce_price_thousand_sep\";";
68 | wp --allow-root db query "UPDATE wp_options SET option_value=\",\" WHERE option_name=\"woocommerce_price_decimal_sep\";";
69 | wp --allow-root config set WP_DEBUG true;
70 | wp --allow-root config set --add --type=constant WP_DEBUG_LOG true;
71 | wp --allow-root config set --add --type=constant WP_DEBUG_DISPLAY false;
72 | wp --allow-root config set --add --type=constant WPS_DEBUG true;
73 | wp --allow-root config set --add --type=constant WPS_DEBUG_SCRIPTS true;
74 | wp --allow-root config set --add --type=constant WPS_DEBUG_STYLES true;
75 | '
76 | volumes_from:
77 | - wordpress
78 | links:
79 | - db
80 |
--------------------------------------------------------------------------------
/plugin/templates/admin/log.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
Información de Registros
12 |
13 |
16 |
17 | Directorio de registros:
18 |
19 |
20 |
21 | = $resume['dir'] ?>
22 |
23 |
24 |
25 |
26 |
30 |
31 | Lista de logs:
32 |
33 |
34 |
63 |
64 |
65 |
66 |
Información del archivo
67 |
68 |
69 |
73 |
74 | Peso del Documento:
75 |
76 |
77 |
78 | = $lastLog['size'] ?? '-'; ?>
79 |
80 |
81 |
82 |
83 |
86 |
87 | Cantidad de Líneas:
88 |
89 |
90 |
91 | = $lastLog['lines'] ?? '-'; ?>
92 |
93 |
94 |
95 |
96 |
97 | ';
100 |
101 | $logLines = explode("\n", $lastLog['content']);
102 |
103 | foreach ($logLines as $line) {
104 | $chunks = explode(' > ', $line);
105 |
106 | $date = $chunks[0];
107 | $level = $chunks[1] ?? null;
108 | $message = $chunks[2] ?? null;
109 |
110 | if (!is_null($date) && !is_null($level) && !is_null($message)) {
111 | $logContent .= '
' . $date . ' > ' .
112 | '' . $level . ' > ' . $message .
113 | ' ';
114 | }
115 | }
116 | $logContent .= '
';
117 | echo $logContent;
118 | }
119 | ?>
120 |
121 |
--------------------------------------------------------------------------------
/docs/INSTALLATION.md:
--------------------------------------------------------------------------------
1 | # Manual de instalación para Plugin Woocommerce
2 |
3 | ## Descripción
4 |
5 | Este plugin oficial ha sido creado para que puedas integrar Webpay fácilmente en tu comercio, basado en Woocommerce.
6 |
7 | ## Requisitos
8 |
9 | Debes tener instalado previamente Woocommerce.
10 |
11 | Habilitar los siguientes módulos / extensiones para PHP:
12 | - OpenSSL 1.0.1 o superior
13 | - SimpleXML
14 | - DOM 2.7.8 o superior
15 |
16 | ## Instalación de Plugin
17 |
18 | 1. Dirígete a [https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest), y descargue la última versión disponible del plugin.
19 |
20 | Una vez descargado el plugin, ingresa a la página de administración de Woocommerce (usualmente en http://misitio.com/wp-admin, http://localhost/wp-admin) y dirígete a (Plugins / Add New), indicado a continuación:
21 |
22 | 
23 |
24 | 2. Selecciona el archivo que descargaste en el paso anterior. Al finalizar aparecerá que fue instalado exitosamente.
25 |
26 | 
27 |
28 | 3. Además debes `Activar Plugin`.
29 |
30 | 
31 |
32 | ## Configuración
33 |
34 | Este plugin posee un sitio de configuración que te permitirá ingresar credenciales que Transbank te otorgará y además podrás generar un documento de diagnóstico en caso que Transbank te lo pida.
35 |
36 | **IMPORTANTE:** El plugin solamente funciona con moneda chilena (CLP). Dado esto Woocommerce debe estar configurado con moneda Peso Chileno y país Chile para que se pueda usar Webpay.
37 |
38 | Para acceder a la configuración, debes seguir los siguientes pasos:
39 |
40 | 1. Dirígete a la página de administración de Woocommerce (usualmente en http://misitio.com/wp-admin, http://localhost/wp-admin) e ingresa usuario y clave.
41 |
42 | 2. Dentro del sitio de administración dirígete a (Plugins / Installed Plugins) y busca `Transbank Webpay Plus`.
43 |
44 | 
45 |
46 | 3. Presiona el link `Settings` del plugin y te llevará a la pagina de configuración del plugin.
47 |
48 | 
49 |
50 | 4. ¡Ya está! Estás en la pantalla de configuración del plugin, debes ingresar la siguiente información:
51 |
52 | * **Ambiente**: Ambiente hacia donde se realiza la transacción.
53 | * **Código de comercio**: Es lo que te identifica como comercio.
54 | * **API Key**: API Key es la clave para acceder a los servicios rest de webpay.
55 |
56 |
57 | Las opciones disponibles para _Ambiente_ son: "Integración" para realizar pruebas y certificar la instalación con Transbank, y "Producción" para hacer transacciones reales una vez que Transbank ha aprobado el comercio.
58 |
59 | ### Credenciales de Prueba
60 |
61 | Para el ambiente de Integración, puedes utilizar las siguientes credenciales para realizar pruebas:
62 |
63 | * Código de comercio: `597055555540`
64 | * API Key : `579B532A7440BB0C9079DED94D31EA1615BACEB56610332264630D42D0A36B1C`
65 |
66 |
67 | 1. Guardar los cambios presionando el botón [Save changes]
68 |
69 | 2. Además, puedes generar un documento de diagnóstico en caso que Transbank te lo pida. Para ello, haz click en el Tab "Diagnóstico" en el botón "Mostrar diagnóstico en Html" ahí podrás visualizarlo en Html e imprimirlo en PDF.
70 |
71 | 
72 |
73 | ## Prueba de instalación con transacción
74 |
75 | En ambiente de integración es posible realizar una prueba de transacción utilizando un emulador de pagos online.
76 |
77 | * Ingresa al comercio
78 |
79 | 
80 |
81 | * Ingresa a cualquier sección para agregar productos
82 |
83 | 
84 |
85 | * Agrega al carro de compras un producto, selecciona el carro de compras y luego presiona el botón [Proceed to checkout]:
86 |
87 | 
88 |
89 | * Agrega los datos que te pida y selecciona `Transbank Webpay` luego presiona el botón [Place order]
90 |
91 | 
92 |
93 | * Una vez presionado el botón para iniciar la compra, se mostrará la ventana de pago Webpay y deberás seguir el proceso de pago.
94 |
95 | Para pruebas puedes usar los siguientes datos:
96 |
97 | * Número de tarjeta: `4051885600446623`
98 | * Rut: `11.111.111-1`
99 | * Cvv: `123`
100 |
101 | 
102 |
103 | Para pruebas puedes usar los siguientes datos:
104 |
105 | * Rut: `11.111.111-1`
106 | * Clave: `123`
107 |
108 | 
109 |
110 | Puedes aceptar o rechazar la transacción
111 |
112 | 
113 |
114 | 
115 |
116 | * Serás redirigido a Woocommerce y podrás comprobar que el pago ha sido exitoso.
117 |
118 | 
119 |
120 | * Además si accedes al sitio de administración sección (Woocommerce / Orders) se podrá ver la orden creada y el detalle de los datos entregados por Webpay.
121 |
122 | 
123 |
124 | 
125 |
126 | ## Pasar a producción
127 | Para operar en el ambiente de producción (con dinero real) debes pasar un proceso de validación. Puedes ver las instrucciones [acá](https://transbankdevelopers.cl/plugin/woocommerce/#puesta-en-produccion)
128 |
--------------------------------------------------------------------------------
/plugin/views/admin/oneclick-admin-options.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
16 |
17 |
18 |
19 |
Webpay Oneclick Mall
20 |
Webpay Oneclick le permite a tus usuarios inscribir su tarjeta en su cuenta de usuario dentro de tu sitio, para que luego puedan
21 | comprar con un solo click.
22 |
Este plugin funciona en modalidad MALL. Esto significa que tienes un código de comercio
23 | mall y código de comercio tienda . Cuando un usuario inscribe su
24 | tarjeta, lo hace asociando su tarjeta al código de comercio Mall, pero cuando se realiza una transacción, el dinero de esa transacción
25 | se pagará al código de comercio "tienda" y no al "mall".
26 |
27 |
28 | VIDEO
29 |
30 |
31 |
32 |
33 |
39 |
40 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
¡Bienvenido a Webpay Oneclick!
55 |
56 |
57 |
Este plugin también incluye integración con Webpay Oneclick Mall REST, para que tus clientes puedan
58 | inscribir su tarjeta de crédito, débito o prepago, y así puedan realizar sus siguientes compras con un solo
59 | click.
60 |
61 |
Para Webpay Plus, necesitas un código de comercio y un Api Key. Para Webpay Oneclick necesitas otros códigos
62 | de comercio que te entregarán cuando contrates este producto. En este necesitas un código de comercio mall,
63 | un código de comercio tienda y un Api Key (llave secreta) para poder operar en producción.
64 |
65 |
66 |
Notarás que el plugin viene configurado en modo Integración, por lo que opera en un ambiente de pruebas, con
67 | dinero y tarjetas de prueba.
68 |
69 |
¿Que hago ahora?
70 |
Verifica que todo funcione correctamente. Realiza algunas compras con tarjetas de crédito y de débito, además de
71 | probar con transacciones aprobadas y rechazadas.
72 |
73 |
Documentación
74 |
Encuentra más detalles y funcionalidades en la documentación oficial del plugin
75 |
76 |
Conoce las novedades
77 |
VIDEO
78 |
79 |
80 |
81 | Ver mensaje de bienvenida nuevamente
82 |
100 |
117 |
--------------------------------------------------------------------------------
/plugin/src/Tokenization/WC_Payment_Token_Oneclick.php:
--------------------------------------------------------------------------------
1 | '',
13 | 'username' => '',
14 | 'email' => '',
15 | 'card_type' => '',
16 | 'environment' => '',
17 | ];
18 |
19 | /**
20 | * Get type to display to user.
21 | *
22 | * @since 2.6.0
23 | *
24 | * @param string $deprecated Deprecated since WooCommerce 3.0.
25 | *
26 | * @return string
27 | */
28 | public function get_display_name($deprecated = '')
29 | {
30 | $testPrefix = ($this->get_environment() === Options::ENVIRONMENT_PRODUCTION ? '' : '[TEST] ');
31 |
32 | return $testPrefix.$this->get_card_type().' terminada en '.$this->get_last4();
33 | }
34 |
35 | public function validate()
36 | {
37 | if (false === parent::validate()) {
38 | return false;
39 | }
40 | if (!$this->get_last4('edit')) {
41 | return false;
42 | }
43 |
44 | if (!$this->get_card_type('edit')) {
45 | return false;
46 | }
47 |
48 | if (!$this->get_username('edit')) {
49 | return false;
50 | }
51 |
52 | if (!$this->get_environment('edit')) {
53 | $this->set_environment(Options::ENVIRONMENT_INTEGRATION);
54 |
55 | return false;
56 | }
57 |
58 | if (!$this->get_email('edit') || !filter_var($this->get_email('edit'), FILTER_VALIDATE_EMAIL)) {
59 | return false;
60 | }
61 |
62 | return true;
63 | }
64 |
65 | /**
66 | * Hook prefix.
67 | *
68 | * @since 3.0.0
69 | */
70 | protected function get_hook_prefix()
71 | {
72 | return 'woocommerce_payment_token_oneclick_get_';
73 | }
74 |
75 | /**
76 | * Returns the card type (mastercard, visa, ...).
77 | *
78 | * @since 2.6.0
79 | *
80 | * @param string $context What the value is for. Valid values are view and edit.
81 | *
82 | * @return string Card type
83 | */
84 | public function get_card_type($context = 'view')
85 | {
86 | return $this->get_prop('card_type', $context);
87 | }
88 |
89 | /**
90 | * Set the card type (mastercard, visa, ...).
91 | *
92 | * @since 2.6.0
93 | *
94 | * @param string $type Credit card type (mastercard, visa, ...).
95 | */
96 | public function set_card_type($type)
97 | {
98 | $this->set_prop('card_type', $type);
99 | }
100 |
101 | /**
102 | * Returns the last four digits.
103 | *
104 | * @since 2.6.0
105 | *
106 | * @param string $context What the value is for. Valid values are view and edit.
107 | *
108 | * @return string Last 4 digits
109 | */
110 | public function get_last4($context = 'view')
111 | {
112 | return $this->get_prop('last4', $context);
113 | }
114 |
115 | /**
116 | * Set the last four digits.
117 | *
118 | * @since 2.6.0
119 | *
120 | * @param string $last4 Credit card last four digits.
121 | */
122 | public function set_last4($last4)
123 | {
124 | $this->set_prop('last4', $last4);
125 | }
126 |
127 | /**
128 | * Returns the last four digits.
129 | *
130 | * @since 2.6.0
131 | *
132 | * @param string $context What the value is for. Valid values are view and edit.
133 | *
134 | * @return string Last 4 digits
135 | */
136 | public function get_username($context = 'view')
137 | {
138 | return $this->get_prop('username', $context);
139 | }
140 |
141 | /**
142 | * Set the last four digits.
143 | *
144 | * @since 2.6.0
145 | *
146 | * @param string $username Credit card last four digits.
147 | */
148 | public function set_username($username)
149 | {
150 | $this->set_prop('username', $username);
151 | }
152 |
153 | /**
154 | * Returns the token oneclick environement.
155 | *
156 | * @param string $context What the value is for. Valid values are view and edit.
157 | *
158 | * @return string [TEST|LIVE]
159 | */
160 | public function get_environment($context = 'view')
161 | {
162 | return $this->get_prop('environment', $context);
163 | }
164 |
165 | /**
166 | * Set the token environment.
167 | *
168 | * @param string $environment Credit card last four digits.
169 | */
170 | public function set_environment($environment)
171 | {
172 | $this->set_prop('environment', $environment);
173 | }
174 |
175 | /**
176 | * Returns the last four digits.
177 | *
178 | * @since 2.6.0
179 | *
180 | * @param string $context What the value is for. Valid values are view and edit.
181 | *
182 | * @return string Last 4 digits
183 | */
184 | public function get_email($context = 'view')
185 | {
186 | return $this->get_prop('email', $context);
187 | }
188 |
189 | /**
190 | * Set the last four digits.
191 | *
192 | * @since 2.6.0
193 | *
194 | * @param string $email Credit card last four digits.
195 | */
196 | public function set_email($email)
197 | {
198 | $this->set_prop('email', $email);
199 | }
200 |
201 | /**
202 | * Returns the user id of the inscriptions.
203 | *
204 | * @param string $context What the value is for. Valid values are view and edit.
205 | *
206 | * @return int The user id.
207 | */
208 | public function get_userId($context = 'view')
209 | {
210 | return $this->get_prop('user_id', $context);
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/plugin/src/Models/Transaction.php:
--------------------------------------------------------------------------------
1 | $value) {
37 | $whereClauses[] = "`$column` = %s";
38 | $values[] = $value;
39 | }
40 |
41 | $whereSql = implode(' AND ', $whereClauses);
42 | $sql = "SELECT * FROM {$tableName} WHERE {$whereSql}";
43 | $safeSql = $wpdb->prepare($sql, $values);
44 |
45 | if (!empty($orderBy)) {
46 | if (is_array($orderBy)) {
47 | $orderBy = implode(", ", array_map('esc_sql', $orderBy));
48 | } else {
49 | $orderBy = esc_sql($orderBy);
50 | }
51 | $orderDirection = strtoupper($orderDirection) === 'DESC' ? 'DESC' : 'ASC';
52 | $safeSql .= " ORDER BY {$orderBy} {$orderDirection}";
53 | }
54 |
55 | return $wpdb->get_results($safeSql);
56 | }
57 |
58 | /**
59 | * Get transaction by order ID.
60 | *
61 | * @param string $orderId Order ID.
62 | *
63 | * @return object|null Transaction data.
64 | */
65 | public static function getByOrderId($orderId): ?object
66 | {
67 | return static::getTransactionsByConditions(['order_id' => $orderId], 'id')[0] ?? null;
68 | }
69 |
70 | /**
71 | * @return string
72 | */
73 | public static function getTableName(): string
74 | {
75 | return static::getBaseTableName(static::TRANSACTIONS_TABLE_NAME);
76 | }
77 |
78 | public static function createTransaction(array $data)
79 | {
80 | return static::insertBase(static::getTableName(), $data);
81 | }
82 |
83 | public static function update($transactionId, array $data)
84 | {
85 | return static::updateBase(static::getTableName(), $transactionId, $data);
86 | }
87 |
88 | /**
89 | * @throws TokenNotFoundOnDatabaseException
90 | */
91 | public static function getByToken($token)
92 | {
93 | global $wpdb;
94 | $transactionTable = static::getTableName();
95 | $sql = $wpdb->prepare("SELECT * FROM $transactionTable WHERE `token` = '%s'", $token);
96 | $sqlResult = $wpdb->get_results($sql);
97 | if (!is_array($sqlResult) || count($sqlResult) <= 0) {
98 | throw new TokenNotFoundOnDatabaseException("Token '{$token}' no se encontró en la base de datos de transacciones, por lo que no se puede completar el proceso");
99 | }
100 |
101 | return $sqlResult[0];
102 | }
103 |
104 | public static function getApprovedByOrderId($orderId)
105 | {
106 | global $wpdb;
107 | $transaction = static::getTableName();
108 | $statusApproved = static::STATUS_APPROVED;
109 | $sql = $wpdb->prepare(
110 | "SELECT * FROM $transaction WHERE status = '$statusApproved' AND order_id = '%s'",
111 | $orderId
112 | );
113 | $sqlResult = $wpdb->get_results($sql);
114 |
115 | return $sqlResult[0] ?? null;
116 | }
117 |
118 | /**
119 | * @throws TokenNotFoundOnDatabaseException
120 | */
121 | public static function getByBuyOrderAndSessionId($buyOrder, $sessionId)
122 | {
123 | global $wpdb;
124 | $transactionTableName = Transaction::getTableName();
125 | $sql = $wpdb->prepare(
126 | "SELECT * FROM $transactionTableName WHERE session_id = '%s' && buy_order='%s'",
127 | $sessionId,
128 | $buyOrder
129 | );
130 | $sqlResult = $wpdb->get_results($sql);
131 | if (!is_array($sqlResult) || count($sqlResult) <= 0) {
132 | throw new TokenNotFoundOnDatabaseException('No se encontró el session_id y buy_order en la base de datos de transacciones, por lo que no se puede completar el proceso');
133 | }
134 |
135 | return $sqlResult[0];
136 | }
137 |
138 | public static function getByBuyOrder($buyOrder)
139 | {
140 | global $wpdb;
141 | $transactionTableName = Transaction::getTableName();
142 | $sql = $wpdb->prepare(
143 | "SELECT * FROM $transactionTableName WHERE buy_order = '%s'",
144 | $buyOrder
145 | );
146 | $sqlResult = $wpdb->get_results($sql);
147 | if (!is_array($sqlResult) || count($sqlResult) <= 0) {
148 | throw new TokenNotFoundOnDatabaseException('No se encontró el session_id y order_id en la base de datos de transacciones, por lo que no se puede completar el proceso');
149 | }
150 | return $sqlResult[0];
151 | }
152 |
153 | public static function checkExistTable()
154 | {
155 | return static::checkExistTableBase(static::getTableName());
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/plugin/src/Controllers/TransactionStatusController.php:
--------------------------------------------------------------------------------
1 | logger = TbkFactory::createLogger();
30 | }
31 |
32 | public function getStatus(): void
33 | {
34 | $response = [
35 | 'body' => [
36 | 'message' => ErrorUtil::DEFAULT_STATUS_ERROR_MESSAGE
37 | ]
38 | ];
39 |
40 | $this->logger->logInfo('Obteniendo estado de la transacción.');
41 |
42 | // Check for nonce security
43 | $nonce = sanitize_text_field($_POST['nonce']);
44 |
45 | if (!wp_verify_nonce($nonce, 'my-ajax-nonce')) {
46 | $this->logger->logError($response['body']['message']);
47 | wp_send_json($response['body'], self::HTTP_UNPROCESSABLE_ENTITY);
48 | return;
49 | }
50 |
51 | $orderId = $this->getSecureInputValue('order_id');
52 | $buyOrder = $this->getSecureInputValue('buy_order');
53 | $token = $this->getSecureInputValue('token');
54 |
55 | $requestMethod = $_SERVER['REQUEST_METHOD'];
56 | $params = ['orderId' => $orderId, 'buyOrder' => $buyOrder, 'token' => $token];
57 |
58 | $this->logger->logDebug("Request: method -> $requestMethod");
59 | $this->logger->logDebug('Request: payload -> ' . json_encode($params));
60 |
61 | try {
62 | $transaction = Transaction::getByOrderId($orderId);
63 |
64 | if (!$transaction) {
65 | $this->logger->logError(self::NO_TRANSACTION_ERROR_MESSAGE);
66 | $response['body']['message'] = self::NO_TRANSACTION_ERROR_MESSAGE;
67 | wp_send_json($response['body'], self::HTTP_UNPROCESSABLE_ENTITY);
68 | return;
69 | }
70 |
71 | $this->logger->logInfo('Transacción encontrada.');
72 | $response = $this->handleGetStatus($transaction, $orderId, $buyOrder, $token);
73 |
74 | wp_send_json($response['body'], $response['code']);
75 | } catch (\Throwable $e) {
76 | $this->logger->logError($e->getMessage());
77 | $response['body']['message'] = $e->getMessage();
78 | wp_send_json($response['body'], self::HTTP_UNPROCESSABLE_ENTITY);
79 | }
80 | }
81 |
82 | private function handleGetStatus(object $transaction, string $orderId, string $buyOrder, string $token): array
83 | {
84 | if ($transaction->product == Transaction::PRODUCT_WEBPAY_ONECLICK) {
85 | return $this->handleOneclickStatus($orderId, $buyOrder, $transaction->buy_order);
86 | }
87 |
88 | return $this->handleWebpayStatus($orderId, $token, $transaction->token);
89 | }
90 |
91 | private function handleOneclickStatus(
92 | string $orderId,
93 | string $requestBuyOrder,
94 | string $transactionBuyOrder
95 | ): array {
96 | if ($transactionBuyOrder !== $requestBuyOrder) {
97 | return [
98 | 'body' => [
99 | 'message' => self::BUY_ORDER_MISMATCH_ERROR_MESSAGE
100 | ],
101 | 'code' => self::HTTP_UNPROCESSABLE_ENTITY
102 | ];
103 | }
104 |
105 | $statusResponse = $this->getStatusForOneclickTransaction($orderId, $transactionBuyOrder);
106 |
107 | return [
108 | 'body' => TbkResponseUtil::getOneclickStatusFormattedResponse($statusResponse),
109 | 'code' => self::HTTP_OK
110 | ];
111 | }
112 |
113 | private function handleWebpayStatus(
114 | string $orderId,
115 | string $requestToken,
116 | string $transactionToken
117 | ): array {
118 | if ($transactionToken !== $requestToken) {
119 | return [
120 | 'body' => [
121 | 'message' => self::TOKEN_MISMATCH_ERROR_MESSAGE
122 | ],
123 | 'code' => self::HTTP_UNPROCESSABLE_ENTITY
124 | ];
125 | }
126 |
127 | $statusResponse = $this->getStatusForWebpayTransaction($orderId, $transactionToken);
128 |
129 | return [
130 | 'body' => TbkResponseUtil::getWebpayStatusFormattedResponse($statusResponse),
131 | 'code' => self::HTTP_OK
132 | ];
133 | }
134 |
135 | private function getStatusForWebpayTransaction(string $orderId, string $token)
136 | {
137 | $webpayTransbankSDK = TbkFactory::createWebpayplusTransbankSdk();
138 | return $webpayTransbankSDK->status($orderId, $token);
139 | }
140 |
141 | private function getStatusForOneclickTransaction(string $orderId, string $buyOrder)
142 | {
143 | $oneclickTransbankSDK = TbkFactory::createOneclickTransbankSdk();
144 | return $oneclickTransbankSDK->status($orderId, $buyOrder);
145 | }
146 |
147 | private function getSecureInputValue(string $varName): string
148 | {
149 | $tmpValue = filter_input(INPUT_POST, $varName, FILTER_DEFAULT);
150 | return htmlspecialchars($tmpValue, ENT_QUOTES, 'UTF-8');
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/plugin/css/font-awesome/svg-with-js.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com
3 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
4 | */
5 | .svg-inline--fa,svg:not(:root).svg-inline--fa{overflow:visible}.svg-inline--fa{display:inline-block;font-size:inherit;height:1em;vertical-align:-.125em}.svg-inline--fa.fa-lg{vertical-align:-.225em}.svg-inline--fa.fa-w-1{width:.0625em}.svg-inline--fa.fa-w-2{width:.125em}.svg-inline--fa.fa-w-3{width:.1875em}.svg-inline--fa.fa-w-4{width:.25em}.svg-inline--fa.fa-w-5{width:.3125em}.svg-inline--fa.fa-w-6{width:.375em}.svg-inline--fa.fa-w-7{width:.4375em}.svg-inline--fa.fa-w-8{width:.5em}.svg-inline--fa.fa-w-9{width:.5625em}.svg-inline--fa.fa-w-10{width:.625em}.svg-inline--fa.fa-w-11{width:.6875em}.svg-inline--fa.fa-w-12{width:.75em}.svg-inline--fa.fa-w-13{width:.8125em}.svg-inline--fa.fa-w-14{width:.875em}.svg-inline--fa.fa-w-15{width:.9375em}.svg-inline--fa.fa-w-16{width:1em}.svg-inline--fa.fa-w-17{width:1.0625em}.svg-inline--fa.fa-w-18{width:1.125em}.svg-inline--fa.fa-w-19{width:1.1875em}.svg-inline--fa.fa-w-20{width:1.25em}.svg-inline--fa.fa-pull-left{margin-right:.3em;width:auto}.svg-inline--fa.fa-pull-right{margin-left:.3em;width:auto}.svg-inline--fa.fa-border{height:1.5em}.svg-inline--fa.fa-li{width:2em}.svg-inline--fa.fa-fw{width:1.25em}.fa-layers svg.svg-inline--fa{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.fa-layers{display:inline-block;height:1em;position:relative;text-align:center;vertical-align:-.125em;width:1em}.fa-layers svg.svg-inline--fa{-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter,.fa-layers-text{display:inline-block;position:absolute;text-align:center}.fa-layers-text{left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);-webkit-transform-origin:center center;transform-origin:center center}.fa-layers-counter{background-color:#ff253a;border-radius:1em;-webkit-box-sizing:border-box;box-sizing:border-box;color:#fff;height:1.5em;line-height:1;max-width:5em;min-width:1.5em;overflow:hidden;padding:.25em;right:0;text-overflow:ellipsis;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-bottom-right{bottom:0;right:0;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom right;transform-origin:bottom right}.fa-layers-bottom-left{bottom:0;left:0;right:auto;top:auto;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:bottom left;transform-origin:bottom left}.fa-layers-top-right{right:0;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top right;transform-origin:top right}.fa-layers-top-left{left:0;right:auto;top:0;-webkit-transform:scale(.25);transform:scale(.25);-webkit-transform-origin:top left;transform-origin:top left}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;position:relative;width:2.5em}.fa-stack-1x,.fa-stack-2x{bottom:0;left:0;margin:auto;position:absolute;right:0;top:0}.svg-inline--fa.fa-stack-1x{height:1em;width:1.25em}.svg-inline--fa.fa-stack-2x{height:2em;width:2.5em}.fa-inverse{color:#fff}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.svg-inline--fa .fa-primary{fill:var(--fa-primary-color,currentColor);opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa .fa-secondary{fill:var(--fa-secondary-color,currentColor)}.svg-inline--fa .fa-secondary,.svg-inline--fa.fa-swap-opacity .fa-primary{opacity:.4;opacity:var(--fa-secondary-opacity,.4)}.svg-inline--fa.fa-swap-opacity .fa-secondary{opacity:1;opacity:var(--fa-primary-opacity,1)}.svg-inline--fa mask .fa-primary,.svg-inline--fa mask .fa-secondary{fill:#000}.fad.fa-inverse{color:#fff}
--------------------------------------------------------------------------------
/plugin/shared/Helpers/PluginLogger.php:
--------------------------------------------------------------------------------
1 | config = $config;
29 |
30 | $logFilePath = $this->getLogFilePath();
31 | $this->initializeLogger($logFilePath);
32 | }
33 |
34 | private function initializeLogger(string $logFilePath)
35 | {
36 | $ecommerceTz = new DateTimeZone(wc_timezone_string());
37 | $dateFormat = "Y-m-d H:i:s P";
38 | $output = "%datetime% > %level_name% > %message% %context% %extra%\n";
39 | $formatter = new LineFormatter($output, $dateFormat);
40 |
41 | $stream = new RotatingFileHandler(
42 | $logFilePath,
43 | 100,
44 | Logger::DEBUG
45 | );
46 | $stream->setFormatter($formatter);
47 |
48 | $this->logger = new Logger('transbank');
49 | $this->logger->setTimezone($ecommerceTz);
50 | $this->logger->pushHandler($stream);
51 | }
52 |
53 | private function getLogFilePath(): string
54 | {
55 | $logFileName = $this->getLogFileNameFromCache();
56 |
57 | if (!$logFileName) {
58 | $logFileName = $this->getLogFileName();
59 | $expireTime = strtotime('tomorrow') - time();
60 | $this->saveLogFileNameInCache($logFileName, $expireTime);
61 | }
62 |
63 | $logDir = $this->getLogDir();
64 | return $logDir . $logFileName;
65 | }
66 |
67 | public function getLogger()
68 | {
69 | return $this->logger;
70 | }
71 |
72 | public function getConfig()
73 | {
74 | return $this->config;
75 | }
76 |
77 | public function logDebug($msg)
78 | {
79 | $this->logger->debug($msg);
80 | }
81 |
82 | public function logInfo($msg)
83 | {
84 | $this->logger->info($msg);
85 | }
86 |
87 | public function logError($msg)
88 | {
89 | $this->logger->error($msg);
90 | }
91 |
92 | public function getInfo()
93 | {
94 | $files = glob($this->config->getLogDir() . '/*.log');
95 | if (!$files) {
96 | return [
97 | 'dir' => $this->config->getLogDir(),
98 | 'length' => 0,
99 | 'logs' => [],
100 | 'last' => ''
101 | ];
102 | }
103 | $files = array_combine($files, array_map('filemtime', $files));
104 | arsort($files);
105 |
106 | $logs = [];
107 | foreach ($files as $key => $value) {
108 | $logs[] = [
109 | "filename" => basename($key),
110 | "modified" => $value
111 | ];
112 | }
113 |
114 | return [
115 | 'dir' => $this->config->getLogDir(),
116 | 'last' => key($files),
117 | 'logs' => $logs,
118 | 'length' => count($logs)
119 | ];
120 | }
121 |
122 | public function getLogDetail($filename, $replaceNewline = false)
123 | {
124 | if ($filename == '') {
125 | return [];
126 | }
127 | $fle = $this->config->getLogDir() . '/' . $filename;
128 | $content = file_get_contents($fle);
129 | if ($replaceNewline && $content !== false) {
130 | $content = str_replace("\n", '#@#', $content);
131 | }
132 | return [
133 | 'filename' => $fle,
134 | 'content' => $content,
135 | 'size' => $this->formatBytes($fle),
136 | 'lines' => count(file($fle)),
137 | ];
138 | }
139 |
140 | private function formatBytes($path)
141 | {
142 | $bytes = sprintf('%u', filesize($path));
143 | if ($bytes > 0) {
144 | $unit = intval(log($bytes, 1024));
145 | $units = ['B', 'KB', 'MB', 'GB'];
146 | if (array_key_exists($unit, $units) === true) {
147 | return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]);
148 | }
149 | }
150 | return $bytes;
151 | }
152 |
153 | private function getLogDir(): string
154 | {
155 | $logDir = $this->config->getLogDir();
156 | return trailingslashit($logDir);
157 | }
158 |
159 | private function getLogFileName(): string
160 | {
161 | $uniqueId = uniqid('', true);
162 | return 'log_transbank_' . $uniqueId . '.log';
163 | }
164 |
165 | private function getLogFileNameFromCache()
166 | {
167 | return get_transient(self::CACHE_LOG_NAME);
168 | }
169 |
170 | private function saveLogFileNameInCache(string $logFileName, int $expireTime)
171 | {
172 | set_transient(self::CACHE_LOG_NAME, $logFileName, $expireTime);
173 | }
174 |
175 | private static function fileExistsInFolder($fileName, $folderPath)
176 | {
177 | $filesInFolder = array_filter(scandir($folderPath), function ($file) use ($folderPath) {
178 | return is_file($folderPath . '/' . $file);
179 | });
180 |
181 | return in_array($fileName, array_values($filesInFolder));
182 | }
183 |
184 | public static function checkCanDownloadLogFile()
185 | {
186 | if (!is_user_logged_in()) {
187 | wp_send_json_error(['error' => 'Debes iniciar sesión para poder descargar']);
188 | }
189 |
190 | if (!current_user_can('manage_options')) {
191 | wp_send_json_error(['error' => 'No tienes permisos para descargar']);
192 | }
193 |
194 | $baseUploadDir = wp_upload_dir();
195 | $tbkLogsFolder = '/transbank_webpay_plus_rest/logs/';
196 | $logName = sanitize_text_field($_POST['file']);
197 | $folderPath = $baseUploadDir['basedir'] . $tbkLogsFolder;
198 | $fileExists = self::fileExistsInFolder($logName, $folderPath);
199 |
200 | if (!$fileExists) {
201 | wp_send_json_error(['error' => 'No existe el archivo solicitado']);
202 | }
203 |
204 | wp_send_json_success(['downloadUrl' => $baseUploadDir['baseurl'] . $tbkLogsFolder . $logName]);
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/plugin/src/Helpers/WebpayTransactionsTable.php:
--------------------------------------------------------------------------------
1 | 'transbank_transaction',
22 | 'plural' => 'transbank_transactions',
23 | 'ajax' => false,
24 | ]);
25 | }
26 |
27 | public function get_columns()
28 | {
29 | return [
30 | 'order_id' => __('Nº de orden'),
31 | 'amount' => __('Monto'),
32 | 'product' => __('Producto'),
33 | 'status' => __('Estado'),
34 | 'token' => __('Token'),
35 | 'buy_order' => __('Orden de compra'),
36 | 'environment' => __('Ambiente'),
37 | 'transaction_date' => __('Fecha'),
38 | 'last_refund_type' => __('Transacción anulada'),
39 | 'detail_error' => __('Observaciones'),
40 | ];
41 | }
42 |
43 | public function get_sortable_columns()
44 | {
45 | return [
46 | 'amount' => ['amount', false],
47 | 'order_id' => ['order_id', false],
48 | 'product' => ['product', false],
49 | 'status' => ['status', false],
50 | 'environment' => ['environment', false],
51 | 'transaction_date' => ['transaction_date', false],
52 | ];
53 | }
54 |
55 | /**
56 | * Prepare the table with different parameters, pagination, columns and table elements.
57 | */
58 | public function prepare_items()
59 | {
60 | global $wpdb;
61 | $orderByColumns = $this->get_sortable_columns();
62 | $orderby = isset($_GET['orderby']) && array_key_exists($_GET['orderby'], $orderByColumns)
63 | ? esc_sql($_GET['orderby'])
64 | : 'order_id';
65 |
66 | $order = isset($_GET['order']) && in_array(strtoupper($_GET['order']), ['ASC', 'DESC'])
67 | ? esc_sql(strtoupper($_GET['order']))
68 | : 'DESC';
69 |
70 | $paged = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
71 | $paged = $paged > 0 ? $paged : 1;
72 |
73 | $perPage = 20;
74 | $offset = ($paged - 1) * $perPage;
75 |
76 | $totalItemsQuery = 'SELECT COUNT(*) FROM ' . esc_sql(Transaction::getTableName());
77 | $totalItems = $wpdb->get_var($totalItemsQuery);
78 |
79 | $totalPages = ceil($totalItems / $perPage);
80 |
81 | $itemsQuery = "SELECT * FROM " . esc_sql(Transaction::getTableName()) . "
82 | ORDER BY %i {$order}
83 | LIMIT %d, %d";
84 |
85 | $this->items = $wpdb->get_results($wpdb->prepare(
86 | $itemsQuery,
87 | [$orderby, (int) $offset, (int) $perPage]
88 | ));
89 |
90 | $this->set_pagination_args([
91 | 'total_items' => $totalItems,
92 | 'total_pages' => $totalPages,
93 | 'per_page' => $perPage,
94 | ]);
95 |
96 | $columns = $this->get_columns();
97 | $this->_column_headers = [$columns, [], $this->get_sortable_columns(), 'id'];
98 | }
99 |
100 | public function column_amount($item)
101 | {
102 | return '$' . number_format($item->amount, 0, ',', '.');
103 | }
104 |
105 | public function column_transaction_date($item)
106 | {
107 | if (!$item->transbank_response) {
108 | return '-';
109 | }
110 | $tbkResponse = json_decode($item->transbank_response);
111 |
112 | return TbkResponseUtil::transactionDateToLocalDate($tbkResponse->transactionDate);
113 | }
114 |
115 | public function column_environment($item)
116 | {
117 | if ($item->environment === Options::ENVIRONMENT_INTEGRATION) {
118 | return 'Integración';
119 | }
120 |
121 | return 'Producción';
122 | }
123 |
124 | public function column_product($item)
125 | {
126 | if ($item->product === Transaction::PRODUCT_WEBPAY_ONECLICK) {
127 | return 'Webpay Oneclick';
128 | }
129 |
130 | return 'Webpay Plus';
131 | }
132 |
133 | public function column_token($item)
134 | {
135 | if ($item->product === Transaction::PRODUCT_WEBPAY_ONECLICK) {
136 | return '-';
137 | }
138 | return '...' . substr($item->token, -5) . ' ';
157 | }
158 |
159 | public function column_status($item)
160 | {
161 | $statusDictionary = [
162 | Transaction::STATUS_PREPARED => 'Preparada',
163 | Transaction::STATUS_INITIALIZED => 'Inicializada',
164 | Transaction::STATUS_APPROVED => 'Aprobada',
165 | Transaction::STATUS_TIMEOUT => 'Timeout en formulario de pago',
166 | Transaction::STATUS_ABORTED_BY_USER => 'Abortada por el usuario',
167 | Transaction::STATUS_FAILED => 'Fallida',
168 | ];
169 |
170 | return $statusDictionary[$item->status] ?? $item->status;
171 | }
172 |
173 | public function column_order_id($item)
174 | {
175 | $userCanEditOrders = current_user_can('edit_shop_order', $item->order_id);
176 |
177 | if ($userCanEditOrders) {
178 | return '' . $item->order_id . ' ';
179 | }
180 |
181 | return $item->order_id;
182 | }
183 |
184 | public function column_last_refund_type($item)
185 | {
186 | return $item->last_refund_type ? 'Si' : 'No';
187 | }
188 |
189 | public function column_default($item, $column_name)
190 | {
191 | return $item->$column_name ?? '-';
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/plugin/css/bootstrap-switch.css:
--------------------------------------------------------------------------------
1 | /**
2 | * bootstrap-switch - Turn checkboxes and radio buttons into toggle switches.
3 | *
4 | * @version v3.3.4
5 | * @homepage https://bttstrp.github.io/bootstrap-switch
6 | * @author Mattia Larentis (http://larentis.eu)
7 | * @license Apache-2.0
8 | */
9 |
10 | .bootstrap-switch {
11 | width: 64px !important;
12 | display: inline-block;
13 | direction: ltr;
14 | cursor: pointer;
15 | border-radius: 4px;
16 | border: 1px solid;
17 | border-color: #ccc;
18 | position: relative;
19 | text-align: left;
20 | overflow: hidden;
21 | line-height: 8px;
22 | z-index: 0;
23 | -webkit-user-select: none;
24 | -moz-user-select: none;
25 | -ms-user-select: none;
26 | user-select: none;
27 | vertical-align: middle;
28 | -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
29 | -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
30 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
31 | }
32 | .bootstrap-switch .bootstrap-switch-container {
33 | display: inline-block;
34 | top: 0;
35 | border-radius: 4px;
36 | -webkit-transform: translate3d(0, 0, 0);
37 | transform: translate3d(0, 0, 0);
38 | }
39 | .bootstrap-switch .bootstrap-switch-handle-on,
40 | .bootstrap-switch .bootstrap-switch-handle-off,
41 | .bootstrap-switch .bootstrap-switch-label {
42 | -webkit-box-sizing: border-box;
43 | -moz-box-sizing: border-box;
44 | box-sizing: border-box;
45 | cursor: pointer;
46 | display: table-cell;
47 | vertical-align: middle;
48 | padding: 6px 12px;
49 | font-size: 14px;
50 | line-height: 20px;
51 | }
52 | .bootstrap-switch .bootstrap-switch-handle-on,
53 | .bootstrap-switch .bootstrap-switch-handle-off {
54 | text-align: center;
55 | z-index: 1;
56 | }
57 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary,
58 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {
59 | color: #fff;
60 | background: #3cb521;
61 | }
62 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info,
63 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info {
64 | color: #fff;
65 | background: #5bc0de;
66 | }
67 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success,
68 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success {
69 | color: #fff;
70 | background: #5cb85c;
71 | }
72 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning,
73 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning {
74 | background: #f0ad4e;
75 | color: #fff;
76 | }
77 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger,
78 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger {
79 | color: #fff;
80 | background: #d9534f;
81 | }
82 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default,
83 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default {
84 | color: #fff;
85 | background: #FFC107;
86 | }
87 | .bootstrap-switch .bootstrap-switch-label {
88 | text-align: center;
89 | margin-top: -1px;
90 | margin-bottom: -1px;
91 | z-index: 100;
92 | color: #333;
93 | background: #fff;
94 | }
95 | .bootstrap-switch span::before {
96 | content: "\200b";
97 | }
98 | .bootstrap-switch .bootstrap-switch-handle-on {
99 | border-bottom-left-radius: 3px;
100 | border-top-left-radius: 3px;
101 | }
102 | .bootstrap-switch .bootstrap-switch-handle-off {
103 | border-bottom-right-radius: 3px;
104 | border-top-right-radius: 3px;
105 | }
106 | .bootstrap-switch input[type='radio'],
107 | .bootstrap-switch input[type='checkbox'] {
108 | position: absolute !important;
109 | top: 0;
110 | left: 0;
111 | margin: 0;
112 | z-index: -1;
113 | opacity: 0;
114 | filter: alpha(opacity=0);
115 | visibility: hidden;
116 | }
117 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,
118 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,
119 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label {
120 | padding: 1px 5px;
121 | font-size: 12px;
122 | line-height: 1.5;
123 | }
124 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,
125 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,
126 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label {
127 | padding: 5px 10px;
128 | font-size: 12px;
129 | line-height: 1.5;
130 | }
131 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,
132 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,
133 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label {
134 | padding: 6px 16px;
135 | font-size: 18px;
136 | line-height: 1.3333333;
137 | }
138 | .bootstrap-switch.bootstrap-switch-disabled,
139 | .bootstrap-switch.bootstrap-switch-readonly,
140 | .bootstrap-switch.bootstrap-switch-indeterminate {
141 | cursor: default !important;
142 | }
143 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,
144 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,
145 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,
146 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,
147 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,
148 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,
149 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,
150 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label,
151 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label {
152 | opacity: 0.5;
153 | filter: alpha(opacity=50);
154 | cursor: default !important;
155 | }
156 | .bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container {
157 | -webkit-transition: margin-left 0.5s;
158 | -o-transition: margin-left 0.5s;
159 | transition: margin-left 0.5s;
160 | }
161 | .bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on {
162 | border-bottom-left-radius: 0;
163 | border-top-left-radius: 0;
164 | border-bottom-right-radius: 3px;
165 | border-top-right-radius: 3px;
166 | }
167 | .bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off {
168 | border-bottom-right-radius: 0;
169 | border-top-right-radius: 0;
170 | border-bottom-left-radius: 3px;
171 | border-top-left-radius: 3px;
172 | }
173 | .bootstrap-switch.bootstrap-switch-focused {
174 | border-color: #66afe9;
175 | outline: 0;
176 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
177 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
178 | }
179 | .bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label,
180 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label {
181 | border-bottom-right-radius: 3px;
182 | border-top-right-radius: 3px;
183 | }
184 | .bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label,
185 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label {
186 | border-bottom-left-radius: 3px;
187 | border-top-left-radius: 3px;
188 | }
189 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest)
2 | [](LICENSE)
3 | [](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/graphs/contributors)
4 | [](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/actions/workflows/release.yml)
5 |
6 | # Transbank Woocommerce Webpay Plugin
7 | Plugin oficial de Webpay para WooCommerce
8 | 
9 |
10 |
11 | ## Descripción
12 | Este plugin **oficial** de Transbank te permite integrar Webpay fácilmente en tu sitio WooCommerce. Está desarrollado en base al [SDK oficial de PHP](https://github.com/TransbankDevelopers/transbank-sdk-php)
13 |
14 | ### ¿Cómo instalar?
15 | 1. [Descarga la última versión del plugin](https://github.com/TransbankDevelopers/transbank-plugin-woocommerce-webpay-rest/releases/latest)
16 | 2. Sube el archivo zip en la sección Plugin > Subir nuevo plugin en el administrador de tu Wordpress
17 |
18 | Puedes ver las instrucciones de instalación y su documentación completa en la página de [Transbank Developers](https://www.transbankdevelopers.cl/plugin/woocommerce/)
19 |
20 | ### Paso a producción
21 | Al instalar el plugin, este vendrá configurado para funcionar en modo **integración** (en el ambiente de pruebas de Transbank).
22 | Para poder operar con dinero real (ambiente de **producción**), debes completar el proceso de validación simplificado para plugins. Revisa el paso a paso [acá](https://transbankdevelopers.cl/plugin/woocommerce/).
23 |
24 |
25 | # Desarrollo
26 | A continuación, encontrarás información necesaria para el desarrollo de este plugin.
27 |
28 | ## Requisitos
29 | * PHP 7.4 o superior
30 | * Woocommerce 7.0 o superior
31 |
32 | ## Dependencias
33 |
34 | El plugin depende de las siguientes librerías:
35 |
36 | * transbank/transbank-sdk:~4.0
37 | * monolog/monolog
38 |
39 | Para cumplir estas dependencias, debes instalar [Composer](https://getcomposer.org), e instalarlas con el comando `composer install`.
40 |
41 | ## Nota
42 | - La versión del sdk de php se encuentra en el archivo [composer.json](plugin/composer.json)
43 |
44 | ## Desarrollo
45 |
46 | Para apoyar el levantamiento rápido de un ambiente de desarrollo, hemos creado la especificación de contenedores a través de Docker Compose.
47 |
48 | Para probar el plugin, ponemos a disposición el siguiente contenedor:
49 | - [WooCommerce 9.4 con php 8.2](./docker-woocommerce-php8.2-wp6.7.1-wc2.11.0-woo9.4.2)
50 |
51 | Si necesitas subir el plugin a Woocommerce y obtienes un error por que no se puede mover el archivo a `wp-content` entonces ejecuta
52 |
53 | ```bash
54 | docker-compose run webserver chmod -Rv 767 wp-content/
55 | ```
56 |
57 | ### Actualizar versión del SDK de Transbank
58 | Para actualizar la versión del SDK de Transbank se debe editar el archivo [composer.json](plugin/composer.json) y cambiar
59 | el valor de la propiedad `"transbank/transbank-sdk"` por la versión que se desea instalar y luego ejecutar el bash `update`
60 | que esta en la carpeta `docker-woocommerce-php*` lo que actualizara la dependencia del plugin.
61 |
62 | ### Crear el instalador del plugin
63 |
64 | ./package.sh
65 |
66 | ## Generar una nueva versión
67 |
68 | Para generar una nueva versión, se debe crear un PR (con un título "Prepare release X.Y.Z" con los valores que correspondan para `X`, `Y` y `Z`). Se debe seguir el estándar semver para determinar si se incrementa el valor de `X` (si hay cambios no retrocompatibles), `Y` (para mejoras retrocompatibles) o `Z` (si sólo hubo correcciones a bugs).
69 |
70 | En ese PR deben incluirse los siguientes cambios:
71 |
72 | 1. Modificar el archivo `plugin/readme.txt` para incluir una nueva entrada (al comienzo) para `X.Y.Z` que explique en español los cambios. (bajo el título == Changelog ==)
73 | 2. Modificar el archivo `plugin/readme.txt` para incluir una nueva entrada en la sección == Upgrade Notice == con una explicación breve de porque se debe actualizar.
74 |
75 | Luego de obtener aprobación del pull request, debes mezclar a master e inmediatamente generar un release en GitHub con el tag `vX.Y.Z`. En la descripción del release debes poner lo mismo que agregaste al changelog.
76 | Con eso Travis CI generará automáticamente una nueva versión del plugin y actualizará el Release de Github con el zip del plugin, además de crear el release en el SVN de Wordpress.org.
77 |
78 | ## Estándares generales
79 |
80 | - Para los commits nos basamos en las siguientes normas: https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits👀
81 | - Todas las mezclas a master se hacen mediante Pull Request ⬇️
82 | - Usamos inglés para los mensajes de commit 💬
83 | - Se pueden usar tokens como WIP en el subject de un commit separando el token con ':', por ejemplo -> 'WIP: this is a useful commit message'
84 | - Para los nombres de ramas también usamos inglés
85 | - Se asume que una rama de feature no mezclada, es un feature no terminado ⚠️
86 | - El nombre de las ramas va en minúscula 🔤
87 | - El nombre de la rama se separa con '-' y las ramas comienzan con alguno de los short lead tokens definidos a continuación, por ejemplo -> 'feat/tokens-configuration' 🌿
88 |
89 | ### **Short lead tokens**
90 |
91 | `WIP` = En progreso
92 |
93 | `feat` = Nuevos features
94 |
95 | `fix` = Corrección de un bug
96 |
97 | `docs` = Cambios solo de documentación
98 |
99 | `style` = Cambios que no afectan el significado del código (espaciado, formateo de código, comillas faltantes, etc)
100 |
101 | `refactor` = Un cambio en el código que no arregla un bug ni agrega una funcionalidad
102 |
103 | `perf` = Cambio que mejora el rendimiento
104 |
105 | `test` = Agregar test faltantes o los corrige
106 |
107 | `chore` = Cambios en el build o herramientas auxiliares y librerías
108 |
109 |
110 | ## Reglas
111 |
112 | 1️⃣ - Si no se añaden test en el pull request, se debe añadir un video o gif mostrando el cambio realizado y demostrando que la rama no rompe nada.
113 |
114 | 2️⃣ - El pr debe tener 2 o mas aprobaciones para hacer el merge
115 |
116 | 3️⃣ - si un commit revierte un commit anterior deberá comenzar con "revert:" seguido con texto del commit anterior
117 |
118 | ## Pull Request
119 |
120 | ### Asunto ✉️
121 |
122 | - Debe comenzar con el short lead token definido para la rama, seguido de ':' y una breve descripción del cambio
123 | - Usar imperativos en tiempo presente: "change" no "changed" ni "changes"
124 | - No usar mayúscula en el inicio
125 | - No usar punto . al final
126 |
127 | ### Descripción 📃
128 |
129 | Igual que en el asunto, usar imperativo y en tiempo presente. Debe incluir una mayor explicación de lo que se hizo en el pull request. Si no se añaden test en el pull request, se debe añadir un video o gif mostrando el cambio realizado y demostrando que la rama no rompe nada.
130 |
--------------------------------------------------------------------------------
/plugin/src/Controllers/OneclickInscriptionResponseController.php:
--------------------------------------------------------------------------------
1 | logger = TbkFactory::createLogger();
33 | $this->gatewayId = $gatewayId;
34 | $this->oneclickTransbankSdk = TbkFactory::createOneclickTransbankSdk();
35 | }
36 |
37 | private function getWcOrder($orderId) {
38 | if ($orderId == null){
39 | return null;
40 | }
41 | return new \WC_Order($orderId);
42 | }
43 |
44 | private function savePaymentToken($inscription, $finishInscriptionResponse){
45 | $token = new WC_Payment_Token_Oneclick();
46 | $token->set_token($finishInscriptionResponse->getTbkUser()); // Token comes from payment processor
47 | $token->set_gateway_id($this->gatewayId);
48 | $token->set_last4(substr($finishInscriptionResponse->getCardNumber(), -4));
49 | $token->set_email($inscription->email);
50 | $token->set_username($inscription->username);
51 | $token->set_card_type($finishInscriptionResponse->getCardType());
52 | $token->set_user_id($inscription->user_id);
53 | $token->set_environment($inscription->environment);
54 | // Save the new token to the database
55 | $token->save();
56 | return $token;
57 | }
58 |
59 | /**
60 | * @throws \Transbank\Plugin\Exceptions\TokenNotFoundOnDatabaseException
61 | */
62 | public function response()
63 | {
64 | $order = null;
65 | try {
66 | $resp = $this->oneclickTransbankSdk->processTbkReturnAndFinishInscription($_SERVER, $_GET, $_POST);
67 | $inscription = $resp['inscription'];
68 | $finishInscriptionResponse = $resp['finishInscriptionResponse'];
69 | $order = $this->getWcOrder($inscription->order_id);
70 | $from = $inscription->from;
71 | do_action('wc_transbank_oneclick_inscription_finished', [
72 | 'order' => $order->get_data(),
73 | 'from' => $from
74 | ]);
75 |
76 | // Todo: guardar la información del usuario al momento de crear la inscripción y luego obtenerla en base al token,
77 | // por si se pierde la sesión
78 | $userInfo = wp_get_current_user();
79 | if (!$userInfo) {
80 | $this->logger->logError('You were logged out');
81 | }
82 | $message = 'Tarjeta inscrita satisfactoriamente. Aún no se realiza ningún cobro. Ahora puedes realizar el pago.';
83 | BlocksHelper::addLegacyNotices(__($message, 'transbank_wc_plugin'), 'success');
84 | $this->logger->logInfo('[ONECLICK] Inscripción aprobada');
85 | $token = $this->savePaymentToken($inscription, $finishInscriptionResponse);
86 | if ($order) {
87 | $order->add_order_note('Tarjeta inscrita satisfactoriamente');
88 | }
89 |
90 | Inscription::update($inscription->id, [
91 | 'token_id' => $token->get_id(),
92 | ]);
93 |
94 | // Set this token as the users new default token
95 | WC_Payment_Tokens::set_users_default(get_current_user_id(), $token->get_id());
96 |
97 | do_action('wc_transbank_oneclick_inscription_approved', [
98 | 'transbankInscriptionResponse' => $finishInscriptionResponse,
99 | 'transbankToken' => $token,
100 | 'from' =>$from
101 | ]);
102 | $this->logger->logInfo('Inscription finished successfully for user #'.$inscription->user_id);
103 | $this->redirectUser($from, BlocksHelper::ONECLICK_SUCCESSFULL_INSCRIPTION);
104 |
105 | } catch (TimeoutInscriptionOneclickException $e) {
106 | BlocksHelper::addLegacyNotices($e->getMessage(), 'error');
107 | $params = ['transbank_status' => BlocksHelper::ONECLICK_TIMEOUT];
108 | $redirectUrl = add_query_arg($params, wc_get_checkout_url());
109 | wp_redirect($redirectUrl);
110 | } catch (WithoutTokenInscriptionOneclickException $e) {
111 | $params = ['transbank_status' => BlocksHelper::ONECLICK_WITHOUT_TOKEN];
112 | BlocksHelper::addLegacyNotices($e->getMessage(), 'error');
113 | $redirectUrl = add_query_arg($params, wc_get_checkout_url());
114 | wp_safe_redirect($redirectUrl);
115 | } catch (GetInscriptionOneclickException $e) {
116 | BlocksHelper::addLegacyNotices($e->getMessage(), 'error');
117 | throw $e;
118 | } catch (UserCancelInscriptionOneclickException $e) {
119 | BlocksHelper::addLegacyNotices($e->getMessage(), 'warning');
120 | $inscription = $e->getInscription();
121 | if ($inscription != null) {
122 | $order = $this->getWcOrder($inscription->order_id);
123 | }
124 | if ($order != null) {
125 | $order->add_order_note('El usuario canceló la inscripción en el formulario de pago');
126 | $params = ['transbank_cancelled_order' => 1,
127 | 'transbank_status' => BlocksHelper::ONECLICK_USER_CANCELED];
128 | $redirectUrl = add_query_arg($params, wc_get_checkout_url());
129 | wp_safe_redirect($redirectUrl);
130 | }
131 | $this->redirectUser($inscription->from, BlocksHelper::ONECLICK_USER_CANCELED);
132 | }catch (InvalidStatusInscriptionOneclickException $e) {
133 | $inscription = $e->getInscription();
134 | $this->redirectUser($inscription->from, BlocksHelper::ONECLICK_INVALID_STATUS);
135 | } catch (FinishInscriptionOneclickException $e) {
136 | BlocksHelper::addLegacyNotices($e->getMessage(), 'error');
137 | $inscription = $e->getInscription();
138 | $this->redirectUser($inscription->from, BlocksHelper::ONECLICK_FINISH_ERROR);
139 | } catch (RejectedInscriptionOneclickException $e) {
140 | BlocksHelper::addLegacyNotices($e->getMessage(), 'error');
141 | $inscription = $e->getInscription();
142 | $this->redirectUser($inscription->from, BlocksHelper::ONECLICK_REJECTED_INSCRIPTION);
143 | } catch (Exception $e) {
144 | throw $e;
145 | }
146 | }
147 |
148 |
149 | /**
150 | * @param $from
151 | */
152 | public function redirectUser($from, $errorCode = null)
153 | {
154 | $redirectUrl = null;
155 | if ($from === 'checkout') {
156 | $checkoutPageId = wc_get_page_id('checkout');
157 | $redirectUrl = $checkoutPageId ? get_permalink($checkoutPageId) : null;
158 | }
159 | if ($from === 'my_account') {
160 | $redirectUrl = get_permalink(get_option('woocommerce_myaccount_page_id')).'/'.get_option(
161 | 'woocommerce_myaccount_payment_methods_endpoint',
162 | 'payment-methods'
163 | );
164 | }
165 | if ($redirectUrl) {
166 | if (isset($errorCode)) {
167 | $params = ['transbank_status' => $errorCode];
168 | $redirectUrl = add_query_arg($params, $redirectUrl);
169 | }
170 | wp_redirect($redirectUrl);
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------