Antes de comenzar, necesitas crear una aplicación en PayPal Developer para obtener un Client ID y un Secret que usarás en la integración.
Accede a PayPal Developer.
Inicia sesión con tu cuenta de PayPal.
En el Dashboard, ve a Apps & Credentials.
Selecciona Sandbox (para pruebas) o Live (para producción). En nuestro caso seleccionaremos Sambox pues solo queremos realizar pruebas y evitar que Paypal nos facture por estas.
Haz clic en Create Acount y proporciona y crea una cuenta cuenta para nuestras pruebas.
Configura la cuenta. Escoja Personal y su pais en pais/región.
Clicka sobre la cuenta recien creada
Copie el e-mail y el password que le proporciona Paypal para usuario de pruebas.
A continuación vuelva a la opción de menú App & Credentials.
Ya dentro de la opción de menu, pulse Create App y rellana los campos del formulario. En typo escoja la primera opción.
A continuación se muestra la aplicación recién creada. Debe copiar el Client ID que nos servira para configurar nuestro botón de Paypal.
En tu archivo HTML, debes incluir el SDK de PayPal para poder utilizar sus funciones. Este script permite cargar el botón de PayPal en tu sitio web. Para este ejemplo utilizaremos un carrito de compras desarrollado previamente. Sustituya CLIENT_ID, por el CLIENT_ID copiado anteriormente. También debes incluir un elemento html donde quieres que aparezca el botón de Paypal, como se muestra en el ejemplo:
<div class="container-md mx-auto" id="paypal-button-container"></div>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Carrito de Compras</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<!-- Pagos con Paypal-->
<script
src="https://www.paypal.com/sdk/js?client-id=<CLIENT_ID>¤cy=USD"></script>
<style>
.product,
.cart-item {
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 10px;
margin: 10px 0;
}
.product img,
.cart-item img {
max-width: 100%;
height: auto;
}
.img-150 {
width: 150px;
align-items: center;
}
#paypal-button-container {
width: 450px;
/* Ajusta el ancho del contenedor */
height: 50px;
/* Ajusta la altura del contenedor */
/* Añadir cualquier otro estilo necesario */
}
#tarjeta {
width: 400px;
/* Ajusta el ancho del contenedor */
}
</style>
</head>
<body>
<div class="container">
<h1 class="my-4">Lista de Productos</h1>
<div id="product-list" class="row"></div>
<h2 class="my-4">Carrito de Compras</h2>
<div id="cart"></div>
<h3>Total: <span id="total">0.00</span>€</h3>
<br>
<div class="mx-auto mb-4 p-4 border" id="tarjeta">
<h6>Tarjeta : 4032034262504429</h6>
<h6>Caducidad : 09/2029</h6>
<h6>CVC: 048</h6>
</div>
</div>
<!-- Contenedor para el botón de pagos con Paypal -->
<div class="container-md mx-auto" id="paypal-button-container"></div>
<!-- Incluir el archivo JavaScript externo -->
<script src="script.js"></script>
<!-- Código para manejar los pagos con Paypal -->
<script src="paypal-integration.js"></script>
</body>
</html>
client-id=YOUR_CLIENT_ID
: Reemplaza YOUR_CLIENT_ID
con el ID de cliente que obtuviste en el paso anterior.currency=USD
: Puedes especificar la moneda que deseas usar para las transacciones.Si desea seguir el ejemplo situado al principio de este tutoríal, deberá crearse el siguiente Script que crea un carrito de compras de ejemplo para poder tener algo sobre lo que facturar. Este paso es opcional.
// Lista de productos disponibles
const products = [
{
id: 1,
nombre: "CAMPO BURGO RESERVA 2018",
descripcion: "Tradición y calidad son las señas de identidad de Bodegas Isidro Milagro. Disfruta de su Campo Burgo Reserva 2018, un rioja de perfil clásico, con un tanino noble, maduro y redondo, aterciopelado, con volumen en boca y un perfecto equilibrio entre la fruta madura y la barrica.",
precio: 10.5,
graduacion: 13.5,
imagen: "https://res.cloudinary.com/dkrew530b/image/upload/v1719863077/fo7xxbtviptvh1x7uwme.webp",
},
{
id: 2,
nombre: "CUNE GRAN RESERVA 2017",
descripcion: "Cune Gran Reserva 2017 es un tinto que reúne toda la complejidad que ha dado fama mundial a Rioja y ofrece un estilo actual de entender los grandes reservas. CVNE, una marca centenaria que es también una de las más conocidas de Rioja, te ofrece ahora su 'top' de la gama. Un Gran Reserva con el que la firma demuestra que las grandes bodegas logran elaborar grandes vinos en añadas difíciles.",
precio: 12.0,
graduacion: 14.0,
imagen: "https://res.cloudinary.com/dkrew530b/image/upload/v1719863376/kaznug3n7aihmi6oozu2.webp",
},
{
id: 3,
nombre: "CUNE SEMIDULCE",
descripcion: "Un blanco suave y fresco producto de la sobremaduración. Cune Semidulce conserva toda la frescura de los blancos jóvenes secos, y la elegancia y suavidad de los tradicionales vinos dulces de Rioja.",
precio: 5.2,
graduacion: 12.28,
imagen: "https://res.cloudinary.com/dkrew530b/image/upload/v1719863787/av09rgd6gkjspixdkemy.webp",
},
{
id: 4,
nombre: "CARRAMONTE CRIANZA 2021",
descripcion: "Bodegas Viyuela se consolida como una apuesta importante y un referente en la Ribera del Duero. Como prueba, en 2019 fue reconocida por Mundus Vini como la mejor bodega de esta denominación. Ahora nos presenta Carramonte Crianza 2021. Un tinto exclusivo para Vinoselección que ya presentamos con la añada 2020. La calidad de esta cosecha 2021, calificada como Excelente en la D.O., ha hecho que no esperemos más para repetir experiencia. Disfruta ahora de este magnífico tempranillo diseñado en el término burgalés de Boada de Roa, en el corazón de la denominación. Es intenso, carnoso, de suaves taninos, tacto sedoso y final fresco.",
precio: 15.0,
graduacion: 14.5,
imagen: "https://res.cloudinary.com/dkrew530b/image/upload/v1719864181/nixctxnj25jmfoubofld.webp",
},
];
// Carrito inicial vacío
let cart = [];
// Referencias a elementos del DOM
const productList = document.getElementById("product-list");
const cartList = document.getElementById("cart");
const totalElement = document.getElementById("total");
// Cargar el carrito desde LocalStorage al iniciar
loadCart();
displayCart();
// Función para guardar el carrito en LocalStorage
function saveCart() {
localStorage.setItem('cart', JSON.stringify(cart));
}
// Función para cargar el carrito desde LocalStorage
function loadCart() {
const savedCart = localStorage.getItem('cart');
if (savedCart) {
try {
cart = JSON.parse(savedCart);
} catch (error) {
console.error('Error al parsear el carrito desde LocalStorage:', error);
cart = []; // Inicializa el carrito como vacío en caso de error
}
}
}
// Función para mostrar los productos en la página
function displayProducts() {
products.forEach((product) => {
const productElement = document.createElement("div");
productElement.classList.add("col-md-3", "mb-4");
productElement.innerHTML = `
<div class="card h-100">
<img src="${product.imagen}" class="card-img-top" alt="${product.nombre}" style="width: 200px;">
<div class="card-body">
<h5 class="card-title">${product.nombre}</h5>
<p class="card-text">Precio: ${product.precio.toFixed(2)}€</p>
<button class="btn btn-primary" onclick="addToCart(${product.id})">Agregar al carrito</button>
</div>
</div>
`;
productList.appendChild(productElement);
});
}
// Función para añadir un producto al carrito
function addToCart(productId) {
const product = products.find((p) => p.id === productId);
if (!product) {
console.error("Producto no encontrado");
return;
}
// Verifica si el producto ya está en el carrito
const existingProduct = cart.find((p) => p.id === productId);
if (existingProduct) {
// Si el producto ya está en el carrito, incrementa la cantidad
existingProduct.cantidad++;
} else {
// Si el producto no está en el carrito, añádelo
cart.push({
id: product.id,
imagen: product.imagen,
nombre: product.nombre,
precio: product.precio,
cantidad: 1,
});
}
saveCart();
displayCart();
}
// Función para eliminar o reducir la cantidad de un producto en el carrito
function removeFromCart(index) {
if (index >= 0 && index < cart.length) {
if (cart[index].cantidad > 1) {
// Si la cantidad es mayor que 1, reduce la cantidad
cart[index].cantidad--;
} else {
// Si la cantidad es 1, elimina el producto del carrito
cart.splice(index, 1);
}
displayCart();
} else {
console.error("Índice fuera de rango");
}
saveCart();
}
// Función para mostrar el carrito en la página
function displayCart() {
cartList.innerHTML = "";
cart.forEach((item, index) => {
const cartItem = document.createElement("div");
cartItem.classList.add("d-flex", "align-items-center", "mb-3", "p-2", "border", "rounded");
cartItem.innerHTML = `
<img src="${item.imagen}" class="img-150" alt="${item.nombre}" style="width: 100px; height: auto; margin-right: 15px;">
<div class="flex-grow-1">
<h5 class="mb-1">${item.nombre}</h5>
<p class="mb-1">Precio: ${item.precio.toFixed(2)}€</p>
<p class="mb-1">Cantidad: ${item.cantidad}</p>
<p class="mb-1">Total: ${(item.precio * item.cantidad).toFixed(2)}€</p>
</div>
<div>
<button class="btn btn-success btn-sm me-2" onclick="increaseQuantity(${index})">Añadir</button>
<button class="btn btn-danger btn-sm" onclick="removeFromCart(${index})">Eliminar</button>
</div>
`;
cartList.appendChild(cartItem);
});
calculateTotal(); // Calcula el total después de actualizar el carrito
}
// Función para incrementar la cantidad de un producto en el carrito
function increaseQuantity(index) {
if (index >= 0 && index < cart.length) {
cart[index].cantidad++;
displayCart(); // Actualiza la vista del carrito después de incrementar la cantidad
} else {
console.error("Índice fuera de rango");
}
}
// Función para calcular y mostrar el total del carrito
function calculateTotal() {
const total = cart.reduce((sum, item) => sum + item.precio * item.cantidad, 0);
totalElement.textContent = total.toFixed(2) + '€';
}
// Mostrar productos al cargar la página
displayProducts();
Para mantener tu código organizado, coloca el código de integración de PayPal en un archivo JavaScript separado.
Crea un archivo llamado paypal-integration.js
en el mismo directorio que tu archivo HTML.
Escribe el siguiente código en paypal-integration.js
:
// Obtener el total de la venta y lo formateamos con dos decimales
let totalNode = document.querySelector('#total');
let total1 = parseFloat(totalNode.innerText.trim()); // Convierte el texto a número decimal
total1 = total1.toFixed(2); // Formatea el número a dos decimales
paypal.Buttons({
// Configura la creación del pedido
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
description: 'Descripción del artículo o servicio',
amount: {
currency_code: 'USD', // Moneda de la transacción
value: total1 // Usa el valor formateado con dos decimales como importe de la transacción
}
}]
});
},
// Maneja la aprobación del pago
onApprove: function(data, actions) {
return actions.order.capture().then(function(details) {
alert('Pago realizado con éxito por ' + details.payer.name.given_name + ' ' + details.payer.name.surname);
// Aquí puedes redirigir al usuario o realizar otras acciones necesarias
// Por ejmplo llamar a una API
});
},
// Maneja la cancelación del pago
onCancel: function(data) {
alert('Pago cancelado.');
},
// Maneja los errores durante la transacción
onError: function(err) {
console.error('Ocurrió un error durante la transacción:', err);
}
}).render('#paypal-button-container'); // Renderiza el botón en el contenedor especificado
En el archivo paypal-integration.js
, hemos configurado el botón de PayPal para que:
Antes de lanzar tu integración en producción, es fundamental probarla en un entorno seguro utilizando las cuentas Sandbox de PayPal:
Una vez que hayas completado las pruebas en el entorno Sandbox y todo funcione correctamente, puedes pasar a producción:
client-id
en tu archivo HTML al Client ID de producción.Siguiendo este tutorial, habrás integrado PayPal en tu sitio web utilizando JavaScript de manera segura y eficiente. Mantener el código de PayPal en un archivo JavaScript separado ayuda a mantener tu proyecto organizado y facilita el mantenimiento y la escalabilidad en el futuro.