Pular para conteúdo

Estorno | Deeplink

Estorno V2

O deeplink getnet://pagamento/v2/refund deverá ser utilizado somente por Sub-Adquirentes.
Em transações de Sub-Adquirentes é estritamente necessário o envio de informações que indiquem o Estabelecimento Comercial que realizou a transação. Dessa forma, se faz necessário o envio das Tags especificadas na tabela abaixo, no campo extraData deste novo deeplink.

Request

Obrigatoriedade Parâmetro Formato Descrição
OPCIONAL amount String 12 dígitos representando o valor, considerando os últimos 2 dígitos como casas decimais. Exemplo: "000000001234" é equivalente R$ 12,34.
OPCIONAL transactionDate String Data da transação a ser estornada. Por padrão será o dia corrente. Enviar no formato: “dd/MM/yyyy”
OPCIONAL cvNumber String Número do CV da transação a ser estornada. É o mesmo campo que o pagamento retorna.
OPCIONAL originTerminal String Número lógico do terminal que efetuou a transação a ser estornada. Este parâmetro só pode ser utilizado caso a funcionalidade de Préautorização esteja habilitada no estabelecimento. Quando este parâmetro não é informado, seráutilizado o número lógico do terminal que está executando o procedimento.
OPCIONAL allowPrintCurrentTransaction boolean Ao habilitar este parâmetro, o aplicativo Pagamento não vai imprimir os comprovantes do estabelecimento e do cliente. Seu aplicativo ficará responsável pela impressão dos comprovantes. Mais detalhes na seção Responsabilidade de Impressão.

Para desabilitar: “false”
Para habilitar: “true”

Default: “false”
OBRIGATÓRIO extraData String Parametro reservado para envio de informações adicionais relativas à transação. Estes dados serão propagados na autorização da transação.

Mais detalhes na seção Sub-Adquirentes.

Response

Não existem mudanças nos dados retornados.

Tags Sub-Comércio

Estão descritas abaixo as Tags necessárias numa transação de Sub Adquirente. Para informações mais detalhadas, consultar Sub-Adquirentes.

Tag Descrição Tipo Tamanho
0350 Soft Descriptor

Descrição do subcomércio.
Tamanho da estrutura: 22 bytes fixos
Dados Soft Descriptor: VAR(1)*VAR(2)
VAR(1) pode ter tamanho 3, 7 ou 12 caracteres:
XXX*YYYYYYYYYYYYYYYYYY
XXXXXXX*YYYYYYYYYYYYYY
XXXXXXXXXXXX*YYYYYYYYY

Obs.: Caracteres não permitidos podem ser transformados em outros similares ou excluídos.
Exemplo: "ç" por "C"

Caracteres permitidos:
A - Z
0 - 9
% $ , . / & ( ) + - = < > *
Espaços

Exemplo: SUBADQ *LOJA SANTANDER
ANS 22
0351 MCC Dinâmico

MCC do subcomércio.
O estabelecimento terá previamente cadastrado em seu ambiente os MCC que utilizará em seu Gateway.
Desta forma, fica ao critério do apenas trafegar por esta TAG a informação recebida do Gateway.

Caracteres permitidos:
0 - 9

Exemplo:9999
N 4
0538 ID do subcomércio

Id de identificação do subcomércio

Caracteres permitidos:
A - Z
0 - 9

Exemplo:1248ADC
AN 15
0539 Cidade do Subcomércio

Obs.: Caracteres não permitidos podem ser transformados em outros similares ou excluídos.
Exemplo: "ç" por "C"

Caracteres permitidos:
A - Z

Exemplo:PORTO ALEGRE
N 13
0540 Estado do Subcomércio

Caracteres permitidos:
A - Z

Exemplo:RS
N 2
0541 CEP do Subcomércio

Caracteres permitidos:
0 - 9

Exemplo:90550142
N 8
0542 CNPJ ou CPF do Subcomércio

A aplicação deve validar se é um CNPJ ou CPF válido, sendo o tamanho de 14 para CNPJ e 11 para CPF.

Caracteres permitidos:
0 - 9

Exemplo CNPJ:12345678901234
Exemplo CPF:12345678901
AN 14
0543 Logradouro do Subcomércio

Obs.: Caracteres não permitidos podem ser transformados em outros similares ou excluídos.
Exemplo: "ç" por "C"

Caracteres permitidos:
A - Z
0 - 9
% $ , . / & ( ) + - = < > *
Espaços

Exemplo:R. DOM PEDRO II, 545
AN 40
0544 Telefone do Subcomércio

Número de telefone de Atendimento ao Cliente do subcomércio.

As três primeiras posições devem ser dedicadas ao DDD do estado do subcomercio.

Exemplo:05140088008
LLLVAR 16
0545 URL do Subcomércio

URL do site do parceiro.

Caso o subcomércio não tenha site, não enviar a TAG na requisição.

Exemplo:https://www.exemplo.com.br
LLLVAR 255
0546 Razão Social do Subcomércio

Razão Social da Pessoa Jurídica (CNPJ)registrado na Receita Federal. Em casosde Pessoa Física (CPF) enviar o nome registrado na Receita Federal.

Caracteres permitidos:
A - Z
0 - 9
% $ , . / & ( ) + - = < > *
Espaços

Exemplo:GETNET ADQUIRENCIA E SERVICOS PARA MEIOS DEPAGAMENTO S.A
LLLVAR 80

Descrição de tipos:
ANS - Alfanúmerico podendo conter letras, números e símbolos.
AN - Alfanúmerico podendo conter letras e números.
A - Alfabético contendo apénas letras.
N - Númerico contendo apénas números.
LLLVAR - Alfanúmerico longo podendo conter letras, números e símbolos.

Estorno V1

O deeplink getnet://pagamento/v1/refund irá iniciar o app de Pagamento na tela de estorno.

Se a requisição for enviada com todos os parâmetros preenchidos, a próxima tela a ser mostrada será a de inserir o cartão para realizar o estorno.

Se a requisição for enviada com parâmetros faltando, a próxima tela a ser mostrada será a de preenchimento manual dos parâmetros restantes. Ao preencher os parâmetros e tocar no botão Continuar, a tela de inserir o cartão será mostrada.

O estorno também pode ser realizado diretamente no aplicativo Pagamento, acessando a opção Estorno e preenchendo os dados manualmente.

O parâmetro originTerminal da requisição e o campo “Terminal de origem” da tela de Estorno do aplicativo Pagamento só podem ser utilizados caso a funcionalidade de Pré-autorização esteja habilitada no estabelecimento. Quando este parâmetro não é informado, será utilizado o número lógico do terminal que está executando o procedimento.

O estorno de pagamento através do deeplink ou do aplicativo Pagamento, pode ser realizado apenas no mesmo dia. Caso o estabelecimento queira estornar uma transação que foi realizada no dia anterior, este deve entrar em contato com a Getnet.

Abaixo seguem as tabelas de requisição e resposta e seus respectivos parâmetros:

Request

Obrigatoriedade Parâmetro Formato Descrição
OPCIONAL amount String 12 dígitos representando o valor, considerando os últimos 2 dígitos como casas decimais. Exemplo: "000000001234" é equivalente R$ 12,34.
OPCIONAL transactionDate String Data da transação a ser estornada. Por padrão será o dia corrente. Enviar no formato: “dd/MM/yyyy”
OPCIONAL cvNumber String Número do CV da transação a ser estornada. É o mesmo campo que o pagamento retorna.
OPCIONAL originTerminal String Número lógico do terminal que efetuou a transação a ser estornada. Este parâmetro só pode ser utilizado caso a funcionalidade de Préautorização esteja habilitada no estabelecimento. Quando este parâmetro não é informado, seráutilizado o número lógico do terminal que está executando o procedimento.
OPCIONAL allowPrintCurrentTransaction boolean Ao habilitar este parâmetro, o aplicativo Pagamento não vai imprimir os comprovantes do estabelecimento e do cliente. Seu aplicativo ficará responsável pela impressão dos comprovantes. Mais detalhes na seção Responsabilidade de Impressão.

Para desabilitar: “false”
Para habilitar: “true”

Default: “false”

Response

Quando retorna? Parâmetro Formato Descrição
SEMPRE result String Resultado da transação, conforme a Tabela de Resultados das Funcionalidades.
OPCIONAL resultDetails String Texto com detalhes do retorno, conforme a Tabela de Resultados das Funcionalidades.
SEMPRE amount String 12 dígitos representando o valor, considerando os últimos 2 dígitos como casas decimais.
Exemplo: 000000001234 = R$ 12,34
OPCIONAL gmtDateTime String Data e hora GMT da transação (MMDDhhmmss). Este campo representa o horário GMT
OPCIONAL nsu String Código de autorização da transação da Getnet – ele é único por terminal (CV impresso no comprovante, não pode se repetir no mesmo dia)
OPCIONAL nsuLocal String NSU gerado no terminal (DOC impresso no comprovante, incremental por dia)
OPCIONAL nsuLastSuccessfullMessage String Último NSU da GetNet gerado com sucesso
OPCIONAL authorizationCode String Código único de autorização (AUT impresso no comprovante, pode se repetir)
* Este campo é de responsabilidade dabandeira
*
OPCIONAL cardBin String Os 6 primeiros dígitos do cartão
OPCIONAL cardLastDigits String Os 4 últimos dígitos do cartão
OPCIONAL refundTransactionDate String Data da transação estornada. No formato: “ddMMyyyy”
OPCIONAL refundCvNumber String Número do CV da transação estornada. É o mesmo campo que o pagamento retorna.
SEMPRE refundOriginTerminal String Número lógico do terminal que efetuou a transação estornada
OPCIONAL cardholderName String Retorna o nome do portador gravado no cartão, se disponível.
OPCIONAL(*) splitPayloadResponse String (*) Retorna quando é feito um estorno de transações com Split de Pagamento.

Mais detalhes na seção Payload do Split de Pagamento.
OPCIONAL automationSlip String Neste parâmetro enviamos as informações que devem ser incluídas nos Comprovantes Impressos do estabelecimento e do cliente. Seu aplicativo só é obrigado a imprimir esses campos caso você opte por usar a funcionalidade Responsabilidade de Impressão, pois nesse caso o aplicativo Pagamento não irá imprimir os comprovantes.

Mais detalhes na seção Dados do Comprovante.

Exemplo de implementação

public class MainActivity extends AppCompatActivity {
  private final int REQUEST_CODE = 1001;
  private final String ARG_RESULT = "result";
  private final String ARG_RESULT_DETAILS = "resultDetails";
  private final String ARG_AMOUNT = "amount";

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("getnet://pagamento/v1/refund"));
    startActivityForResult(intent, REQUEST_CODE);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data){
    super.onActivityResult(requestCode, resultCode, data);
    if(REQUEST_CODE == requestCode && RESULT_OK == resultCode){
      String result = data.getStringExtra(ARG_RESULT);
      String resultDetails = data.getStringExtra(ARG_RESULT_DETAILS);
      String amount = data.getStringExtra(ARG_AMOUNT);
    }
  }
}
class MainActivity : AppCompatActivity() {
    private val REQUEST_CODE = 1001
    private val ARG_RESULT = "result"
    private val ARG_RESULT_DETAILS = "resultDetails"
    private val ARG_AMOUNT = "amount"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val intent = Intent(Intent.ACTION_VIEW, Uri.parse("getnet://pagamento/v1/refund"))
        startActivityForResult(intent, REQUEST_CODE)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (REQUEST_CODE == requestCode && resultCode == RESULT_OK) {
            val result = data?.getStringExtra(ARG_RESULT)
            val resultDetails = data?.getStringExtra(ARG_RESULT_DETAILS)
            val amount = data?.getStringExtra(ARG_AMOUNT)
        }
    }
}
import React, { useState, useLayoutEffect } from 'react';
import { View, Text } from 'react-native';
import * as IntentLauncher from 'expo-intent-launcher';

const RESULT_OK = -1;
const RESULT_CANCELED = 0;

const ACTION_VIEW = 'android.intent.action.VIEW';

export default function MainComponent() {

  const ARG_RESULT = "result";
  const ARG_RESULT_DETAILS = "resultDetails";
  const ARG_AMOUNT = "amount";

  const [resultCode, setResultCode] = useState<number>();
  const [resultData, setResultData] = useState({});

  const launchIntent = async(deeplink: string, bundle: {}) =>  {

    const intentParams = { ...bundle, data: deeplink }; //Unindo URI Deeplink com o bundle no intentParams

    try {
      const activityResult = await IntentLauncher.startActivityAsync(ACTION_VIEW, intentParams);
      if (activityResult.data && activityResult.resultCode == RESULT_OK) {
        if(activityResult.extra) {
          const JSON_obj = JSON.parse(JSON.stringify(activityResult.extra))

          const result = JSON_obj[ARG_RESULT];
          const resultDetails = JSON_obj[ARG_RESULT_DETAILS];
          const amount =JSON_obj[ARG_AMOUNT];

          setResultData(JSON_obj);
          setResultCode(activityResult.resultCode);
        }
      }
    } catch (error) {
      console.error(error);
    }
  };

  useLayoutEffect(() => {
    const intentParams = {};

    //Dispara o Deeplink assim que a tela termina de ser carregada
    launchIntent('getnet://pagamento/v1/refund', intentParams);
  }, []);

  return (
    <View>
      <Text>Result Code: {resultCode}</Text>
      <Text>Result Data: {JSON.stringify(resultData)}</Text>
    </View>
  );
}

Para utilizar o deeplink, será necessário fazer uso do código nativo:

package com.example.deeplink_test

import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log

class MainActivity: FlutterActivity(), MethodCallHandler {
    private val CHANNEL = "sample.android/deeplink"
    private lateinit var channel: MethodChannel
    private var callback: Result? = null

    private var requestCode: Int = -1

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).apply {
            setMethodCallHandler(this@MainActivity)
        }
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        var action = ""
        var deeplink = ""
        var bundle = Bundle()

        when(call.method) {
            "startActivityForResult" -> {
                callback = result
                val params = call.arguments as? Map<String, Any>
                params?.run {
                    for ((key, value) in params) {
                        when(key.toString()) {
                            "action" -> action = value.toString()
                            "data" -> deeplink = value.toString()
                            "requestCode" -> requestCode = value.toString().toInt()
                            "arguments" -> {
                                bundle.apply{
                                    for((argKey, argValue) in (value as Map<String, Any>)) {
                                        when(argValue) {
                                            is String -> putString(argKey, argValue as String)
                                            is Int -> putInt(argKey, argValue as Int)
                                            is Boolean -> putBoolean(argKey, argValue as Boolean)
                                        }
                                    }
                                }
                            }
                        }
                    }
                    val intent = Intent(action, Uri.parse(deeplink)).apply {
                        putExtras(bundle)
                    }
                    startActivityForResult(intent, requestCode)
                }
            }
            else -> result.notImplemented()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when(requestCode) {
            this.requestCode -> {
                when(resultCode) {
                    Activity.RESULT_OK -> {
                        data?.getExtras()?.let { extras ->
                            val resultMap = hashMapOf<String, Any?>()
                            for(key in extras.keySet()) {
                                resultMap[key] = extras.get(key)
                            }
                            callback?.success(resultMap)
                        }
                    } else -> callback?.error("ERROR", "No valid return from DeepLink", null)
                }
            } else -> callback?.error("ERROR", "Activity result was not OK", null)
        }
    }
}

E com o código nativo criado, podemos chamar ele através do startIntent abaixo:

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key,});

  @override
  State<MyApp> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {

  static const int REQUEST_CODE = 10001;
  static const String ARG_RESULT = 'result';
  static const String ARG_RESULT_DETAILS = 'resultDetails';
  static const String ARG_AMOUNT = 'amount';

  int? resultCode;
  var deeplinkResult = '';

  static const platform = MethodChannel('sample.android/deeplink');

  void startIntent(String deeplink, Map<String, String> bundle) async {
      try {
        final intent = {
          'requestCode': REQUEST_CODE,
          'action': 'android.intent.action.VIEW',
          'data': deeplink,
          'arguments': bundle,
        };
        var result = await platform.invokeMethod('startActivityForResult', intent);
        if (result != null) {
          var resultMap = Map<String, dynamic>.from(result);

          var resultValue = resultMap[ARG_RESULT];
          var resultDetailsValue = resultMap[ARG_RESULT_DETAILS];
          var amountValue = resultMap[ARG_AMOUNT];
          setState(() {
            resultCode = 1;
          });
        }
      } catch (e) {
        log('Error launching intent: $e');
      }
    }

  void _sendDeeplink() {
    Map<String, String> intentParams = {};
    startIntent('getnet://pagamento/v1/refund', intentParams);
  }

  @override
  void initState() {
    super.initState();
    _sendDeeplink();
  }
  @override
  Widget build(BuildContext context) {

    return ();
  }
}