MercadoPagoCommunity / foro

No oficial y administrado por la comunidad | Unofficial and managed by the community
4 stars 1 forks source link

Mercadopago MarketPlace: autorización del vendedor #7

Open esteban-turnocheck opened 5 years ago

esteban-turnocheck commented 5 years ago
// Así lo mandás a autorizar tu app. Fijate que al final le estás poniendo la "redirect_uri". Ahí va a ir a parar luego de autorizar tu app.
redirect("https://auth.mercadopago.com.ar/authorization?client_id=" . xxxxxxxx . "&response_type=code&platform_id=mp&redirect_uri='auth_code_obtenido'");

// Que viene a ser acá. Y ya te viene con el auth_code que tenés que usar para pedir las credenciales de tu vendedor para usar después en el resto del marketplace.
function auth_code_obtenido() {
    if(!isset($_GET['code']) || trim($_GET['code']) == '') {
        $this->session->set_flashdata('error', "No se recibió el código de autorización de MercadoPago. Por favor, inténtelo nuevamente.");
        redirect('/empresa/index');
    }
    $auth_code = $_GET['code'];

    try {
        MercadoPago\SDK::initialize();
        $mpconfig = MercadoPago\SDK::config();
        $mpconfig->set('CLIENT_ID', xxxxxxxxxxxxxxxx);
        $mpconfig->set('CLIENT_SECRET', xxxxxxxxxxxxxxxxxx);

        $credenciales = MercadoPago\SDK::post("/oauth/token", array(
            "form_data" => array(
            "client_id" => xxxxxxxxxxxxx,
            "client_secret" => xxxxxxxxxxxxxxxxx,
            "grant_type" => "authorization_code",
            "code" => $auth_code,
                "redirect_uri" => base_url($this->router->class) ."/auth_code_obtenido"),
            "headers" => array(
                            "Content-Type" => "multipart/form-data",
                            "Accept" => "application/json"
                    )
            ));
    } catch (Exception $e) {
        $this->session->set_flashdata('error', $e->getMessage());
        redirect('/empresa/index');
    }

    if ($credenciales['code'] != 200) {
        $this->session->set_flashdata('error', "Error en la comunicación con MercadoPago:<br/>" . $credenciales['body']['message'] . ' - Causa:' . implode(', ', $credenciales['body']['cause']));
        redirect('/empresa/index');
    }

    $datos_credenciales = array(
            'email' => $usuario_logueado->email,
                'nombre' => $usuario_logueado->nombre,
            'apellido' => $usuario_logueado->apellido,
            'access_token' => $credenciales['body']['access_token'],
            'public_key' => $credenciales['body']['public_key'],
            'refresh_token' => $credenciales['body']['refresh_token'],
            'live_mode' => $credenciales['body']['live_mode'],
            'mp_user_id' => $credenciales['body']['user_id'],
            'token_type' => $credenciales['body']['token_type'],
            'expires_in' => $credenciales['body']['expires_in'],
            'scope' => $credenciales['body']['scope'],
            );
    $this->v2mercadopago_model->grabar_credenciales($_SESSION['empresa_id'], $datos_credenciales);
plencovich commented 5 years ago

Muy bueno, te comparto uno que uso en codeigniter: (tiene el IPN también)

<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Mercadopago extends CI_Controller
{
    function __construct()
    {
        parent::__construct();

        $this->load->model('backend/Producers_model','producers');
        $this->load->model('frontend/Cart_model', 'cart');
    }

    public function auth_provider_get($producer_id_encode)
    {
        $producer_id = $this->pcrypt->data('decode', $producer_id_encode);
        $get_code = $this->input->get('code');

        $mp = new MP(wmscp('access_token','mercadopago'));

        $request = array(
            "uri" => "/oauth/token",
            "data" => array(
                "client_id" => wmscp('client_id','mercadopago'),
                "client_secret" => wmscp('client_secret','mercadopago'),
                "grant_type" => "authorization_code",
                "code" => $get_code,
                "redirect_uri" => 'https://'.$this->config->item('app','url_website').'/auth/code/'.$producer_id_encode
            ),
            "headers" => array(
                "content-type" => "application/x-www-form-urlencoded"
            ),
            "authenticate" => false
        );

        $mp_resp = $mp->post($request);

        $info = array(
            'p_mp_access_token' => $mp_resp['response']['access_token'],
            'p_mp_public_key' => $mp_resp['response']['public_key'],
            'p_mp_refresh_token' => $mp_resp['response']['refresh_token'],
            'p_mp_user_id' => $mp_resp['response']['user_id'],
            'p_mp_expires_in' => $mp_resp['response']['expires_in'],
            'p_mp_scope' => $mp_resp['response']['scope'],
            'p_mp_live_mode' => $mp_resp['response']['live_mode'],
            'p_mp_token_type' => $mp_resp['response']['token_type'],
            'p_mp_status' => 1
        );

        $update = $this->producers->update_item($info, $producer_id);

        redirect(wmscp('url_access_producers'),'refresh');
    }

    public function mercadopago_ipn_get()
    {
        $mp = new MP(wmscp('mp_client_id'), wmscp('mp_client_secret'));

        if (!isset($_GET["id"], $_GET["topic"]) || !ctype_digit($_GET["id"])) {
            $this->output->set_status_header(400);
            return;
        }

        $params = ["access_token" => $mp->get_access_token()];
        $collection_id = $_GET["id"];

        if($_GET["topic"] == 'payment'){
            $payment_info = $mp->get("/v1/payments/" . $_GET["id"], $params, false);
            $merchant_order_info = $mp->get("/merchant_orders/" . $payment_info["response"]["order"]["id"], $params, false);
        } else if($_GET["topic"] == 'merchant_order'){
            $merchant_order_info = $mp->get("/merchant_orders/" . $_GET["id"], $params, false);
        }

        if ($merchant_order_info["status"] == 200) {

            $payments=$merchant_order_info["response"]["payments"];
            $payment_status = 'pending';

                foreach ($payments as  $payment) {
                    if($payment['status'] == 'approved'){
                        $payment_status = 'approved';
                    }
                }

            $info = array(
                'or_collection_status' => $payment_status
            );

            $update_order = $this->cart->update_order_ipn($info,$collection_id);
        }
    }
}

Por otro lado, todavía no pude probar si un vendedor, desautoriza la app, cómo me notifica a mi mercadopago? Tenes idea?

Abrazo

esteban-turnocheck commented 5 years ago

Qué interesante. Ahí en tu código veo que decidiste no escuchar las IPN que vienen con topic=merchant_order, que fue una de las cosas que originaron todo este asunto y derivaron en este repo/foro. Porque (lo digo por ahí en el post más largo) cuando te viene el topic=merchant_order, vos tenés que ir a buscar esa merchant_order con el id que te viene. Pero para eso necesitás las credenciales del vendedor en tu marketplace que generó esa merchant order, y no lo tenés, ni tenés en ningún momento la posibilidad de asociar al vendedor con la merchant order. Una opción que yo planteaba era esa, la que hiciste vos, que es no darle bola al topic=merchant_order. La otra, la que finalmente implementé yo, es no usar ni IPN ni webhooks. Hice un cronjob que corre cada tanto, y que me trae todos los payments, y en función del external reference voy procesando cada uno para cada vendedor. Yo yampoco pude probar qué pasa cuando un vendedor te desautoriza la app, pero en un rato voy a correr unos test con un cliente, y ahí hago esa prueba y comento después acá, es buena pregunta. Me imagino que te debe dar un famoso "invalid_caller_id" cuando vas a buscar la merchant_order, pero ya lo probaré.

plencovich commented 5 years ago

Si, hay que probar con guardar el log, a ver que informa mercadopago al ipn puesto en la app, cuando un vendedor desautoriza. yo apenas pueda lo hago.

En cuanto a ese IPN, lo uso en un sitio ecommerce de una sola persona. En el que tengo con marketplace, hice como hiciste vos, directamente no uso IPN y tengo un cron que comprueba por external_reference o merchant_order_id $search_result = (is_null($order_info->or_merchant_order_id)) ? $mp->get('/v1/payments/search?external_reference='.$order_info->or_number) : $mp->search_payment(array('merchant_order_id' => $order_info->or_merchant_order_id),0,10) ;