I am implementing a payment by card and I do everything that the process asks me:
Install the JS and the anti-fraud + the DEVICEHIDDENFIELNAME
<!-- Openpay Anti-fraud system-->
<script type="text/javascript"
src="https://js.openpay.mx/openpay.v1.min.js"></script>
<script type='text/javascript'
src="https://js.openpay.mx/openpay-data.v1.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
OpenPay.setId('mikey'); //aqui todo OK
OpenPay.setApiKey('mipk'); //aqui todo OK
OpenPay.setSandboxMode(true);
var deviceSessionId = OpenPay.deviceData.setup("payment-form", "deviceIdHiddenFieldName");
});
</script>
Add the form:
<form action="#" method="POST" id="payment-form" class="hide-element form-group need-validation" novalidate>
<input type="hidden" name="token_id" id="token_id">
<input type="hidden" name="use_card_points" id="use_card_points" value="false">
<div class="row">
<div class="margin-t col-12">
<h4><b>Aceptamos tarjetas de débito y crédito</b></h4>
</div>
<div class="col-4">
<h6>Tarjetas de crédito</h6>
<img src="assets/img/tarjeta-de-credito.png" class="img-tdc">
</div>
<div class="col-8">
<h6>Tarjetas de débito</h6>
<img src="assets/img/tarjeta-de-debito.png" class="img-tdc">
</div>
<div class="col-12"><br></div>
<div class="col-6">
<label>Nombre del titular</label><input type="text" id="nombre_tarjeta" name="nombre_tarjeta" minlength="5" maxlength="400" class="form-control" placeholder="Como aparece en la tarjeta" autocomplete="off" data-openpay-card="holder_name" pattern="^[a-zA-Z0-9 ]*$" required>
<div class="valid-feedback">Correcto.</div>
<div class="invalid-feedback">Este dato es obligatorio. Min 5, Max 50 letras. No utilizar (*%/$+-.,').</div>
</div>
<div class="col-6">
<label>Número de tarjeta</label><input type="text" id="num_tarjeta" name="num_tarjeta" maxlength="30" class="form-control" autocomplete="off" pattern="[0-9]+"data-openpay-card="card_number" required="">
<div class="valid-feedback">Correcto.</div>
<div class="invalid-feedback">Ingresa un número de cuenta correcto, sin letras y sin espacios.</div>
</div>
<div class="col-12"><br></div>
<div class="col-6">
<label>Fecha de expiración</label><br>
<input type="number" id="mes_tarjeta" name="mes_tarjeta" placeholder="Mes" max="12" step="1" class="form-control special-size rigth-marg" data-openpay-card="expiration_month" required=""><input type="text" id="anio_tarjeta" name="anio_tarjeta" maxlength="2" class="form-control special-size" placeholder="Año" data-openpay-card="expiration_year" pattern="[0-9]+" required="">
<div class="valid-feedback">Correcto.</div>
<div class="invalid-feedback">Ingresa un mes o año de vencimiento correcto, solo dos números para mes o año ej: 02/20 - 01/23 - 04/21.</div>
</div>
<div class="col-6">
<label>Código de seguridad</label><br>
<input type="text" id="cvv_tarjeta" name="cvv_tarjeta" class="form-control special-size rigth-marg" maxlength="3" placeholder="3 dígitos" autocomplete="off" data-openpay-card="cvv2" pattern="[0-9]{3}" required=""> <img src="assets/img/cvv.png" class="img-cvv rigth-marg"> <img src="assets/img/cvv-v2.png" class="img-cvv-two ">
<div class="valid-feedback">Correcto.</div>
<div class="invalid-feedback">Ingresa un CVV correcto.</div>
</div>
<div class="col-12"><br></div>
<div class="col-1"></div>
<div class="col-5">
<small><b>Transacciones realizadas vía:</b></small>
<img src="assets/img/openpay.png" class="img-opn">
</div>
<div class="col-6">
<table style="width:100%">
<tr>
<th><img src="assets/img/secure.png" class="img-secure"></th>
<th class="secure-text"><small> Tus pagos se realizan de forma segura con encriptación de 256 bits.</small></th>
</tr>
</table>
</div>
</div>
</form>
2 more Javascript functions are added for the token, as you can see SUCCESS_CALLBACK is the one who assigns the TOKEN_ID and its value in the frontend:
var success_callbak = function(response) {
var token_id = response.data.id;
$('#token_id').val(token_id);
$('#payment-form').submit();
};
var error_callbak = function(response) {
var desc = response.data.description != undefined ?
response.data.description : response.message;
alert("ERROR [" + response.status + "] " + desc);
$("#pay-button").prop("disabled", false);
};
When I make the token, everything works fine, the platform receives it without problems,
function formPay(){
var holder_name = $('#nombre_tarjeta').val();
var card_number = $('#num_tarjeta').val();
var expiration_month = $('#mes_tarjeta').val();
var expiration_year = $('#anio_tarjeta').val();
var cvv = $('#cvv_tarjeta').val();
var address = orderDelivery.direccion + " " + orderDelivery.cp;
var deviceIdHiddenFieldName = $('#deviceIdHiddenFieldName').val();
/*AQUI HAGO EL TOKEN EN JS - Se activa success_callback y al ejecutarse esa function
se asigna el token_id al INPUT OCULTO, pero a mi no me devuelve nada*/
OpenPay.token.extractFormAndCreate('payment-form', success_callbak, error_callbak);
/*
INTENTE CON ESTE TOQUEN PERSONALIZADO PERO NO ME FUNCIONO TAMPOCO
OpenPay.token.create({
"card_number":card_number,
"holder_name":holder_name,
"expiration_year":expiration_year,
"expiration_month":expiration_month,
"cvv2":cvv,
}, success_callbak, error_callbak);
*/
//AQUI OBTENGO YO EL TOKEN_ID para mandarlo por POST con AJAX
var token_id = $('#token_id').val();
var formData = new FormData();
formData.append('phone_number',orderDelivery.telefono);
formData.append('holder_name',holder_name);
formData.append('card_number',card_number);
formData.append('expiration_month',expiration_month);
formData.append('expiration_year',expiration_year);
formData.append('cvv',cvv);
formData.append('address',address);
formData.append('amount',orderDelivery.total);
formData.append('email',orderDelivery.correo);
formData.append('token_id',token_id);
formData.append('deviceIdHiddenFieldName',deviceIdHiddenFieldName);
formData.append('function',"addPay");
$.ajax({
data: formData, //send data via AJAX
url: 'controller/ctrlPago.php', //url file controller PHP
dataType:'json',
contentType: false,
processData: false,
type: 'post', //send POST data
success:function(response) { //get request
/*if(response.success){
//CODE
}
});
}
As you can see I need to collect the token_id , to POST IT to my PHP FILE and generate the charge, so I send my data without problems, but the charge fails because I can not CATCH the token_id
Here the PHP code:
$openpay = Openpay::getInstance('mikey','misk');
// Establecer la zona horaria predeterminada a usar. Disponible desde PHP 5.1
date_default_timezone_set('America/Mexico_City');
$fecha = date("m.d.y");
$customer = array(
'name' => $_POST["holder_name"],
'email' => $_POST["email"],
'phone_number' => $_POST["phone_number"],
'card_number' => $_POST["card_number"],
'expiration_month' => $_POST["expiration_month"],
'expiration_year' => $_POST["expiration_year"],
'creation_date' => $fecha,
'cvv2' => $_POST["cvv"],);
$chargeData = array(
'method' => 'card',
'source_id' => $_POST["token_id"],
'amount' => $_POST["amount"], // formato númerico con hasta dos dígitos decimales.
'description' => "Compra de comida rápida",
'device_session_id' => $_POST["deviceIdHiddenFieldName"],
'customer' => $customer
);
$charge = $openpay->charges->create($chargeData);
Cash Token:
{
"holder_name": "MArian Miranda M",
"card_number": "424242XXXXXX4242",
"expiration_month": "11",
"expiration_year": "23",
"cvv2": "XXX"
}
Respuesta
{
"id": "k9gzznpuhv8ankcktcbo",
"card": {
"card_number": "424242XXXXXX4242",
"holder_name": "MArian Miranda M",
"expiration_year": "23",
"expiration_month": "11",
"address": null,
"creation_date": null,
"brand": "visa",
"points_card": true,
"points_type": "bancomer"
}
}
I do not understand why it does NOT obtain the token_id, if it is supposed to do the token, here are my OPENPAY CODES OF THE BAD REQUEST of the CHARGE:
CALL:
{
"method": "card",
"source_id": "",
"amount": "120.00",
"description": "Compra de comida r\u00e1pida",
"device_session_id": "Jp74we8dc0ROf2FxeH1QGhT00Le8rGFv",
"customer": {
"name": "MArian Miranda M",
"email": "[email protected]",
"phone_number": "6654465654",
"card_number": "424242XXXXXX4242",
"expiration_month": "11",
"expiration_year": "23",
"creation_date": "09.12.20",
"cvv2": "XXX"
}
}
RESPONSE:
{
"http_code": 400,
"error_code": 1001,
"category": "request",
"description": "Please specify card info",
"request_id": "2773509d-f31b-4b15-a2c5-31a593c2026e"
}
As you can see souce_id is empty, I'm 100% sure it's because I didn't send the token_id , do you see something wrong when obtaining it?
*When I debug with the browser console, everything does fine, but it seems that the SUCCESS_CALLBACK doesn't assign the EL TOKEN_ID in the form back to catch it like I do.
Settings in relation to the BUTTON
I don't have it inside the form, but I get the data from the following button:
<button id="btn_pay" class="btn btn-success hide-element" type="button" onclick="formPay()">Pagar pedido</button>
Don't add it, ignore it, but that button calls the function formPay(); which, in turn, executes my token creation code, all good up to here, because if I get the token, but then I don't know what happens to it:
Actually what I was doing wrong was this:
The error is that I WANTED TO CONTINUE EXECUTING THE CODE SYNCHRONOUSLY and the response to the TOKEN was a variable called SUCCESS_CALLBACK that works RECURSIVELY, so to execute the charge I did this: