Skip to content

Instantly share code, notes, and snippets.

@merlox
Created August 3, 2019 06:08
Show Gist options
  • Save merlox/62764e14366ad4700c9c928fb77ffe42 to your computer and use it in GitHub Desktop.
Save merlox/62764e14366ad4700c9c928fb77ffe42 to your computer and use it in GitHub Desktop.
function payProduct(req, cb){
console.log('PayProduct, functions.js');
let dataObject = req.body.data,
direccion = dataObject.direccion,
arrayProductos = dataObject.productos,
token = dataObject.token,
idPago = 0,
customerId = null,
error = null,
precioTotalCentimos = null,
arrayProductosInterno = [];
if(!/.+@.+\./.test(direccion.email)){
return cb('#1 Error: el email es incorrecto, inténtelo de nuevo.');
}
if(!req.session.username) return cb('#2 Error, tienes que iniciar sesión para comprar.');
//Guardamos en la base de datos de usersData los productos comprados conjuntamente
db.collection('usersData').update({
'username': req.session.username
}, {
'$set': {
'compradosJuntos': arrayProductos
}
}, err => {
if(err) console.log(`#3 Error guardando los compradosJuntos al pagar la cesta del usuario ${req.session.username}`);
});
//Comprobamos que la cantidad sea correcta, que existan los productos puestos y que se cree un nuevo id de compra
db.collection('facturas').count((err, count) => {
if(err) return cb('#4 Error procesando el pago, inténtelo de nuevo.');
let index = 0;
idPago = count+1
//Comprobamos que los productos que ha puesto existan
for(let i = 0; i < arrayProductos.length; i++){
let productoPermalink = arrayProductos[i].permalink;
let productoCantidad = arrayProductos[i].cantidad;
if(arrayProductos[i].cantidad <= 0){
error = '#5 Error, la cantidad del producto: '+arrayProductos[i].nombre+' no puede ser menor o igual a 0';
}
db.collection('productos').findOne({
'permalink': productoPermalink
}, (err, result) => {
index++;
if(err) error = '#6 Error procesando el pago, por favor inténtalo de nuevo.';
if(!result) error = '#7 Este producto no existe o no está disponible: '+arrayProductos[i].nombre+', por favor cambialo.';
//Si se ha llegado al último producto sin errores, continuar
if(index >= arrayProductos.length){
if(error) return cb(error);
crearCustomer();
}
});
}
});
/**
* Comprueba si el usuario ya tiene customerId y si no, hace lo siguiente:
* 1. Crea un costumer con stripe.customers.create con su email de sessión
* 2. Si no se puede crear lanza un catch y le devuelve el error #8.5
* 3. Una vez creado se guarda en la base de datos el customerId para ese usuario en "users"
* 4. Entonces se pasa a realizarPago();
* @return { callback } Puede devolver errores en el proceso que termina el programa inmediatamente
*/
function crearCustomer(){
console.log('CrearCustomer, functions.js');
//Creamos un customer y pagamos por cada producto por separado
if(!req.session.customerId){
stripe.customers.create({
"source": token,
"description": req.session.username,
"email": req.session.username
}).then((customer) => {
//En el customer.id se guarda el id que se usa para crear charges en stripe
req.session['customerId'] = customer.id;
//Hay que guardar la sesión para actualizar el objeto de sesión puesto que en las POST request no se salva automaticamente.
req.session.save();
//Guardamos el customer id en la base de datos del usuario
db.collection('users').update({
'username': req.session.username
},{
$set: {
'customerId': customer.id
}
}, (err, result) => {
if(err) return cb('#8 Error procesando el pago, por favor inténtalo de nuevo.');
realizarPago();
});
}).catch(err => {
return cb('#8.5 No se pudo realizar el pago, inténtalo de nuevo y prueba a iniciar sesión de nuevo.');
});
}else{
//Preparamos los productos para crear los objetos y arrays necesarios para realizar el pago
prepararProductosPago(err => {
if(err) return cb(err);
realizarPago();
});
}
};
/**
* Prepara los productos ordenando la información a guardar en la base de datos y preparando
* la información de cada producto para el email factura.
* 1. Creamos un array de permalinks y buscamos en la bd de productos
* esos permalinks para obtener información sobre esos productos
* 2. Por cada producto encontrado, pasamos su precio de 11.02 -> 1102 int
* 3. Creamos un objeto producto por cada uno de esos productos con los datos principales
* 4. Establecemos el precio individual y total de todos los productos en un array de productos
* para enviar el email transaccional
* @return { callback } Callback error or null
*/
function prepararProductosPago(done){
//Buscamos cada producto para saber su precio real y lo pagamos
//Creamos un array con cada titulo para buscarlo en la bd
let arrayPermalinks = [];
for(let i = 0; i < arrayProductos.length; i++){
let permalink = arrayProductos[i].permalink;
arrayPermalinks.push(permalink);
}
//Conseguimos el precio de cada producto
db.collection('productos').find({
'permalink': {$in: arrayPermalinks}
}, {
'_id': false,
'precio': true,
'titulo': true,
'permalink': true,
'imagenes': true
}).toArray((err, results) => {
if(err) return done('#9 Hubo un error procesando los productos, por favor intentalo de nuevo.');
if(results.length <= 0) return done('#10 No se han encontrado esos productos en la base de datos, por favor inténtelo de nuevo.');
//Recorremos los productos
for(let index = 0; index < results.length; index++){
let producto = results[index],
precioCentimos = parseInt((producto.precio*100).toFixed(0)),
cantidad = null;
//Creamos el array de productos interno para meterlo en la base de datos
let objetoArrayProducto = {
'precioCentimos': precioCentimos,
'titulo': producto.titulo,
'permalink': producto.permalink,
'atributos': arrayProductos[index].atributos, //Es un array de objetos {atributoNombre: 'color', atributoValorSeleccionado: 'Rojo'}
'cantidad': null,
'estaEnviado': false,
'imagen': producto.imagenes[1] //Las imagenes están dentro de un objeto "1": "asfasf.jpg"
};
/*
arrayProductos[index] No tiene nada que ver con el arrayProductosInterno,
arrayProductos es el precio para el email y la factura.
Le calculamos el precio individual para meterlo en el email factura.
*/
//Conseguimos la cantidad comprada de ese producto
for(let f = 0; f < arrayProductos.length; f++){
if(arrayProductos[f].nombre == producto.titulo){
cantidad = arrayProductos[f].cantidad;
objetoArrayProducto.cantidad = parseInt(cantidad);
precioCentimos *= cantidad;
}
}
//Introducimos el objeto producto en el array interno de productos
arrayProductosInterno.push(objetoArrayProducto);
//Aumentamos el precio total
precioTotalCentimos += precioCentimos;
if(index + 1 >= results.length){
precioTotalCentimos = parseInt(precioTotalCentimos);
}
};
for(let o = 0; o < arrayProductos.length; o++){
//Ponemos los atributos
let textoAtributos = '';
for(let indexAtb = 0; indexAtb < arrayProductos[o].atributos.length; indexAtb++){
if(indexAtb > 0)
textoAtributos += ', '+arrayProductos[o].atributos[indexAtb].atributoSeleccionado;
else
textoAtributos += arrayProductos[o].atributos[indexAtb].atributoSeleccionado;
}
let precioOriginal; //El precio de este producto aunque esté repetido en la cesta
for(let x = 0; x < results.length; x++){
if(arrayProductos[o].permalink === results[x].permalink){
precioOriginal = results[x].precio;
break;
}
}
arrayProductos[o]['atributos'] = textoAtributos;
//En el email se muestra "Producto" - "Cantidad" - "Precio individual" - "Precio total"
arrayProductos[o]['precioUno'] = precioOriginal;
//Le calculamos el precio individual x cantidad para la factura
arrayProductos[o]['precioTotal'] = parseFloat(precioOriginal*parseInt(arrayProductos[o].cantidad)).toFixed(2);
}
done(null);
});
};
/**
* Realiza el pago de la compra del usuario con el customerId una vez estén preparados los productos
* 1. Creamos el pago propiamente dicho con stripe.charges.create
* 2. Si no hay errores pagando, insertamos la factura en la base de datos
* 3. Borramos la cesta para quitar los productos comprados
* 4. Renderizamos el email con la información necesaria
* 5. Terminamos la función y devolvemos el callback pero sigue ejecutandose el envio del email
* 5. Enviamos el email transaccional de la factura de compra para referencias futuras
*/
function realizarPago(){
console.log('RealizarPago, functions.js');
//Pagamos el total y luego guardamos la factura en la base de datos
let charge = stripe.charges.create({
"amount": parseInt(precioTotalCentimos), //Cantidad en centimos
"currency": 'eur',
"customer": req.session.customerId,
"description": 'Hola',
"metadata": {
'idPago': idPago
}
}, (err, charge) => {
if(err){
console.log(err);
return cb('#11 Tu tarjeta ha sido rechazada, por favor escribe otra vez la información de tu tarjeta e intentalo de nuevo.');
}else{
db.collection('facturas').insert({
'idPago': idPago,
'emailUsuarioConectado': req.session.username,
'nombreApellidos': direccion.nombreApellidos,
'cantidad': charge.amount,
'estaProcesado': charge.captured,
'estaPagado': charge.paid,
'estaEnviado': false,
'fecha': charge.created,
'moneda': charge.currency,
'productos': arrayProductosInterno,
'precioTotalCentimos': precioTotalCentimos,
'telefono': charge.receipt_number,
'direccion': direccion,
'terminacionTarjeta': charge.source.last4,
'customer': charge.customer,
'idCharge': charge.id,
'chargeObject': charge
}, (err, result) => {
if(err) return cb('#12 Error procesando el pago, por favor inténtalo de nuevo.');
/*
1. Renderizar el email
2. Enviar la factura por email
*/
let emailObject = {
from: '[email protected]',
to: direccion.email,
subject: 'Aqui tienes tu factura. Gracias por comprar.',
html: null
};
let renderEmailObject = {
arrayProductos: arrayProductos,
precioFinal: (precioTotalCentimos/100)
};
//Borramos la cesta en la bd y en la session
db.collection('usersData').update({
'username': req.session.username
}, {
'$set': {
'cesta': []
}
}, err => {
if(err) console.log(err);
//Borramos la cesta al terminar de pagar
delete req.session.cesta;
req.session.save();
});
//Terminamos el pago aunque el envío de email continúa solo hasta terminar de enviarse el email
cb(null);
render(path.join(__dirname, 'emails', 'factura.html'), renderEmailObject, (err, emailHTML) => {
if(err) console.log(err);
emailObject.html = emailHTML;
sendEmail(emailObject, (err, success) => {
if(err) console.log(err);
console.log(success);
});
});
});
}
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment