Opção 2: integrando a DLL ZOOP PC diretamente no seu projeto .NET

Nesta seção vamos explicar como integrar a biblioteca diretamente no seu sistema .NET , que é a opção que lhe dará maior controle e flexibilidade do processo de forma completa. Para isto seu projeto de sistema precisa aceitar referenciar uma biblioteca .NET 64 bits (framework 4.6 ou superior).

A DLL do Zoop PC está na pasta "opcao_2_integracao_direta_DLL_dotNET". Copie as 3 dlls ali contidas para dentro do seu projeto e adicione a referência da ZoopSDKPC.dll no seu projeto de forma que o namespace ZoopSDKPC fique disponível no seu código fonte.

494494

Além das DLLs essa pasta contém 2 projetos completos de demonstração de uso da DLL. Um projeto de UI checkout em Windows Forms (similar ao modo UI do Zoop PC porém mais simplificado) e um projeto de aplicação CONSOLE que está bem simplifcado para que você entenda as chamadas. Usaremos ele como referencia para esta explicação de uso.

🚧

AVISO IMPORTANTE

Utilize os projetos de código fonte demonstrativo são apenas como REFERÊNCIA para entender como adaptar a sua aplicação ao uso da DLL.

Não recomendamos usar o próprio projeto diretamente como sistema, por sua simplicidade, nao contém todos os cenários de uso do dia-a-dia e não contém tratamento para todo tipo de erro que ocorra. Esta responsabilidade é do SEU sistema onde você incluirá a DLL que lhe permitirá transacionar com segurança através da Zoop. A Zoop não se responsabilizará pelo aplicativo demo se o for usado como "produtivo" pois o mesmo tem exclusivo uso previsto para ensinar o seu DESENVOLVEDOR a usar a integração da forma correta.

Como se dá o processo de comunicação da sua aplicação (contendo a DLL integrada) com o backend de pagamentos da Zoop:

O processo consiste basicamente em:

a) inicializar a comunicação (autenticação das credenciais, abertura da porta serial de comunicação com o pinpad e leitura das configurações do arquivo zconfig.ini,

b) criar um objeto de "terminal virtual" para executar as chamadas de venda (charge) ou de estorno (void) de acordo com a necessidade.

c) invocar o servidor de backend websockets da Zoop (Zoop EMV Cloud - Z.E.C) o qual faz a mediação entre os processos com o Emissor/Bandeira do cartão através da rede de adquirência.

d) Aguardar e responder aos CALLBACKS que o servidor fará a cada passo do processo do fluxo de venda até sua finalização com sucesso seja recebendo autorização da venda ou negação da venda pelo Emissor/bandeira. Dependendo do tipo do cartão (aproximação, chip, tarja) e critérios do próprio emissor, pode ser que callbacks adicionais solicitem verificação de digitos finais do cartão, ou código CVC do verso do mesmo ou até assinatura no comprovante. Assim o número de chamadas callback trocados em cada transação pode variar. Num cenário simples ideal ocorre o método charge() invocado no seu código fonte, seguido por callbacks de notificação para inserir cartão, digitar senha e finalizando com o retorno do sucesso ou falha da operação. O fluxo segue rigorosamente o mesmo apresentado durante o uso do Zoop PC no modo "mini-checkout" mostrado na opção de uso 1, porém, neste modelo ao invés de passar as msgs para uma UI própria, as mensagens serão direcionadas para o seu aplicativo para o método que você indicar como recebedor das callbacks do servidor.

518518

Diagrama de Mensagens

INTEGRANDO SEU CÓDIGO FONTE:

Usaremos como referência de exemplo a linguagem C#, você pode adaptar os conceitos para a linguagem utilizada pelo seu sistema que suporte .NET

O primeiro passo que você precisa tomar é referenciar o namespace ZoopSDKPC incluindo o mesmo na seção de "using" do código fonte.

Você precisa de uma classe que responda como intermediadora do envio das chamadas de venda (charge) e estorno (void) e que recepcione os callbacks do servidor com as ações a serem tomadas e resultados da transação. Para isso você pode criar uma classe especifica ou usar a própria classe do seu FORM principal (o form que representa a sua tela de vendas) e nessa classe implementar a herança das seguintes interfaces:

*TerminalPaymentListener,
ApplicationDisplayListener,
ExtraCardInformationListener,

TransactionEventsListener,
VoidTransactionListener,

LogInterceptorListener*

sendo as 3 primeiras obrigatórias para operação de venda (charge) ou estorno (void),
as 2 seguintes (TransactionEventsListener e VoidTransactionListener) obrigatórias respectivamente para venda(charge) e a outra para estorno(void).
a última (LogInterceptorListener) é opcional caso você deseje consumir as logs do processo (as mesmas que vão para o arquivo ZoopSDK.log caso a configuração debug_to_file=true esteja presente no arquivo zconfig.ini) e redirecione uma cópia das mesmas para um método da sua aplicação para que você possa controlar o debug de logs caso precise em algum momento.

Esses interfaces funcionam como "Listeners" sendo chamado sob demanda pelos callbacks que a aplicação receberá do servidor e cada um tem função específica que será explicada na sequencia abaixo.

A forma correta para implementar a declaração desta herança seria:

public class ZoopClient :     TerminalPaymentListener,            
                              ApplicationDisplayListener,       
                              ExtraCardInformationListener,     
                              VoidTransactionListener,
                              TransactionEventsListener,    
                              LogInterceptorListener   
   {
      ... 
   }

O nome da classe (no exemplo "ZoopClient" é livre) basta vc lembrar que essa classe é que fará a mediação entre sua aplicação e o backend da Zoop. Inclusive pode ser o próprio form da sua aplicação WindowsForms, e neste caso a declaração seria semelhante a esta:

public partial class seuFormDeVendas :     Form,
                              TerminalPaymentListener,            
                              ApplicationDisplayListener,       
                              ExtraCardInformationListener,     
                              VoidTransactionListener,
                              TransactionEventsListener,    
                              LogInterceptorListener   
   {
      ... 
   }

a partir do momento que você herdar essas interfaces para implementar na sua classe escolhida, seja o form de venda da sua aplicação ou uma classe separada, será exigido pelo compilador que você crie (implemente) uma série de métodos para cada uma dessas classes. Cada um desses métodos tem uma função de recepção de informação.

Para facilidade didática abaixo segue o trecho de código fonte a ser implementado na classe que herdou as interfaces, sendo em cada um comentado o seu uso e propósito:

public void paymentSuccessful(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener, quando a transação foi autorizada pelo Emissor/bandeira com sucesso. 
            //      O mesmo retorna um JSON contendo toda a informação da transação, inclusive o comprovante de venda já formatado para impressão.
        }

        public void paymentFailed(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener, quando a transação foi negada pelo Emissor/bandeira,
            //      ou se ocorreu algum erro durante o processamento da transação.
            //      O mesmo retorna um JSON contendo maiores informações sobre o erro ocorrido ou motivo da negação.
        }

        public void paymentAborted()
        {
            //      este método é automaticamente invocado na sua aplicação pelo SDK, na classe que vc implementou a interface TerminalPaymentListener, quando a transação é interrompida de forma abrupta.
            //      Ex: usuário apertou o botao cancela (vermelho) da maquininha, ou removeu o cartão antes do esperado, ou sua app tentou gerar uma nova transacao de venda durante o fluxo em andamento ainda não concluído.
            //      Utilize ele para informar que a operação em andamento foi abandonada. Em alguns casos, uma chamda de paymentFailed() pode ser recebida no seu app, contendo maiores detalhes.
            ;
        }

        public void onStartTransaction(string clientTransactionId)
        {
            // este método é invocado na sua aplicação, na classe que vc implementou a interface TransactionEventsListener quando a transação é processada
            // e retorna um id do processo gerado no backend, o qual poderá ser usados em chamadas de reversão posteriores (chamadas que nao exigem a presença
            // do cartão físico, nas situaçoes em que se aplica tal ação de forma permitida.)
            // atenção: reversão é diferente de estorno (void) sendo que este último exige a leitura fisica do cartão original da transação para ocorrer.
            // a interface TransactionEventsListener não é obrigatória sendo desnecessário este método caso nao seja implementada.
            ;
        }
                public void endOfTransaction()
        {
            // este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener ao final de todo o processo concluído, quando o backend de pagamento do servidor já foi
            //  desconectado,sinalizando que o terminal foi desconectado e o controle volta para sua aplicação para uma nova operação ou qualquer ação que julgar
            //  necessário executar do lado do seu aplicativo.
            ;
        }

        public void cardholderSignatureRequested()
        {
            // este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener quando o Emissor/bandeira
            //  exige que seja realizda uma assinatura do cliente no recibo impresso. Use esta chamada para pausar e mostrar aviso na tela do seu app,
            //  notificado o cliente da necessidade. Este método nao necessita retornar nada para o servidor.
        }

        public void showMessage(string sMessage, TerminalMessageType messageType)
        {
            /* 
                        este método é invocado na sua aplicação, na classe que vc implementou a interface ApplicationDisplayListener, quando
            existe uma notificação a ser enviada para o display da sua aplicação ou lhe informar sobre um evento de estado na maquininha 
            que lhe interesse mostrar algum sinal ao cliente na sua app (Ex: ampulheta de espera enquatno procesando compra, ou mostrar icone
            de cartao inserido quando aguardando um cartão ser inserido, etc)

            É composta pela string mensagem sMessage e um enum messageType (vide lista) indicando o tipo de ação da mensagem, para que 
            vocë possa tomar decisão de como mostrar a mensagem visualmente a da melhor forma no contexto da sua aplicação.

                Vide o enum TerminalMessageType para conhecer os tipos possíveis de identificação da msg.

                Tipos comuns são 
                TerminalMessageType.WAIT (indica espera, e seu app pode mostrar uma ampulheta por exemplo)
                TerminalMessageType.ACTION_INSERT_CARD(na tela da maquininnha está pedindo cartao, vc pode mostrar um icone de cartao inserindo, etc..)
                TerminalMessageType.ACTION_REMOVE_CARD , 
                etc...
            */
        }
        public void showMessage(string sMessage, TerminalMessageType messageType, string sExplanation)
        {
            /* 
                    este método é um variante do showMessage porém com mais detalhamento explicativo.
                    Em alguns casos a bandeira emissora envia informações adicionais para serem utilizadas
                    por seu aplicativo.
            */
            ;
        }
        public void cardCVCRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que seja digitado o CVC do verso do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardCVC() passando para ele o valor capturado para continuidade da autorização.
        }

        public void cardLast4DigitsRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que sejam digitados os 4 ultimos digitos do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardLast4Digits() passando para ele o valor capturado para continuidade da autorização.
        }

        public void cardExpirationDateRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que seja digitada a data de expiracao MM/AA do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardExpirationDate() passando para ele o valor capturado para continuidade da autorização.
        }

        public void voidTransactionSuccessful(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface VoidTransactionListener, quando o estorno solicitado da transação teve sucesso. 
            //      O mesmo retorna um JSON as informações originais detalhadas da transação.
        }

        public void voidTransactionFailed(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface VoidTransactionListener, quando o estorno solicitado da transação falhou ou não foi autorizado.
            //      O mesmo retorna um JSON as informações originais detalhadas da transação.
        }

        public void dump(string msgLog) {

            //  este método é invocado na sua aplicação, na classe que vc implementou a interface LogInterceptionListener, e recebe
            // uma cópia da msg de todas as logs sendo geradas durante o processo. Vc pode direcionar essas logs da forma que achar melhor ou apenas
            // descartá-las.
            // atencao: essa interface nao é obrigatória, se desejar  ver cópia das logs, você pode nao declarar a herança dela e nao implementar este método.
        }

Uma vez definidas a classe de mediação que herdou a implementação das interfaces necessárias e implementados os métodos exigidos, os próximos passos são:

a) implementar um método de cobrança (nome sugerido charge() ou cobrar()...) na sua classe mediadora. Esse método deve receber 3 parametros int sendo respectivamente o valor a ser cobrando (em centavos), o tipo de pagamento (0 - crédito,1 - débito,2 - crédito parcelado,3 - vouchers) e o número de parcelas (0 para a vista ou 1, 2, 3... para parcelamento).
O conteudo deste método será o descrito no passo (c) em diante.

b) implementar um método de estorno (nome sugerido void() ou estornar()...) na sua classe mediadora. Esse método deve receber um parametro string que representa o id da transação confirmada que será estornado. Esse id é recebido no JSON de resposta do sucesso da transação pelo método paymentSucessfull() definido na interface.
O conteudo deste método será o descrito no passo (c) em diante.

c) Dentro de cada método (cobrança e estorno) implementar um objeto que representará o "terminal virtual" na sua aplicação. Esse método deve ser do tipo ZoopTerminalPayment para o método de venda ou ZoopTerminalVoidPayment para o método de estorno.
Ex:

// para venda:
ZoopTerminalPayment meuTerminalVirtualVendas = new ZoopTerminalPayment();

// para estorno:
ZoopTerminalVoidPayment meuTerminalVirtualEstornos = new ZoopTerminalVoidPayment();

Uma vez definidos os objetos que representam os terminais virtuais de venda e estorno, os mesmos devem ser vinculados com os métodos de callback (os listeners) que você definiu nessa mesma classe.

Para isso use o trecho de código abaixo, dentro do seu método de compra ou estorno, que faz esse vinculo.

//Para Venda:
                // mandatórios:
                meuTerminalVirtualVendas.setTerminalPaymentListener(this);
                meuTerminalVirtualVendas.setApplicationDisplayListener(this);
                meuTerminalVirtualVendas.setExtraCardInformationListener(this);

                //opcionais:
                //  meuTerminalVirtual.setTransactionEventsListener(this);
                //  meuTerminalVirtual.setLogInterceptorListener(this);
//Para estorno:

                meuTerminalVirtualEstornos.setApplicationDisplayListener(this);
                meuTerminalVirtualEstornos.setVoidPaymentListener(this);
                meuTerminalVirtualEstornos.setExtraCardInformationListener(this);
                //opcional:
                //  meuTerminalVirtual.setLogInterceptorListener(this);

Vinculados os métodos com o objeto o mesmo está pronto pra atender as chamadas de callback do servidor.

Agora o método pode inicializar a Zoop API (isso pode ser chamado no inicio também, independente do vinculo acima, mas foi colocado nesta ordem pra facilitar a didática da explicação).

A inicialização da API é importante pq ela define pelo menos 3 ações relevantes:

  1. Ela define o formato de autenticação no backend Zoop ( via email/senha ou via marketplaceId,sellerId,publishableKey). O primeiro modo é mais aconselhado porque é compatível com os padrões de segurança mais atuais da Zoop, o segundo modo é retro-compatível e um dia no futuro pode não estar mais disponível por apresentar uma exposição de dados maior uma vez que a publishableKey é a sua senha de API , fixa, que pode ser usada em uma chamada caso seja publicada. O email senha já é uma forma que além de não expor os dados de id da sua conta de parceiro, e do seller, também permite mudança em tempo real no caso de desconfiança de comprometimento.

  2. Inicializa (detecta) a porta serial USB

  3. Lê as configurações do arquivo zconfig.ini

ZoopAPI.initialize();   //para usar o formato de autenticação por Ids fixos. (ZPK)

// Neste caso deve ser chamado complementarmente após o initialize o método:

 ZoopAPI.setCredentials("0162893710a6495e86542eeff192baa1", "2c3f90702ab541b88a6f0c6011a1e22f", "xxxxxxxxx"); 
//onde o primeiro parametro é o seu marketplaceId, 
// o segundo é o sellerId do estabelecimento cliente, 
// e o terceiro é o publishablekey (código ZPK).


// Ou opcionalmente,

ZoopAPI.initialize("[email protected]", "sua_senha");
//não sendo neste caso necessário usar o método complementar de credenciais.

e por fim completar o seu método de compra ou estorno com a chamada do método charge() ou void() dos objetos de terminal virtual, sendo:

meuTerminalVirtualVendas.charge(valorEmCentavos, TipoOperacao, NumeroParcelas);
// OU
meuTerminalVirtualEstornos.voidTransaction(idTransacaoParaEstornar);

A partir deste ponto o controle é passado para o backend da Zoop, que começará o fluxo de processamento, descendo dados de produtos (cartões aceitos) para a maquininha, em seguida pedindo inserção/aproximação do cartão (conforme as capacidades do terminal detectadas durante este processo) e por fim pedindo senha e autorizando ou negando a compra.
Todos estes processos serão monitorados pelo seu app através dos recebimentos de chamadas dos métodos que você implementou nas interfaces descritas neste tutorial.

Para completar a experiência didática, segue abaixo o código fonte demonstrativo didático COMPLETO da aplicação console usando este processo descrito acima. Os arquivos deste projeto podem ser encontrados na pasta "opcao2_integracao_direta_DLL_dotNet" na subpasta "zoop-pc-console-demo-sample-1.0".

// Código-fonte exemplo para livre uso que serve como base para usar
// os serviços Zoop PC no seu aplicativo.
//
// Por Regis Silva (@Zoop).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LightJson;
using ZoopSDKPC;

namespace ZoopDemoConsoleClient
{
    class Program
    {
        public static JsonObject joTransaction;

        static void Main(string[] args)
        {
            //
            // Passo 1: criar uma classe que implemente as chamadas ao backend Zoop e 
            // que possua a herança das interfaces que recebem de volta os callbacks.
            // vide classe ZoopClient abaixo. (nome da classe é livre, de sua escolha)

            // Passo 2: instanciar a classe criada
            ZoopClient zc = new ZoopClient();

            // Passo 3: executa a transação desejada: venda (charge) ou estorno (void)

            Console.Clear();
            Console.WriteLine("Iniciando uma cobrança de R$ 0,01 ...");
            zc.cobrar(1, 1, 0);
            Console.ReadLine(); // aguarda processos e callbacks 
                                // este passo nao necessário num app Windows que é multithread.

            Console.WriteLine("Agora vamos estornar a compra realizada ...");

            if (Program.joTransaction.ContainsKey("id"))
            {
                zc.estornar(joTransaction["id"]);
            }
            Console.ReadLine(); // aguarda processos e callbacks 
                                // este passo nao necessário num app Windows que é multithread.

        }


    }

    // abaixo uma classe exemplo que vc precisa implementar para responder aos callbacks
    // do servidor Zoop. O Nome da classe é livre, basta herdar as interfaces indicadas.
    // a classe pode inclusive ser o FORM de VENDA do seu aplicativo, nao precisa ser uma classe
    // separada. Basta que ela herde as interfaces e seja configurada/vinculada ao 
    // seu objeto de terminal virtual (passo 4 descrito acima).
    // O servidor Zoop vai invocar estes métodos para passar pra sua aplicação respostas
    // e solicitar acões em alguns casos.

    public class ZoopClient : TerminalPaymentListener,           //mandatória
                              ApplicationDisplayListener,        //mandatória
                              ExtraCardInformationListener,      //mandatória
                              VoidTransactionListener           //mandatória
                                                                //  TransactionEventsListener,        //opcional
                                                                //   LogInterceptorListener            //opcional
    {

        public void cobrar(Int32 piValueToChargeInCents, int pPaymentOption, int piNumberOfInstallments)
        {
            try
            {
                // 1: inicialização da API do client e credenciais de conexão Zoop.
                if (!ZoopAPI.initialize()) // opção sem login/senha
                {
                    if (ZoopAPI.panicAlert != null)
                    {
                        minhaLog(ZoopAPI.panicAlert);
                    }
                }
                else
                {
                    ZoopAPI.setCredentials("0162893710a6495e86542eeff192baa1", "2c3f90702ab541b88a6f0c6011a1e22f", "zpk_prod_O6Wo7kRzYX11U0KQCy5Yl9hx");
                }

                // OU

                /*
                if (ZoopAPI.initialize("[email protected]", "[email protected]"))
                // neste caso não há necessidade de configurar credenciais manualmente.
                // utilize o LOGIN (email/senha) do estabelecimento cadastrados para acesso ao 
                // Dashboard ou Minha Loja.

                {
                    if (ZoopAPI.panicAlert != null)
                    {
                        minhaLog(ZoopAPI.panicAlert);
                    }
                }
                */

                // 2: definir objeto que representa seu terminal virtual.
                ZoopTerminalPayment meuTerminalVirtualVendas = new ZoopTerminalPayment();


                // 3:
                // vincular os listenners da classe do seu terminal virtual com a classe
                // que recebe/responde callbacks do backend Zoop.

                // mandatórios:
                meuTerminalVirtualVendas.setTerminalPaymentListener(this);
                meuTerminalVirtualVendas.setApplicationDisplayListener(this);
                meuTerminalVirtualVendas.setExtraCardInformationListener(this);

                //opcionais:
                //  meuTerminalVirtual.setTransactionEventsListener(this);
                //  meuTerminalVirtual.setLogInterceptorListener(this);

                //4: executar o charge
                meuTerminalVirtualVendas.charge(piValueToChargeInCents, pPaymentOption, piNumberOfInstallments);

            }
            catch (Exception ex)
            {
                minhaLog(ex.Message);
            }

        }
        public void estornar(string idTransacaoParaEstornar)
        {
            try
            {
                // 1: inicialização da API do client e credenciais de conexão Zoop.
                if (!ZoopAPI.initialize()) // opção sem login/senha
                {
                    if (ZoopAPI.panicAlert != null)
                    {
                        minhaLog(ZoopAPI.panicAlert);
                    }
                }
                else
                {
                    ZoopAPI.setCredentials("0162893710a6495e86542eeff192baa1", "2c3f90702ab541b88a6f0c6011a1e22f", "zpk_prod_O6Wo7kRzYX11U0KQCy5Yl9hx");
                }

                // OU

                /*
                if (ZoopAPI.initialize("[email protected]", "[email protected]"))
                // neste caso não há necessidade de configurar credenciais manualmente.
                // utilize o LOGIN (email/senha) do estabelecimento cadastrados para acesso ao 
                // Dashboard ou Minha Loja.

                {
                    if (ZoopAPI.panicAlert != null)
                    {
                        minhaLog(ZoopAPI.panicAlert);
                    }
                }
                */

                // 2: definir objeto que representa seu terminal virtual.
                ZoopTerminalVoidPayment meuTerminalVirtualEstornos = new ZoopTerminalVoidPayment();


                // 3:
                // vincular os listenners da classe do seu terminal virtual com a classe
                // que recebe/responde callbacks do backend Zoop.

                meuTerminalVirtualEstornos.setApplicationDisplayListener(this);
                meuTerminalVirtualEstornos.setVoidPaymentListener(this);
                meuTerminalVirtualEstornos.setExtraCardInformationListener(this);
                //opcional:
                //  meuTerminalVirtual.setLogInterceptorListener(this);

                // 4: executar o estorno
                meuTerminalVirtualEstornos.voidTransaction(idTransacaoParaEstornar);

            }
            catch (Exception ex)
            {
                minhaLog(ex.Message);
            }

        }

        public void minhaLog(string log)
        {
            Console.WriteLine(log);
        }

        public void paymentSuccessful(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener, quando a transação foi autorizada pelo Emissor/bandeira com sucesso. 
            //      O mesmo retorna um JSON contendo toda a informação da transação, inclusive o comprovante de venda já formatado para impressão.
            minhaLog(joResponse);
            Program.joTransaction = JsonValue.Parse(joResponse);
        }

        public void paymentFailed(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener, quando a transação foi negada pelo Emissor/bandeira,
            //      ou se ocorreu algum erro durante o processamento da transação.
            //      O mesmo retorna um JSON contendo maiores informações sobre o erro ocorrido ou motivo da negação.
            minhaLog(joResponse);
            Program.joTransaction = JsonValue.Parse(joResponse);
        }

        public void paymentAborted()
        {
            //      este método é automaticamente invocado na sua aplicação pelo SDK, na classe que vc implementou a interface TerminalPaymentListener, quando a transação é interrompida de forma abrupta.
            //      Ex: usuário apertou o botao cancela (vermelho) da maquininha, ou removeu o cartão antes do esperado, ou sua app tentou gerar uma nova transacao de venda durante o fluxo em andamento ainda não concluído.
            //      Utilize ele para informar que a operação em andamento foi abandonada. Em alguns casos, uma chamda de paymentFailed() pode ser recebida no seu app, contendo maiores detalhes.
            ;
        }

        public void endOfTransaction()
        {
            // este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener ao final de todo o processo concluído, quando o backend de pagamento do servidor já foi
            //  desconectado,sinalizando que o terminal foi desconectado e o controle volta para sua aplicação para uma nova operação ou qualquer ação que julgar
            //  necessário executar do lado do seu aplicativo.
            ;
        }

        public void cardholderSignatureRequested()
        {
            // este método é invocado na sua aplicação, na classe que vc implementou a interface TerminalPaymentListener quando o Emissor/bandeira
            //  exige que seja realizda uma assinatura do cliente no recibo impresso. Use esta chamada para pausar e mostrar aviso na tela do seu app,
            //  notificado o cliente da necessidade. Este método nao necessita retornar nada para o servidor.
        }

        public void showMessage(string sMessage, TerminalMessageType messageType)
        {
            /* 
                        este método é invocado na sua aplicação, na classe que vc implementou a interface ApplicationDisplayListener, quando
            existe uma notificação a ser enviada para o display da sua aplicação ou lhe informar sobre um evento de estado na maquininha 
            que lhe interesse mostrar algum sinal ao cliente na sua app (Ex: ampulheta de espera enquatno procesando compra, ou mostrar icone
            de cartao inserido quando aguardando um cartão ser inserido, etc)

            É composta pela string mensagem sMessage e um enum messageType (vide lista) indicando o tipo de ação da mensagem, para que 
            vocë possa tomar decisão de como mostrar a mensagem visualmente a da melhor forma no contexto da sua aplicação.

                Vide o enum TerminalMessageType para conhecer os tipos possíveis de identificação da msg.

                Tipos comuns são 
                TerminalMessageType.WAIT (indica espera, e seu app pode mostrar uma ampulheta por exemplo)
                TerminalMessageType.ACTION_INSERT_CARD(na tela da maquininnha está pedindo cartao, vc pode mostrar um icone de cartao inserindo, etc..)
                TerminalMessageType.ACTION_REMOVE_CARD , 
                etc...
            */
            minhaLog(sMessage);
        }
        public void showMessage(string sMessage, TerminalMessageType messageType, string sExplanation)
        {
            /* 
                    este método é um variante do showMessage porém com mais detalhamento explicativo.
                    Em alguns casos a bandeira emissora envia informações adicionais para serem utilizadas
                    por seu aplicativo.
            */
            ;
        }
        public void cardCVCRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que seja digitado o CVC do verso do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardCVC() passando para ele o valor capturado para continuidade da autorização.
        }

        public void cardLast4DigitsRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que sejam digitados os 4 ultimos digitos do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardLast4Digits() passando para ele o valor capturado para continuidade da autorização.
        }

        public void cardExpirationDateRequested()
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface ExtraCardInformationListener quando o 
            //  emissor/bandeira exige que seja digitada a data de expiracao MM/AA do cartão.
            //  O terminal mostrará para seguir as informações da tela do seu aplicativo.
            //  Sua aplicação deve capturar essa informação numa tela permitindo digitar (via teclado normal, nao no pinpad) a informacao solicitada.
            //  Em seguida sua aplicação deve chamara o método  addCardExpirationDate() passando para ele o valor capturado para continuidade da autorização.
        }

        public void voidTransactionSuccessful(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface VoidTransactionListener, quando o estorno solicitado da transação teve sucesso. 
            //      O mesmo retorna um JSON as informações originais detalhadas da transação.
            minhaLog(joResponse);
            Program.joTransaction = JsonValue.Parse(joResponse);
        }

        public void voidTransactionFailed(string joResponse)
        {
            //  este método é invocado na sua aplicação, na classe que vc implementou a interface VoidTransactionListener, quando o estorno solicitado da transação falhou ou não foi autorizado.
            //      O mesmo retorna um JSON as informações originais detalhadas da transação.
            minhaLog(joResponse);
            Program.joTransaction = JsonValue.Parse(joResponse);
        }

    }
}

📘

Bônus: demonstração em vídeo

E como "cereja do bolo", disponibilizamos de forma bem resumida, uma demonstração deste processo em um vídeo, caso seja do seu interesse visualizar o procedimento em andamento para comparar com a sua experiência:

Vídeo tutorial em MP4

👍

Check-List de conferência final:

  1. Criar uma classe (ou ajustar a classe do form de vendas) para herdar as interfaces.
  2. Implementar os métodos de callback
  3. Implementar na classe um método de cobrança e estorno
  4. Nos métodos de cobrança/estorno Instanciar o terminal Virtual e vinculá-lo com os métodos de callback.
  5. Nos métodos de cobrança/estorno Inicializar a ZoopAPI
  6. Instanciar (se necessário) um objeto da sua classe mediadora criado e invocar (diretamente se for o caso do próprio form implementar a herança) os métodos de charge() para cobrança e void() para estorno
  7. Responder aos callbacks à medida que forem sendo chamados
  8. usar as informações dos callbacks no seu sistema

📘

Lembrando que neste modo de operação, não há necessidade de rodar o ZoopPC.exe em segundo plano. A DLL faz o papel exato da aplicação em segundo plano que é mandatória nos outros demais formatos (opção 1-checkout, 2-websockets, 3-IPC WMI).

.