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:
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:
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









