Dev (Back & Front)ARTIGO

Utilizando a API TransactionSearch para pesquisas dentro da aplicação

Vamos aproveitar a flexibilidade oferecida pelas APIs do PayPal para fazer uma integração completa de transações.

Segundo a definição na Wikipédia, ERP significa:

“…sistemas de informação que integram todos os dados e processos de uma organização em um único sistema. A integração pode ser vista sob a perspectiva funcional (sistemas de: finanças, contabilidade, recursos humanos, fabricação, marketing, vendas, compras, etc) e sob a perspectiva sistêmica (sistema de processamento de transações, sistemas de informações gerenciais, sistemas de apoio a decisão, etc).”

Como o objetivo desse tipo de sistema é integrar todos os dados e processos de uma organização, incluindo finanças e sistema de processamento de transações, vamos aproveitar a grande flexibilidade oferecida pelas APIs do PayPal para fazer uma integração completa de transações, incluindo busca, visualização, captura e estorno de transações.

Do ponto de vista do operador do sistema, essa integração se parece com o seguinte:

compaypalerptransaction

Como podemos ver, o operador pode pesquisar por transações, listá-las, ver detalhes e, se for o caso, fazer a captura do valor ou até o estorno. Ao fazer a integração com o PayPal, a listagem depende da pesquisa que pode ser feita por vários critérios.

TransactionSearch

A operação TransactionSearch da API do PayPal permite que as aplicações enviem alguns campos que especificam os critérios da busca e retorna uma lista de transações que atendam à esses critérios.

Critérios de busca

Vou listar abaixo apenas alguns desses campos, para a listagem completa a página da documentação deve ser consultada: Documentação TransactionSearch.

  • STARTDATE – Esse é o único campo obrigatório e especifica a data inicial. Qualquer transação cuja data for maior ou igual a especificada em STARTDATE será retornada pelo PayPal.
  • ENDDATE – Ao contrário da STARTDATE, esse campo é opcional e especifica a data final. Qualquer transação que estiver entre a data inicial e a data final (inclusive) serão retornadas pela operação TransactionSearch.
  • EMAIL – O campo email é utilizado para pesquisar transações de um comprador específico, se informado, apenas as transações daquele comprador serão retornadas.
  • RECEIVER – Assim como o campo EMAIL, esse campo recebe um email, porém, o email do vendedor. Esse campo não é muito útil em lojas que operam com apenas 1 vendedor, mas em market places, que operam com vários vendedores, esse campo pode ser extremamente útil.
  • TRANSACTIONID – Sempre que uma transação é criada no PayPal, um identificador de transação é retornado para a aplicação. Para pesquisar uma transação específica, podemos informar o id dessa transação nesse campo.
  • TRANSACTIONCLASS – Existem diversas classes de transações e podemos pesquisar por transações que estejam em uma classe específica:
    • All – Vai retornar todas as transações, seria o mesmo que não enviar esse campo.
    • Sent – Somente transações de pagamentos enviados serão retornadas.
    • Received – Somente transações de pagamentos recebidos serão retornadas.
    • Refund – Somente transações envolvendo estornos.
  • AMT – Esse campo permite uma pesquisa pelo valor da transação.
  • CURRENCYCODE – Esse campo permite pesquisar as transações que foram feitas em uma determinada moeda (USD, BRL, etc.).
  • STATUS – Permite uma pesquisa pelo status da transação:
    • Pending – Vai retornar apenas as transações pendente de revisão.
    • Processing – Vai retornar apenas as transações que estão em processamento.
    • Success – Vai retornar apenas as transações bem sucedidas, ou seja, aquelas que o pagamento foi concluído e o dinheiro transferido para o vendedor.

Além dos campos relacionados com a transação, é possível especificar alguns dados com comprador:

FIRSTNAME, MIDDLENAME e LASTNAME – Esses campos podem ser utilizados para pesquisar pelo nome do comprador, seja o primeiro nome ou último nome.

Implementação

A operação TransactionSearch da API do PayPal oferece duas inferfaces distintas: NVP e SOAP. Apenas para simplificar essa postagem, vou tratar apenas da interface NVP, onde uma lista de pares nome=valor são enviados para o PayPal. A imagem abaixo ilustra a modelagem que será utilizada na implementação:

 

com.paypal.nvp

Como vamos utilizar a interface NVP da API do PayPal, vamos começar escrevendo o participante Nvp:

Nvp

A classe Nvp oferece uma associação parametrizada entre os campos de uma mensagem e seus valores em requisições ou respostas. NVP é uma forma de especificar os nomes e valores em uma string, é um nome informal para a parte “query” na especificação da URI, onde o par nome=valor é adicionado à URL.

Nvp.php

<?php
namespace paypal\nvp;

use \ArrayObject;

class Nvp extends ArrayObject
{
    /**
     * @var float
     */
    private $version = 91;

    /**
     * Converte o objeto Nvp em uma string representando a parte "query" na
     * especificação da URI.
     *
     * @return string
     */
    public function __toString()
    {
        $str = null;

        foreach ( $this as $name => $value ) {
            $str .= sprintf('%s=%s', $name, urlencode($value));
            $str .= '&';
        }

        $str .= 'VERSION=' . $this->version;

        return $str;
    }

    /**
     * @param string $name
     *            Nome do campo.
     * @return string O valor do campo.
     */
    public function get($name)
    {
        return isset($this[$name]) ? $this[$name] : null;
    }

    /**
     * @param string $name
     *            Nome do campo.
     * @return boolean O valor do campo.
     * @see Nvp::get()
     */
    public function getBool($name)
    {
        $v = $this->get($name);

        return $v !== null && ($v == '1' || $v == 'true');
    }

    /**
     * @param string $name
     *            Nome do campo.
     * @return integer O valor do campo.
     * @see Nvp::get()
     */
    public function getInt($name)
    {
        return (int) $this->get($name);
    }

    /**
     * @param string $name
     *            Nome do campo.
     * @return double O valor do campo.
     * @see Nvp::get()
     */
    public function getDouble($name)
    {
        return (double) $this->get($name);
    }

    /**
     * @param string $name
     *            O nome do campo.
     * @param mixed $value
     *            O valor do campo.
     */
    public function set($name, $value)
    {
        $this[$name] = $value;
    }

    /**
     * Define a versão da API.
     *
     * @param
     *            $version
     */
    public function setVersion($version)
    {
        $this->version = (float) $version;
    }
}

Transaction

A definição da classe Transaction é a mais simples possível. Como ela é uma derivação de Nvp, ela apenas utiliza os métodos já definidos para recuperar os dados utilizando nomes mais intuitívos:

Transaction.php

namespace paypal\nvp;

/**
 * Representação de uma transação.
 */
class Transaction extends Nvp
{
    /**
     * @return double Recupera o valor do pagamento.
     */
    public function getAmount()
    {
        return $this->getDouble('L_AMT');
    }

    /**
     * @return string O email do comprador ou do recebedor. Se o valor do
     *         pagamento for positivo, então é o email do recebedor.
     */
    public function getEmail()
    {
        return $this->get('L_EMAIL');
    }

    /**
     * @return double O valor da taxa.
     */
    public function getFeeAmount()
    {
        return $this->getDouble('L_FEEAMT');
    }

    /**
     * @return string O nome de exibição do comprador
     */
    public function getName()
    {
        return $this->get('L_NAME');
    }

    /**
     * @return double O valor líquido do pagamento.
     */
    public function getNetAmount()
    {
        return $this->getDouble('L_NETAMT');
    }

    /**
     * @return string O status da transação.
     */
    public function getStatus()
    {
        return $this->get('L_STATUS');
    }

    /**
     * @return string O timestamp do momento que a transação ocorreu.
     */
    public function getTimestamp()
    {
        return $this->get('L_TIMESTAMP');
    }

    /**
     * @return string O timezone da transação.
     */
    public function getTimezone()
    {
        return $this->get('L_TIMEZONE');
    }

    /**
     * @return string O identificador da transação
     */
    public function getTransactionId()
    {
        return $this->get('L_TRANSACTIONID');
    }

    /**
     * @return string O tipo da transação
     */
    public function getType()
    {
        return $this->get('L_TYPE');
    }
}

PayPalOperation

Agora que já temos a coleção de pares nome e valor, vamos definir uma abstração para uma operação da API.

PayPalOperation.php

<?php
namespace paypal;

use \ReflectionObject;
use \RuntimeException;
use \UnexpectedValueException;
use paypal\http\HTTPConnection;
use paypal\http\HTTPRequest;
use paypal\nvp\Nvp;

abstract class PayPalOperation
{
    /**
     * HOST PayPal de produção
     */
    const NVP_HOST = 'api-3t.paypal.com';

    /**
     * HOST PayPal de testes
     */
    const NVP_SANDBOX_HOST = 'api-3t.sandbox.paypal.com';

    /**
     * @var paypal\nvp\Nvp
     */
    protected $nvp;

    /**
     * @var paypal\nvp\Nvp
     */
    protected $responseNvp;

    /**
     * @var boolean
     */
    private $sandbox = true;

    /**
     * Constroi o objeto que representa uma operação da API do PayPal.
     *
     * @param string $user
     *            Usuário da API
     * @param string $pwd
     *            Senha da API
     * @param string $signature
     *            Assinatura da API
     */
    public function __construct($user, $pwd, $signature)
    {
        $this->nvp = new Nvp();
        $this->nvp->set('USER', $user);
        $this->nvp->set('PWD', $pwd);
        $this->nvp->set('SIGNATURE', $signature);
        $this->nvp->set('METHOD', $this->getMethod());
    }

    /**
     * Executa a operação.
     *
     * @return paypal/nvp/Nvp
     */
    public function execute()
    {
        $conn = $this->getConnection();

        foreach ( $this->nvp as $name => $value ) {
            $conn->setParam($name, $value);
        }

        $conn->setParam('VERSION', $this->nvp->getVersion());

        $httpResponse = $conn->execute('/nvp', HTTPRequest::POST);
        $matches = array();

        if (preg_match_all('/(?<name>[^\=]+)\=(?<value>[^&]+)&?/',
            $httpResponse->getContent(), $matches)) {

            $nvp = array();
            $version = null;

            foreach ( $matches['name'] as $offset => $name ) {
                if ($name == 'VERSION') {
                    $version = (float) $matches['value'][$offset];
                } else {
                    $nvp[$name] = urldecode($matches['value'][$offset]);
                }
            }

            $this->responseNvp = new Nvp($nvp);
            $this->responseNvp->setVersion($version);

            return $this->responseNvp;
        } else {
            throw new UnexpectedValueException('Resposta inesperada.');
        }
    }

    /**
     * Recupera o nome da operação.
     *
     * @return string
     */
    public function getMethod()
    {
        $r = new ReflectionObject($this);

        return $r->getShortName();
    }

    /**
     * Recupera o objeto de conexão HTTP.
     *
     * @return paypal\http\HTTPConnection
     */
    protected function getConnection()
    {
        $conn = new HTTPConnection();
        $conn->initialize(
            $this->sandbox ? self::NVP_SANDBOX_HOST : self::NVP_HOST, true);

        return $conn;
    }

    /**
     * Define o ambiente onde a operação será executada.
     *
     * @param boolean $sandbox
     *            TRUE fará com que a operação seja executada no
     *            Sandbox, FALSE no ambiente de produção.
     * @return paypal\PayPalOperation
     */
    public function sandbox($sandbox = true)
    {
        $this->sandbox = !!$sandbox;

        return $this;
    }
}

TransactionSearch

Com a base PayPalOperation definida, fica fácil definir qualquer operação que utiliza a interface NVP da API do PayPal. No caso da operação TransactionSearch só precisaremos definir uma forma para acessar a lista de operações e definir os critérios da busca:

TransactionSearch.php

<?php
namespace paypal;

use paypal\nvp\Transaction;

/**
 * A operação TransactionSearch da API do PayPal permite pesquisar por
 * transações utilizando vários critérios.
 */
class TransactionSearch extends PayPalOperation
{
    /**
     * @return array[paypal\nvp\Transaction] A lista de transações.
     */
    public function getTransactions()
    {
        $transactions = array();

        for($i = 0;; ++$i) {
            $timestamp = $this->responseNvp->get('L_TIMESTAMP' . $i);

            if ($timestamp == null) {
                break;
            } else {
                $rnvp = $this->responseNvp;

                $transactions[] = new Transaction(
                    array('L_TIMESTAMP' => $timestamp,
                        'L_TIMEZONE' => $rnvp->get('L_TIMEZONE' . $i),
                        'L_TYPE' => $rnvp->get('L_TYPE' . $i),
                        'L_EMAIL' => $rnvp->get('L_EMAIL' . $i),
                        'L_NAME' => $rnvp->get('L_NAME' . $i),
                        'L_TRANSACTIONID' => $rnvp->get('L_TRANSACTIONID' . $i),
                        'L_STATUS' => $rnvp->get('L_STATUS' . $i),
                        'L_AMT' => $rnvp->getDouble('L_AMT' . $i),
                        'L_FEEAMT' => $rnvp->getDouble('L_FEEAMT' . $i),
                        'L_NETAMT' => $rnvp->getDouble('L_NETAMT' . $i)
                    ));
            }
        }

        return $transactions;
    }

    /**
     * Define o valor da transação.
     *
     * @param float $amount
     */
    public function setAmount($amount)
    {
        $this->nvp->set('AMT', $amount);
    }

    /**
     * Define a moeda.
     *
     * @param string $currencyCode
     */
    public function setCurrencyCode($currencyCode)
    {
        $this->nvp->set('CURRENCYCODE', $currencyCode);
    }

    /**
     * Define o email do pagador.
     *
     * @param string $email
     */
    public function setEmail($email)
    {
        $this->nvp->set('EMAIL', $email);
    }

    /**
     * Define a data final.
     *
     * @param string $endDate
     */
    public function setEndDate($endDate)
    {
        $this->nvp->set('ENDDATE', $endDate);
    }

    /**
     * Define o número da fatura.
     *
     * @param string $invoiceNum
     */
    public function setInvoiceNum($invoiceNum)
    {
        $this->nvp->set('INVNUM', $invoiceNum);
    }

    /**
     * Define o identificador do recebimento.
     *
     * @param string $receiptId
     */
    public function setReceiptId($receiptId)
    {
        $this->nvp->set('RECEIPTID', $receiptId);
    }

    /**
     * Define o email do recebedor.
     *
     * @param string $receiver
     */
    public function setReceiver($receiver)
    {
        $this->nvp->set('RECEIVER', $receiver);
    }

    /**
     * Define a data inicial.
     *
     * @param string $startDate
     */
    public function setStartDate($startDate)
    {
        $this->nvp->set('STARTDATE', $startDate);
    }

    /**
     * Define o status da transação.
     *
     * @param string $status
     */
    public function setStatus($status)
    {
        $this->nvp->set('STATUS', $status);
    }

    /**
     * Define a classe da transação.
     *
     * @param string $transactionClass
     */
    public function setTransactionClass($transactionClass)
    {
        $this->nvp->set('TRANSACTIONCLASS', $transactionClass);
    }

    /**
     * Define o identificador da transação.
     *
     * @param string $transactionId
     */
    public function setTransactionId($transactionId)
    {
        $this->nvp->set('TRANSACTIONID', $transactionId);
    }
}

Retorno da API

Quando a operação TransactionSearch for chamada, uma lista de transações será retornada com os seguintes campos:

  • L_TIMESTAMPn – Informa o timestamp do momento que a transação foi criada.
  • L_TIMEZONEn – Informa o timezone da transação.
  • L_TYPEn – Informa o tipo da transação.
  • L_EMAILn – Informa o email do recebedor ou do pagador. Se o valor do pagamento for positivo, então esse email é do recebedor, do contrário é do pagador.
  • L_NAMEn – Informa o nome de exibição do comprador.
  • L_TRANSACTIONIDn – Informa o identificador da transação.
  • L_STATUSn – Informa o status da transação.
  • L_AMTn – Informa o valor bruto da transação, incluindo taxas e despesas de entrega.
  • L_FEEAMTn – Informa o valor de taxa da transação.
  • L_NETAMTn – Informa o valor líquido da transação.

Utilização

Para utilizar tudo isso podemos fazer assim:

codesample.php

<?php
$t = new TransactionSearch('usuario', 'senha', 'assinatura');

//busca por todas as transações ocorridas desde janeiro de 2013
$t->setStartDate('2013-01-01T00:00:00Z');

//executa a operação dentro do PayPal Sandbox
$t->sandbox()->execute();

//listando as transações encontradas
foreach ( $t->getTransactions() as $transaction ) {
    printf("Transação: %s\n", $transaction->getTransactionId());
    printf("Criação: %s\n", $transaction->getTimestamp());
    printf("Valor: %.02f\n", $transaction->getAmount());
}

d

é engenheiro de aplicações e trabalha com ambiente web desde 2000 em diversas linguagens, como Java e PHP, dedicando esforços ao desenvolvimento de bibliotecas reutilizáveis para a comunidade. Especialista em integração de sistemas, possui várias bibliotecas reutilizáveis publicadas como open-source para a comunidade, como biblioteca Cielo, PayPal, ECT (Correios), BuscaPé, Lomadee, Twitter, Facebook entre várias outras. É administrador do fórum iMasters e iMasters Code, onde compartilha conhecimento com a comunidade de desenvolvedores. Também é autor de cursos no iMasters PRO.

Ver perfil