Created
August 3, 2019 06:08
-
-
Save merlox/62764e14366ad4700c9c928fb77ffe42 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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