3 Operaciones Webpay - DarkGhostHunter/TransbankApi GitHub Wiki
Tabla de Contenido
- Introducción
- Webpay Plus
- Webpay Oneclick
La mayoría de las transacciones de Webpay envían al usuario hacia la plataforma de Transbank para pagar, y cuando el usuario vuelve a tu sitio, tu Servidor saca el resultado de la transacción a Transbank y muestra el resultado.
La redirección hacia a Transbank debe ser realizada a través del método HTTP POST, y enviando el token como token_ws (o TBK_TOKEN para el caso de Webpay Oneclick) como parte del cuerpo de la petición.
¿Cómo actúa la redirección? Simplemente tu aplicación mostrará una página vacía con una redirección vía Javascript hacia Transbank.
Créeme, no hay otra manera más eficiente y fácil de redirigir al usuario. De hecho, te recomendamos usar el archivo html/plusRedirect.php y html/oneclickRedirect.php en tu aplicación para redirigir al usuario, entregando el resultado como $result.
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Conectando con Webpay...</title>
</head>
<body>
<form id="redirect" action="<?php echo $result->url ?>" method="POST">
<input type="hidden" name="<?php echo $result->getTokenName() ?>" value="<?php echo htmlspecialchars($result->token, ENT_HTML5) ?>">
</form>
<script>
// Redirige al usuario inmediatamente a Webpay
document.getElementById('redirect').submit();
</script>
</body>
</html>Lo único que hace este archivo es redirigir al usuario a Webpay lo más rápido posible
Por supuesto tienes total libertad para crear otro archivo u otro mecanismo para redirigirlo: AJAX, señales de humo, algo más expresivo para el usuario, lo que quieras. No importa qué, considera que al final debe ser el método HTTP POST con el token que ha enviado Webpay para que pueda pagar.
Cuando tu aplicación redirige a Webpay Plus para mostrar el recibo, Webpay Plus redireccionará al usuario de vuelta a tu aplicación junto al token como token_ws.
Como sólo se puede recuperar la transacción por su token una única vez, no es posible recuperar la transacción por su token una segunda vez, aún cuando recibas el mismo token nuevamente.
Lo recomendable es hacer énfasis en la página de retorno returnUrl, y dejar en un botón o un contador la redirección final a Webpay Plus, ya que la página para mostrar el voucher final tiene un mayor tiempo de vida, y dejar el finalUrl para el home de tu comercio.
Si la transacción fue rechazada, el urlRedirection se transformará en tu finalUrl. Lo recomendable es decirle al usuario que la transacción falló y permitir que vuelva al flujo de pago desde el principio.
Hay algunas aplicaciones que, después de guardar la transacción internamente, redirigen al usuario al voucher de Webpay Plus inmediatamente. Aunque no es lo recomendado, dado que no ve a la aplicación confirmando el pago, también es una técnica válida si puedes recuperar la información de la transacción y la compra desde tus sistemas.
La actual implementación de Webpay Plus y Oneclick usan WS-SOAP, que para algunos es un asco. No necesariamente.
En peras y manzanas, WS-SOAP funciona como si el método (o función) del servidor "maestro" estuviese presente en otro servidor. Los servicios son compartidos en un XML llamado "WSDL", y cuando se ocupan, se envían peticiones y reciben respuestas en XML. Sin importar qué lenguaje de programación o protocolo que se use (HTTP, SMTP, FTP, etc..), el resultado será el mismo. Esto permite al servidor padre dos cosas: añadir más servicios vía el WSDL sin tanto dolor, y no exponer las funciones de los servicios.
Ahora, esto suena muy overkill para los servicios web de Transbank, considerando el actual de la Internet con la masificación de HTTPs. Considerando que REST es más fácil de entender e implementar, aunque algo menos seguro, habrá que soportar WS-SOAP hasta que la versión REST llegue a Transbank.
Mientras tanto, WS-SOAP seguirá vivo debajo de la mesa en instituciones financieras (bancos, por ejemplo) donde el ancho de banda o la escalabilidad no es un problema, la seguridad debe ser parte del protocolo y transacciones requieren múltiples llamadas entre ambos servidores. Si tu empresa se avalúa sobre el millón de dólares, WS-SOAP es obligatorio, especialmente end-to-end.
La parte "Plus" de Webpay es la clásica transacción donde el cliente es redirigido a Webpay para pagar, y luego vuelve a tu aplicación, que consigue y muestra el resultado de la transacción.
Si te preguntas porqué se llama "Plus", es porque existe una versión que no-Plus: los usuarios tiene que ir a webpay.cl, seleccionar el establecimiento, y pagar desde allí, sin notificación al comercio. The more you know.
Las Transacciones Normales son, bueno, las típicas que podrás encontrar en la mayoría del comercio online , donde el usuario decide cómo pagar.
Los métodos de pago admitidos por el comercio deben ser configurados en Transbank.cl con anterioridad.
Para crear una transacción normal, simplemente llama a Webpay y crea la transacción.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use DarkGhostHunter\TransbankApi\Webpay;
use App;
$webpay = Transbank::make('integration')->webpay();
$transaction = $webpay->makeNormal([
'sessionId' => 'client-session-id-88',
'buyOrder' => 'myOrder#16548',
'amount' => 1000,
]);
$result = $transaction->getResult();
echo $result->token; // "a923asod3u1nd0g3ktnvk3..."
echo $result->url; // "http://webpay3g.transbank.cl/..." Luego tendrás que redirigir al usuario a Webpay mediante una operación POST.
Una vez Webpay redirige al usuario de vuelta a tu sitio después de pagar, deberás obtener el resultado de la transacción con el token token_ws que entrega Webpay a tu aplicación a través de otro método HTTP POST. Para ello, puedes usar getAndConfirm(), que devolverá el resultado de la transacción desde Webpay usando ese token, y la confirmará automáticamente.
Finalmente, podrás verificar si la transacción fue exitosa o no con isSuccess().
<?php
// Consige la transacción desde Webpay
$transaction = $webpay->getAndConfirm(
App::request()->input('token_ws')
);
// Si la transacción fue un éxito, avisamos
if ($transaction->isSuccess()) {
return "La transacción $transaction->buyOrder fue realizada exitosamente.";
}
// Como la transacción no fue un éxito, devolveremos el error
return "Ocurrió un error realizando la transacción: \n" .
$transaction->getErrorForHumans();Después manejar el resultado de la transacción, y ojalá guardar la transacción, deberás redirigir al usuario de nuevo a Webpay para mostrar el resultado el recibo si es que todo fue un éxito.
Por defecto, getAndConfirm() obtiene primero el resultado de la transacción, y luego la confirma automáticamente si se recibió. Esta es la opción recomendada para procesar las transacciones.
Si necesitas realizar estos procesos por separado, por ejemplo para verificar si un producto de la transacción tiene stock antes de sellar la transacción, o verificar que pagó como se le indicó, puedes usar por separado los métodos para obtener el resultado y confirmar.
<?php
use App\Database\BuyOrder;
$webpay = Transbank::make('integration')->webpay();
$token = App::request()->input('token_ws');
$transaction = $webpay->getTransaction($token);
// La transacción fue completada con éxito, sólo falta la confirmación final
if ($transaction->isSuccess()) {
// Aquí la aplicación verifica que el producto tiene stock en su última instancia.
// Si no hay stock, no podremos entregar los productos, por lo que no deberíamos
// confirmar la transacción en Webpay, lo que evita problemas con el cliente.
$hasStock= BuyOrder::select('buyOrder', '=', $transaction->buyOrder)->productsHaveStock();
// Si los productos están en stock, confirmamos y entregamos el resultado
if ($hasStock && $webpay->acknowledgeTransaction($token)) {
return "La transacción $transaction->buyOrder fue un éxito y tus productos van en camino.";
}
// Como no hay productos, devolveremos el error
return "Los productos de tu orden $transaction->buyOrder ya no tienen stock. ¡Debes comprar rápido!";
}
// La transacción no fue completada, así que mostraremos el error
return "Hubo un error procesando la transacción $transaction->buyOrder";La confirmación final debe realizarse dentro de 30 segundos después que Webpay autoriza la transacción, sino será reversada automáticamente. ¡Más vale que tu lógica entre obtener el resultado y la confirmación no sea lenta!
Webpay Plus Mall es lo mismo que Plus, pero la diferencia es que una transacción puede contener varios items, y éstas pertenecer a diferentes "Tiendas hijas".
Este modo de operación es muy útil si tienes diferentes tiendas web, como por ejemplo una verdulería, una pescadería, una tienda de accesorios para teléfonos, y quieres operar bajo un sólo sitio web o servidor web. Tal como si fuese un Mall.
También sirve si tienes otras empresas o socios. Ellos pueden enviar la transacción a tu sitio junto con el Código de Comercio que los identifica, y tu Servidor realiza todo el proceso con Webpay. Es algo más complicado pero se puede ;).
Para crear una Transacción Mall Normal, creála considerando que debes ingresar cada "orden" como si fuese un item dentro de la llave llamada items, además del código de cada tienda a la que pertenece cada uno de éstos.
También puedes añadirlos posteriormente usando addItem().
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App;
$webpay = Transbank::make('integration')->webpay();
$transaction = $webpay->makeMallNormal([
'sessionId' => 'alpha-session-1',
'finalURL' => 'https://app.com/electronics/transaction/result/',
'items' => [
[
'commerceCode' => 597044444402,
'amount' => 4990,
'buyOrder' => 20000001,
],
[
'commerceCode' => 597044444403,
'amount' => 4990,
'buyOrder' => 30000001,
]
// ...
]
]);
// Vamos a ingresar otro item a nuestra transacción Mall Normal
$transaction->addItem([
'commerceCode' => 597044444403,
'amount' => 4990,
'buyOrder' => 30000001,
]);
$result = $transaction->getResult();
echo $result->token; // "a923asod3u1nd0g3ktnvk3..."
echo $result->url; // "http://webpay3g.transbank.cl/..." Si vas a crear una transacción con sólo un ítem, sólo indica la item dentro de un simple array.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$transaction = $webpay->makeMallNormal([
'sessionId' => 'alpha-session-1',
'finalURL' => 'https://app.com/electronics/transaction/result/',
'items' => [
'storeCode' => 597044444402,
'amount' => 4990,
'buyOrder' => '02-order#001',
]
]);
$result = $transaction->getResult();
echo $result->token; // "a923asod3u1nd0g3ktnvk3..."
echo $result->url; // "http://webpay3g.transbank.cl/..." Si estás probando bajo Integración, puedes ocupar los Códigos de Comercio Mall
597044444402y597044444403.
La confirmación de una Transacción Mall Normal es similar a una Transacción Normal, a excepción de dos diferencias: el método a llamar es confirmMallTransaction(), y cada item tendrá su estado de éxito o fallo en un array llamado items.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$transaction = $webpay->confirmMallTransaction(
App::request()->input('token_ws')
);
// Veremos si la transacción y todas sus órdenes fueron un éxito
if ($transaction->isSuccess()) {
return 'La transacción completa ha sido un éxito';
}
// Como la transacción no fue un éxito, mostraremos las órdenes que fallaron
echo 'Las siguientes órdenes fallaron en realizarse:';
// Empujaremos cada Item fallido en cada línea
foreach ($result->failedItems() as $key => $item) {
echo "Orden $item->buyOrder falló por la siguiente razón: " . $result->getOrderErrorForHumans($key) . "\n";
}Para obtener el resultado y confirmar por separado, puedes usar los mismos métodos para una Transacción Normal.
Si quieres realizar alguna especie de lógica por cada item devuelta desde Webpay, puedes ocupar los siguientes métodos para ahorrarte tiempo:
<?php
// Retorna todos los items
$items = $transaction->getItems();
// Retorna todos los items exitosas
$successfulItems = $transaction->getSuccesfulItems();
// Retorna todos los items fallidas
$failedItems= $transaction->getFailedItems();
// Retorna el monto total de la transacción
$total = $transaction->getTotal();
// Retorna el monto total de las transacciones exitosas
$total = $transaction->getSuccessfulTotal();
// Retorna el monto total de las transacciones fallidas
$total = $transaction->getFailedTotal();
// Retorna el código de error del item
$itemErrorCode = $failedItems[0]->getErrorCode();
// Retorna el texto de error del item
$itemErrorCode = $failedItems[0]->getErrorForHumans();La captura diferida se refiere a capturar el pago después de autorizada la transacción.
Puesto de otra forma, sólo si enviaste a tu cliente a pagar con tarjeta de crédito, podrás "reservar" el cupo en la tarjeta del cliente hasta por 7 días, período en donde podrás "cobrar" (capturar) antes que el cupo se libere de vuelta al tarjetahabiente.
Esto es muy útil cuando no puedes confirmar el stock del producto en tiempo real sino en algunos días, o necesitas tener certeza que tus clientes van pagar un producto cuando se haga disponible dentro de esos 7 días, como en las pre-ordenes o pseudo-subastas.
Tienes dos opciones. La primera es crear una transacción Webpay Plus Normal o Webpay Plus Mall Normal, y la segunda es usar makeDefer() o makeMallDefer() (o sus verisiones create)
La ventaja de usar los métodos makeDefer() y makeMallDefer() es que te saber qué tipo transacción estás escribiendo, y te evitas confundirte con las transacciones normales si algún día decides desactivar la captura diferida.
<?
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$defer = $webpay->createDefer([
'sessionId' => 'client-session-id-88',
'buyOrder' => 'app-order#001',
'amount' => 19990,
]);
$result = $transaction->getResult();
echo $result->token; // "a923asod3u1nd0g3ktnvk3..."
echo $result->url; // "http://webpay3g.transbank.cl/..." Si estás usando el ambiente de integración, estarás obligado a usar estos métodos para crear la prueba con transacciones diferidas, ya que las credenciales están ligadas al tipo de transacción a probar.
Cuando vuelva el usuario después de "pagar", debes guardar el resultado de la transacción si fue exitosa, porque para la captura necesitaremos:
- El código de autorización
authorizationCode, - el identificador de la transacción
buyOrder, - el monto a capturar
amount, - y para el caso Mall, el código de comercio
commerceCodeque hizo la transacción.
Una vez tengas la transacción hecha, podrás confirmarla como cualquiera y decirle al usuario que está todo listo. En su cuenta sólo verá que la transacción fue hecha como "no facturada" o "pendiente".
Todo lo anterior lo haremos en este ejemplo:
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App\Database\Order;
$webpay = Transbank::make('integration')->webpay();
// Consige la transacción desde Webpay
$transaction = $webpay->confirmTransaction(
App::request()->input('token_ws')
);
// Si la transacción fue un éxito, avisamos
if ($transaction->isSuccess()) {
// Antes de avisar, guarda los datos de la transacción.
Order::insert($transaction);
return "La transacción $transaction->buyOrder fue realizada exitosamente, el cupo será capturado si nuestro producto está disponible.";
}
// Como la transacción no fue un éxito, devolveremos el error
return "Ocurrió un error realizando la transacción: \n" .
$transaction->getErrorForHumans();Ahora que ya creamos la transacción, dentro de estos 7 días deberemos capturarla, sino el monto se liberará al cliente y tendremos que pedirle nuevamente que haga transacción.
Para ello, podemos llamar a makeCapture() y makeMallCapture() de Webpay, que creará la captura con los datos de la transacción a capturar. O si quieres, puedes pedir el resultado directamente con create.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$transaction = $webpay->makeCapture([
'authorizationCode' => 1213,
'buyOrder' => 'app-order#001',
'captureAmount' => 19990,
]);
$transaction = $webpay->makeMallCapture([
'authorizationCode' => 1213,
'buyOrder' => 'app-order#001',
'captureAmount' => 1000,
'commerceOrder' => 597044444402
]);Una vez tengas lista la Transacción Diferida lista, deberás enviarla a Webpay, que retornará éxito o error.
<?php
use App\Database\CompletedOrder;
$result = $transaction->getResult();
if ($result->isSuccess()) {
// Guardaremos la transacción en nuestra base de datos para confirmarla
// o anularla después usando los datos que ha entregado Webpay.
CompletedOrder::insert([
'buyOrder' => $transaction->buyOrder,
'token' => $result->token,
'authorizationCode' => $result->authorizationCode,
'authorizationDate' => $result->authorizationDate,
'captureAmount' => $result->captureAmount
]);
}
// Como el resultado no fue exitoso, indicaremos el error
echo $result->getErrorCode(); // 311
echo $result->getErrorForHumans(); // "Monto a capturar excede el monto autorizado"
// Reportaremos el error en nuestra aplicación por si acaso.
return App::reportError($transaction);En el ejemplo, estamos guardando los datos para anularla después, algo muy útil si tu cliente tiene los mecanismos para anular la compra, o tienes un panel en tu aplicación para hacerlo.
Sólo las transacciones Webpay hechas con tarjetas de crédito se pueden anular. Para poder realizarlo, hay ciertas condiciones:
- La anulación parcial sólo puede ser ante una Venta Normal (VN), de esas que se pagan sin cuotas, sino deberá ser por el total de la transacción.
- Puedes hacerlo antes del día número 30 después de realizada, o "reservada" para el caso de una Transacción Diferida que fue "capturada" exitosamente.
- Sólo se puede realizar una vez.
¿Y qué hace Webpay en caso de anulación? Muy simple: cuando Webpay abona el dinero en la cuenta del comercio, resta el monto de las transacciones anuladas, hasta que el monto de todas las anulaciones sea cero o hasta que el abono sea cero. Si quedan más anulaciones, se seguirán restando en de los siguientes abonos. Mientras tanto, el cliente verá la transacción reembolsada en su cupo, evitando que tu negocio deba hacer algo al respecto.
Por si acaso, las transacciones hechas con tarjeta de débito (como Redcompra) no se pueden anular una vez completadas porque el traspaso de dinero es inmediato. Si necesitas hacerlo, tendrás que usar tus propios canales o lógica para reembolsar el monto al cliente.
Aquí también necesitarás el código de autorización para anular la captura diferida o transacción, que es diferente al entregado en transacción original, junto al monto autorizado, que es la cifra que fue cargada al tarjetahabiente.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$nullify = $webpay->makeNullify([
'authorizationCode' => 136178,
'authorizedAmount' => 19990,
'buyOrder' => 'app-order#001',
'nullifyAmount' => 10000, // El producto resultó ser $10.000 más barato
]); Cuando tengamos lista la anulación, la enviaremos a Webpay que nos devolverá el resultado, que puede tener éxito o error.
<?php
$result = $nullify->getResult();
if ($result->isSuccess()) {
// Si la anulación fue total, le diremos que la orden fue anulada totalmente
if ($result->isTotal()) {
return "La Orden $nullify->buyOrder ha sido anulada totalmente.";
}
// Si no, le diremos que fue parcial y le entregaremos el nuevo monto
return "Hemos restado $ $nullify->nullifiedAmount a la Orden $nullify->buyOrder. \n
El nuevo monto es de $result->balance.";
}
// Como el resultado no fue exitoso, devolveremos el error
echo $result->getErrorCode(); // 311
echo $result->getErrorForHumans(); // "Monto a capturar excede el monto autorizado"Oneclick es básicamente Plus pero mucho más simple dado que después que el usuario se inscribe, puedes cargar el monto directamente al cliente en vez de redireccionarlo a Webpay cada vez que vaya a pagar.
Para que Oneclick funcione bien, debes guardar el estado de la inscripción en tu aplicación. Al saber si tu usuario está inscrito en Oneclick, podrás invitarlo a registrarse, o derechamente cargar el monto en su tarjeta usando sus datos de inscripción.
Oneclick es muy útil cuando tus clientes realizan compras recurrentes, ya que ahorra tiempo y lógica en tu servidor. Por ejemplo, cuando compran varios artículos a la semana. Incluso, podrías ligar el registro a tu aplicación a Oneclick si este es crítico para el funcionamiento.
Oneclick Normal se refiere a todas las transacciones que se realizan usando sólo un comercio. Si necesitas hacer varias transacciones de comercios diferentes, deberías usar Webpay Oneclick Mall.
Para crear una inscripción, puedes seguir los mismos pasos que para una transacción Webpay Plus, sin embargo, debemos usar el método makeRegistration(). Porque no tenemos mucho que hacer, usaremos createRegistration() que retornará la petición de registro inmediatamente.
Al final, tendremos que redirigir al usuario con una petición HTTP POST hacia la URL que Webpay ha enviado de vuelta, incluyendo el token que identifica el proceso de inscripción.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$result = $webpay->createRegistration([
'username' => 'Commerce_username',
'email' => '[email protected]',
'responseUrl' => 'https://app.com/oneclick/result'
]);Al cliente le será cargado $1 para ver si la tarjeta está habilitada.
Al registrarse, recibirás un username y un tbkUser. En teoría esto debería funcionar, sin embargo, el usuario podría registrar otra tarjeta.
Si tu comercio quiere aceptar más de una tarjeta por usuario, tendrás que añadir una variación al username para poder diferenciar la tarjeta que ha registrado. Por ejemplo, así:
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$result = $webpay->createRegistration([
'username' => 'username.1',
'email' => '[email protected]',
'responseUrl' => 'https://app.com/oneclick/result'
]);Y luego en tu aplicación, adquirir o separar el username del index de la tarjeta a usar (que en este caso sería 1.), y configurar alguna opción para que el usuario pueda pagar con uno de ambos username a su nombre.
Si necesitas algo más agraciado, puedes usar Onepay.
Una vez la inscripción en Webpay finalize, el cliente será enviado de vuelta a tu aplicación web junto con el token.
Como verás, deberás identificar a tu usuario en tu aplicación para asociarlo al tbkUser, el identificador del usuario en Webpay, que es necesario para autorizar cargos en la tarjeta de crédito. En este ejemplo, usaremos una cookie.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App\Http\Request;
use App\Cookie\UserCookie;
use App\Database\Database;
$webpay = Transbank::make('integration')->webpay();
$registration = $webpay->confirmRegistration(Request::get('token'));
if ($registration->isSuccess()) {
// Recuperaremos nuestro ID de Usuario desde la Cookie
$userId = UserCookie::getUserId();
// Ahora asociaremos el tbkUser y username al ID de Usuario de nuestra
// aplicación a través de nuestra base de datos.
Database::table('users')
->where('userId', '=', $userId)
->update([
'tbkUser' => $registration->tbkUser, // 250af988-360b-48d9-b15b-0ec62f5a9e33
'username' => $registration->username,
]);
// Como el registro fue exitoso, le diremos que ahora puede pagar con Oneclick
return 'Tu registro en Webpay Oneclick fue exitoso, ya puedes realizar pagos más fácilmente.';
}
// Como el resultado no fue exitoso, devolveremos el error
echo $registration->getErrorCode();
echo $registration->getErrorForHumans();Aquí puedes obtener el resultado del registro tantas veces como quieras, no como en Webpay Plus donde el resultado de una transacción es única.
Quizás tu usuario quiere volver a pagar de forma manual, o bien has eliminado el usuario de tus sistemas y necesitas también eliminarlo de Oneclick. No importa la razón, tu aplicación puede eliminar el registro Oneclick en Webpay de forma bastante simple con sólo el tbkUser y username.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App\Cookie\UserCookie;
use App\Database\Database;
$webpay = Transbank::make('integration')->webpay();
// Identificaremos el Usuario en nuestra aplicación y obtendremos la
// información pertinente
$userId = UserCookie::getUserId();
$userData = Database::table('users')
->where('userId', '=', $userId)
->select(['tbkUser', 'username']);
$unregister = $webpay->makeUnregistration([
'tbkUser' => $userData->tbkUser,
'username' => $userData->username,
]);
$result = $unregister->getResult();
if ($result->isSuccess()) {
return 'Has sido eliminado de Oneclick de forma exitosa.';
}
// Como el resultado no fue exitoso, devolveremos el error
return 'No te pudimos eliminar de Oneclick, por favor inténtalo nuevamente.'; Para autorizar un pago, o cargar un monto al tarjetahabiente, sólo necesitas su tbkUser y su username.
El buyOrder
A pesar que suena simple, hay una consideración especial con el buyOrder. Webpay pide que esta variable sea un timestamp más un número correlativo de 3 dígitos. Algo así como 2018 06 01 12 30 23 123, pero sin los espacios.
Para simplificarte la vida, el SDK generará el timestamp automáticamente justo antes de enviarlo a Transbank, y sólo deberás suministrar los últimos 3 dígitos. Si deseas usar otro timestamp, deberás usar los 17 dígitos que necesita Webpay, o el SDK devolverá un error. Y si no ingresas nada, el sistema añadirá automáticamente 000.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App\Cookie\UserCookie;
use App\Database\Database;
use \Datetime;
$webpay = Transbank::make('integration')->webpay();
$userId = UserCookie::getUserId();
$userData = Database::table('users')
->where('userId', '=', $userId)
->select(['tbkUser', 'username']);
$charge = $webpay->makeCharge([
'amount' => 9990,
'buyOrder' => 'app-order#001',
'tbkUser' => $userData->tbkUser,
'username' => $userData->username,
]);
echo $charge->buyOrder; // '123'. Sólo se transformará en '20190101123000123' cuando lo envíes a Transbank
// Cambiamos de opinión, usaremos nuestro propio timestamp
$charge->buyOrder = date('YmdHis') . 123;Una vez estemos listos, enviaremos el cargo a Webpay que retornará el resultado.
<?php
$result = $charge->getResult();
if ($result->isSuccess()) {
// Guardaremos la transacción en nuestros sistemas
Database::table('transbank_transactions')->insert([
'transactionId' => $result->transactionId,
'data' => $result
]);
return "La transacción $result->transactionId por $ $charge->amount ha sido un éxito. \n" .
"El cargo fue realizado a tu tarjeta $result->creditCardType que termina en $result->last4CardDigits.";
}
// Como el resultado no fue exitoso, devolveremos el error
echo $result->getErrorCode(); // -97
echo $result->getErrorForHumans(); // "Límites Oneclick, máximo monto diario de pago excedido." Es posible anular un cargo dentro del mismo día contable, esto quiere decir antes de las siguientes 14:00 horas del día hábil - no feriados ni fines de semana. La anulación es siempre por el total del monto.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
$reverse = $webpay->makeReverseCharge([
'buyOrder' => 20202020120001001,
]);
$result = $reverse->getResult();
if ($result->isSuccess()) {
return "Hemos anulado tu transacción $reverse->buyOrder.";
}
// Como el resultado no fue exitoso, devolveremos el error
return "La anulación de la orden $reverse->buyOrder falló. ¿Estás seguro estás a tiempo?";Oneclick Mall es básicamente Oneclick pero para tiendas Mall, y con algunas ligeras diferencias:
- Debes suministrar el código del comercio Mall en los atributos de cada item.
- Se puede anular un item, o bien, reembolsar la transacción entera con sus cargos.
Mejor que veamos cada operación.
El Transbank SDK oficial no soporta aún transacciones Webpay Oneclick Mall (y probablemente nunca pasará). De todas maneras, este wrapper las incluye, sin embargo, tendrás un lindo
ServiceSdkUnavailableExceptioncuando quieras enviarlas a Transbank.
Simplemente crea una Inscripción normal. El proceso, métodos y atributos son los mismos.
Simplemente confirma una Inscripción normal. El proceso, métodos y atributos son los mismos.
Aquí la transacción difiere de un cargo normal. Como es una transacción Mall, podemos ingresar múltiples cargos (u órdenes) en una única transacción, provenientes de diferentes tiendas.
Para tu conveniencia, cada item genera el timestamp del buyOrder automáticamente, sólo debes suministrar los últimos 3 dígitos, o bien los 17 dígitos completos.
Perdónanos por la muralla de código, pero es necesario mostrarlo considerando que la autorización del cargo devuelve inmediatamente el resultado, algo que tendrás que informar al usuario de alguna forma una vez terminado el proceso.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
use App\Cookie\UserCookie;
use App\Database\Database;
$webpay = Transbank::make('integration')->webpay();
// Identifiquemos el Usuario en nuestro sistema
$userId = UserCookie::getUserId();
$userData = Database::table('users')
->where('userId', '=', $userId)
->select(['tbkUser', 'username']);
// Creamos la transacción con dos órdenes
$charge = $webpay->makeMallCharge([
'buyOrder' => 'app-order#001',
'tbkUser' => $userData->tbkUser,
'username' => $userData->username,
'storesInput' => [
[
'storeCode' => 597044444402,
'amount' => 4990,
'buyOrder' => '02-order#001',
'sessionId' => 'alpha-session-id-1',
'sharesNumber' => 3 // Pagará en 3 cuotas
],
[
'storeCode' => 597044444403,
'amount' => 4990,
'buyOrder' => '03-order#001',
'sessionId' => 'beta-session-id-2',
'sharesNumber' => null // Por defecto, pagará sin cuotas
],
],
]);
// Vamos a añadir una tercer item porque es nuestro usuario favorito
$charge->addOrder([
'storeCode' => 5000000003,
'amount' => 4990,
'buyOrder' => 30000002,
'sessionId' => 'beta-session-id-2',
'sharesNumber' => null // Por defecto, pagará sin cuotas
]);Cuando tu transacción esté lista con todas sus órdenes, envíala a Webpay y recibirás el resultado de cada una. Podrás mostrar el resultado de cada una de ellas, o mostrar cuáles tuvieron error.
<?php
// Entregamos la transacción y recibimos el resultado
$result = $charge->getResult();
// Si la transacción fue un éxito, avisaremos
if ($result->isSuccess()) {
return "El pago # $result->transactionId fue un éxito";
}
// Como la transacción no fue un éxito, mostraremos las órdenes que fallaron
echo 'Las siguientes órdenes fallaron en realizarse:';
foreach ($result->failedOrders() as $order) {
echo "Orden $order->buyOrder falló por la siguiente razón: " . $order->getErrorForHumans() . "\n";
}Revertir un Cargo Mall quiere decir anular toda la transacción, incluyendo todas las órdenes hechas a través de ésta.
Usa esto cuando tu comercio y lo enviado por Transbank no cuadre (diferentes montos, todas las transacciones debían ser exitosas, etc.), o bien, cuando la respuesta de Webpay no puedas recibirla a tiempo para mostrarle el resultado al cliente, etc.
Sólo puede ser llamado después de los siguientes 30 segundos creada la transacción, así que es buena idea que tengas algún contador u otro sistema en paralelo que se encargue de realizarlo, si así lo deseas.
La anulación se debe llamar a la transacción generada por el Comercio "padre", aquél que sostiene todas los otros comercios Mall.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
// Creamos la transacción
$reverse = $webpay->makeReverseMall([
'buyOrder' => 'app-order#001',
]);Cuando tengamos la operación preparada la enviaremos a Webpay, que retornará una lista de las órdenes parte de la transacción, y el estado de cada una.
<?php
$results = $reverse->getResult();
// Si todas las transacciones fueron reversadas, avisaremos
if ($reverse->isSuccess()) {
return 'Todas las órdenes de la transacción "store-order#123" fueron anuladas completamente';
}
// Si no fue así, devolveremos cada item fallido en revertir
echo 'Las siguientes órdenes fallaron en revertirse:';
foreach ($reverse->failedOrders as $order) {
echo "Orden $order->buyOrder. \n";
}Una transacción pueden tener varias órdenes, y puedes anularlas individualmente. Sin embargo, sólo podrás anular un item a la vez.
Usa la anulación cuando, por ejemplo, no puedas entregar el producto o servicio de ese item por cualquier razón. Por supuesto, esta anulación puede ser parcial.
Como en la anulación Webpay Mall, será necesario que suministres el authorizationCode.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
// Creamos la transacción
$nullify = $webpay->makeNullifyMall([
'authorizationCode' => 'makoy123',
'commerceId' => 'store-child-1',
'buyOrder' => 20181201153000001,
'authorizedAmount' => 19990,
'nullifyAmount' => 10000 // Digamos que cobramos $ 10.000 de más.
]);Cuando termines de crear la anulación, envíala a Webpay para recibir el resultado:
<?php
$result = $nullify->getResult();
// Si el resultado fue exitoso, avisaremos
if ($result->isSuccess()) {
// Si la anulación fue total, le diremos que el item fue anulado totalmente
if ($result->isTotal()) {
return "La Orden $nullify->buyOrder ha sido anulada totalmente.";
}
// Si no, le diremos que fue parcial y le entregaremos el nuevo monto
return "Hemos restado $ $nullify->nullifiedAmount a la Orden $nullify->buyOrder \n.
El nuevo monto es de $result->balance.";
}
// Como el resultado no fue exitoso, devolveremos el error
echo $result->getErrorCode(); // 311
echo $result->getErrorForHumans(); // "Monto a capturar excede el monto autorizado"Te recomendamos guardar el item
buyOrder, el Código de Comercio MallcommerceCodey el monto anulado, porque podrás después dejar sin efecto dicha anulación.
¿Has visto Inception? Si no la has visto, te confundirá saber que puedes revertir una anulación.
Puesto de otra manera, puedes dejar sin efecto una anulación, logrando que el item sea cobrado, sólo después de los 30 segundos en que fue anulada. Para ello necesitarás el buyOrder, el código de Comercio Mall commerceId, y el monto exacto que fue anulado. Ahora ya sabes porqué te decíamos que era bueno guardar el resultado de la anulación.
<?php
namespace App;
use DarkGhostHunter\TransbankApi\Transbank;
$webpay = Transbank::make('integration')->webpay();
// Creamos la transacción
$reverse = $webpay->makeReverseNullifyMall([
'commerceId' => 'store-child-1',
'buyOrder' => '20181201153000001',
'nullifyAmount' => 10000 // ¡Esos $ 10.000 que cobramos demás estaban correctos!
]);Después de tener lista la petición para dejar sin efecto la anulación, la enviaremos a Webpay, que retornará un resultado.
<?php
$result = $reverse->getResult();
// Si la reversa fue correcta, avisaremos
if ($result->isSuccess()) {
return "La orden $reverse->buyOrder ha dejado de ser nula.";
}
// Pero sino, retornaremos que hubo un error
return "La orden $reverse->buyOrder no pudo volver a ser válida. Inténtalo nuevamente.";Simplemente elimina una Inscripción normal. El proceso, métodos y atributos son los mismos.