¿Cómo integrar Mercado Pago 与您的网络吗?
必要的知识
我们很努力
我们采用设置
道路的创造
创建控制器
服务创造
本周,我将提交一份与Mercado Pago 网上结帐相结合的认证“考试” (de acá en más MP,请让我通过 cansar de escribirlo)。
最后,您可以在CourseIt上集成 MP (更多返工),以获得更多体验。
我遇到了这样的问题,遇到了各种各样的问题,在市场文件中,我发现很多问题都没有解决。 (这是使用 MP avisen 沙箱的问题!)
因此,该文章的目的是与类似的角色的意图
这篇文章的主题是实践中的角色,以确保内容和内容,以解释可能的阿巴卡蒂瓦意图
必要的知识
想要了解简单的教程,需要注意以下几点:
我们很努力
- Vamos 可以在 Node 上创建API,更快捷。
- 在 API 中,您可以创建一个通用的 pago 链接,也可以通过 MP nos mande ( webhooks ) 接收 pago 的通知。
- Esas rutas van 使用控制器和服务。 En los que vamos a tener que conectarnos con la API de MP.
我们采用设置
-
首先需要安装Express-Generator,然后才能使用 Express 的通用应用程序:
$ npm install express-generator -g
-
第二步创建 Express 应用程序
$ express --view=none MercadoPagoCheckout
Con este comando lo que estamos haciendo es crear una API, que se llama MercadoPagoCheckout
-
您可以在 MercadoPagoCheckout 上查看 (que se acaba de crear) ejecutamos:
$ npm install
可以安装node_modules。
依赖于计算机,如果您想了解更多信息,请联系我们。 -
安装 axios 时,请使用MP API 请求
$ npm install axios --save
您可以进行 API 基础设置!
道路的创造
如果要安装的话,我们需要先进行项目编辑,然后再进行编辑。
Dentro de los archivos, nos vamos a encontrar con uno que se llama app.js
, que contiene lo siguiente:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
module.exports = app;
Lo que tenemos que hacer a continuación es crear las rutas.
创建 2 个规则:一般链接 MP 和其他 MP 通知 (webhook)
Vamos a eliminar algunas rutas que NO vamos a usar como:
app.use('/', indexRouter);
app.use('/users', usersRouter);
Y agregar las rutas que SI vamos a usar que son:
app.post("/payment/new", (req, res) =>
PaymentInstance.getMercadoPagoLink(req, res)
);
请使用 llamar 功能,getMercadoPagoLink()
使用 estar 和控制器,然后使用 cear más adelante。
此功能可以通过请求POST
网址来执行实际操作localhost:3000/payment/new
app.post("/webhook", (req, res) => PaymentInstance.webhook(req, res));
Esta linea lo que hace es muy 类似于 la linea anterior。
Cuando se reciba un request POST
en la url localhost:3000/webhook
se va a ejecutar la función webhook()
que está dentro delcontroller (que todavía no Creamos)
最后,导入控制器和服务,并按照以下步骤进行操作:
const PaymentController = require("./controllers/PaymentController");
//importamos el controller
const PaymentService = require("./services/PaymentService");
//importamos el service
const PaymentInstance = new PaymentController(new PaymentService());
// Permitimos que el controller pueda usar el service
Entonces, nos tentría que quedar así:
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var app = express();
const PaymentController = require("./controllers/PaymentController");
//importamos el controller
const PaymentService = require("./services/PaymentService");
//importamos el service
const PaymentInstance = new PaymentController(new PaymentService());
// Permitimos que el controller pueda usar el service
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.post("/payment/new", (req, res) =>
PaymentInstance.getMercadoPagoLink(req, res)
);
app.post("/webhook", (req, res) => PaymentInstance.webhook(req, res));
module.exports = app;
创建控制器
作为控制器,它是一个功能或与其他功能相结合的功能,允许获取有关数据基础的信息,或者我们可以使用外部 API 的数据。
首先,我们要创建一个新的文件夹,然后controllers
创建一个新的归档文件PaymentController.js
,然后再创建一个新的文件夹PaymentController
。
Dentro de esa clase vamos a crear dos funciones, una que se llame getMercadoPagoLink()
, y otra que se llame webhook()
.
class PaymentController {
constructor(paymentService) {
this.paymentService = paymentService;
}
async getMercadoPagoLink(req, res) {
}
webhook(req, res) {
}
}
module.exports = PaymentController;
La función getMercadoPagoLink()
, va a llamar al service (que estamos importando desde el constructor
) y ejecutar la función createPaymentMercadoPago()
que va a recibi información del Producto o servicio que queramos Vender, como por ejemplo:
nombre, precio, cantidad
async getMercadoPagoLink(req, res) {
const { name, price, unit, img } = req.body;
try {
const checkout = await this.paymentService.createPaymentMercadoPago(
name, // nombre del producto o servicio
price, //precio del producto o servicio
unit, //cantidad que estamos vendiendo
img // imagen de referencia del producto o servicio
);
return res.redirect(checkout.init_point);
//si es exitoso los llevamos a la url de Mercado Pago
return res.json({url: checkout.init_point})
// o si queres devolver la url al front
} catch (err) {
// si falla devolvemos un status 500
return res.status(500).json({
error: true,
msg: "Hubo un error con Mercado Pago"
});
}
}
La función tiene que ser declarada con un async
,ya que vamos a estar haciendo un await
a la función del service.
请注意,请求正文、前端信息(name
、、、、)price
。unit
img
Una vez resuelta PaymentService.createPaymentMercadoPago()
,vamos a tener la url de pago que nos da MP。
La función webhook()
, en cambio, debería verse así:
webhook(req, res) {
if (req.method === "POST") {
let body = "";
req.on("data", chunk => {
body += chunk.toString();
});
req.on("end", () => {
console.log(body, "webhook response");
res.end("ok");
});
}
return res.status(200);
}
在功能上webhook()
,请验证海洋请求的方法POST
,这是向曼达尔议员提供所需信息的必要条件。
Luego,声明变量是美洲驼,需要清楚地body
写出需要解决的医疗问题,因为需要大块的信息,所以需要使用清晰的算法(字符串)。
En síntesis, nuestro PaymentController
, debería quedar:
class PaymentController {
constructor(paymentService) {
this.paymentService = paymentService;
}
async getMercadoPagoLink(req, res) {
const { name, price, unit, img } = req.query;
try {
const checkout = await this.paymentService.createPaymentMercadoPago(
name,
price,
unit,
img
);
return res.redirect(checkout.init_point);
} catch (err) {
return res.status(500).json({
error: true,
msg: "Hubo un error con Mercado Pago"
});
}
}
webhook(req, res) {
if (req.method === "POST") {
let body = "";
req.on("data", chunk => {
body += chunk.toString();
});
req.on("end", () => {
console.log(body, "webhook response");
res.end("ok");
});
}
return res.status(200);
}
}
module.exports = PaymentController;
服务创造
该服务是一种功能或功能的结合,不允许query
在数据基础上执行,或与外部 API 连接。
最初,我们创建了services
一个新的创建对象,创建了地毯(创建了一个不存在的对象),并在新的归档中创建了一个新的归档对象PaymentService.js
,然后创建了一个新的分类对象PaymentService
。
需要保护constructor
MP 钥匙/代币。
无论如何,重要的是axios
,您可以使用 API de MP 连接器。
const axios = require("axios");
class PaymentService {
constructor() {
this.tokensMercadoPago = {
prod: {},
test: {
access_token:
"APP_USR-6317427424180639-042414-47e969706991d3a442922b0702a0da44-469485398"
// el access_token de MP
}
};
// declaramos de la siguiente manera el token
// para que sea más fácil cambiarlo dependiendo del ambiente
this.mercadoPagoUrl = "https://api.mercadopago.com/checkout";
// declaramos la url en el constructor para poder accederla a lo largo de toda la class
}
}
Dentro de esa clase,vamos a crear una sola función llamada CreatePaymentMercadoPago()
。
在该功能中,您可以使用该async
功能中的变量来调节环境。getMercadoPagoLink()
PaymentController.js
También,vamos 声明变量 llamada url
que es la dirección de MP a donde vamos a pedir la information midte el método POST
。使用constructor
公式中声明的变量。
async createPaymentMercadoPago(name, price, unit, img) {
const url = `${this.mercadoPagoUrl}/preferences?access_token=${this.tokensMercadoPago.test.access_token}`;
}
接下来,我们将继续创建骆驼createPaymentMercadoPago()
物件阵列的功能。[{}]
items
Este Array,是一个关于销售产品或服务信息的内容。
可以使用变量、、name
和unit
函数price
来getMercadoPagoLink()
实现PaymentController.js
const items = [
{
id: "1234",
// id interno (del negocio) del item
title: name,
// nombre que viene de la prop que recibe del controller
description: "Descripción del producto o servicio",
// descripción del producto
picture_url: "https://localhost:3000/static/product.png",
// url de la imágen del producto, tiene que ser una url válida
category_id: "1234",
// categoría interna del producto (del negocio)
quantity: parseInt(unit),
// cantidad que estamos vendiendo, que tiene que ser un intiger
currency_id: "ARS",
// id de la moneda, que tiene que ser en ISO 4217
unit_price: parseFloat(price)
// el precio, que por su complejidad tiene que ser tipo FLOAT
}, {
// si queremos agregar otro item, pasamos la misma información acá
}
];
Ahora,vamos 声明一个目标 llamado preferences
,que contiene las preencias de pago de nuestro array items
。
Todo esto lo estamos haciendo de acuerdo a la documentación de la API de MP que pueden encontrar acá
const preferences = {
items,
// el array de objetos, items que declaramos más arriba
external_reference: "referencia del negocio",
// referencia para identificar la preferenciaç
payer: {
// información del comprador, si estan en producción tienen que traerlos del request
//(al igual que hicimos con el precio del item)
name: "Lalo",
surname: "Landa",
email: "test_user_63274575@testuser.com",
// si estan en sandbox, aca tienen que poner el email de SU usuario de prueba si estan
//en producción, deberian completar esta información
//de la misma manera que lo hicimos con items, units, y price
phone: {
area_code: "11",
number: "22223333"
},
address: {
zip_code: "1111",
street_name: "False",
street_number: "123"
}
},
payment_methods: {
// declaramos el método de pago y sus restricciones
excluded_payment_methods: [
// aca podemos excluir metodos de pagos, tengan en cuenta que es un array de objetos
// donde el id de cada objeto es la exclusión
{
id: "amex"
// acá estamos excluyendo el uso de la tarjeta American Express
}
],
excluded_payment_types: [{ id: "atm" }],
// aca podemos excluir TIPOS de pagos, es un array de objetos
// Por ejemplo, aca estamos excluyendo pago por cajero
installments: 6,
// mayor cantidad de cuotas permitidas
default_installments: 6
// la cantidad de cuotas que van a aparecer por defecto
},
back_urls: {
// declaramos las urls de redireccionamiento
success: "https://localhost:3000/success",
// url a la que va a redireccionar si sale todo bien
pending: "https://localhost:3000.com/pending",
// url a la que va a redireccionar si decide pagar en efectivo por ejemplo
failure: "https://localhost:3000.com/error"
// url a la que va a redireccionar si falla el pago
},
notification_url: "https://localhost:3000/webhook",
// declaramos nuestra url donde recibiremos las notificaciones
// es la misma ruta que declaramos en app.js
auto_return: "approved"
// si la compra es exitosa automaticamente redirige a "success" de back_urls
};
//NOTA: TODAS las URLS que usemos tienen que ser reales,
// si prueban con localhost, va a fallar
最后,我们无法实现POST
axios:
const request = await axios.post(url, preferences, {
// hacemos el POST a la url que declaramos arriba, con las preferencias
headers: {
// y el header, que contiene content-Type
"Content-Type": "application/json"
}
});
El PaymentService.js
les debería haber quedado:
const axios = require("axios");
class PaymentService {
constructor() {
this.tokensMercadoPago = {
prod: {},
test: {
access_token:
"APP_USR-6317427424180639-042414-47e969706991d3a442922b0702a0da44-469485398"
// el access_token de MP
}
};
// declaramos de la siguiente manera el token, para que sea más fácil cambiarlo dependiendo del ambiente
this.mercadoPagoUrl = "https://api.mercadopago.com/checkout";
// declaramos la url en el constructor para poder accederla a lo largo de toda la clase
}
async createPaymentMercadoPago(name, price, unit, img) {
// recibimos las props que le mandamos desde el PaymentController
const url = `${this.mercadoPagoUrl}/preferences?access_token=${this.tokensMercadoPago.test.access_token}`;
// url a la que vamos a hacer los requests
const items = [
{
id: "1234",
// id interno (del negocio) del item
title: name,
// nombre que viene de la prop que recibe del controller
description: "Dispositivo movil de Tienda e-commerce",
// descripción del producto
picture_url: "https://courseit.com.ar/static/logo.png",
// url de la imágen del producto
category_id: "1234",
// categoría interna del producto (del negocio)
quantity: parseInt(unit),
// cantidad, que tiene que ser un intiger
currency_id: "ARS",
// id de la moneda, que tiene que ser en ISO 4217
unit_price: parseFloat(price)
// el precio, que por su complejidad tiene que ser tipo FLOAT
}
];
const preferences = {
// declaramos las preferencias de pago
items,
// el array de objetos, items que declaramos más arriba
external_reference: "referencia del negocio",
// referencia para identificar la preferencia, puede ser practicamente cualquier valor
payer: {
// información del comprador, si estan en producción tienen que //traerlos del request
//(al igual que hicimos con el precio del item)
name: "Lalo",
surname: "Landa",
email: "test_user_63274575@testuser.com",
// si estan en sandbox, aca tienen que poner el email de SU usuario de prueba
phone: {
area_code: "11",
number: "22223333"
},
address: {
zip_code: "1111",
street_name: "False",
street_number: "123"
}
},
payment_methods: {
// declaramos el método de pago y sus restricciones
excluded_payment_methods: [
// aca podemos excluir metodos de pagos, tengan en cuenta que es un array de objetos
{
id: "amex"
}
],
excluded_payment_types: [{ id: "atm" }],
// aca podemos excluir TIPOS de pagos, es un array de objetos
installments: 6,
// limite superior de cantidad de cuotas permitidas
default_installments: 6
// la cantidad de cuotas que van a aparecer por defecto
},
back_urls: {
// declaramos las urls de redireccionamiento
success: "https://localhost:3000/success",
// url que va a redireccionar si sale todo bien
pending: "https://localhost:3000.com/pending",
// url a la que va a redireccionar si decide pagar en efectivo por ejemplo
failure: "https://localhost:3000.com/error"
// url a la que va a redireccionar si falla el pago
},
notification_url: "https://mercadopago-checkout.herokuapp.com/webhook",
// declaramos nuestra url donde recibiremos las notificaciones
auto_return: "approved"
// si la compra es exitosa automaticamente redirige a "success" de back_urls
};
try {
const request = await axios.post(url, preferences, {
// hacemos el POST a la url que declaramos arriba, con las preferencias
headers: {
// y el header, que contiene content-Type
"Content-Type": "application/json"
}
});
return request.data;
// devolvemos la data que devuelve el POST
} catch (e) {
console.log(e);
// mostramos error en caso de que falle el POST
}
}
}
//NOTA: TODAS las URLS que usemos tienen que ser reales,
//si prueban con localhost, va a fallar
module.exports = PaymentService;
是的,一切都回来了。 Para terminar con el ciclo, desde el front, deberían realizar un POST
request a /payment/new
y eso les va a devolver un link, que es el del pago.
Recuerden que el POST
ejecutado desde el front tiene que tener un body que contenga (por lo menos), name
, unit
, img
, y price
.
Espero que este 教程 les haya servido como guía para iniciarse en este tipo de integraciones or para resolver dudas!
Toda la documentación de Mercado Pago, y lo que use para crear este codigo, está acá
请参阅有关使用说明的建议
Me pueden mandar sus Consultas o mejoras del código (porque hay mil cosas para mejorar) a mi twitter @ncastrogarcia
没有回复更多评论! si tienen dudas pueden Consultarme por twitter!
Tambien les dejo este 视频, que explico lo Mismo que este blog pero en formato video
与咖啡店比较
非常感谢你的时间!
文章来源:https://dev.to/nicolascatrogarcia/como-integrar-mercado-pago-a-tu-web-34al