Dicas para quem quer integrar PayPal com Java

Olá, recentemente eu venho estudando esse assunto - integrar paypal com java - e obtive alguns resultados, agora quero compartilhar com vocês algumas dicas.

Existem várias maneiras de permitir o usuário comprar algo em seu site, a mais simples é colocando um botão no seu site desta maneira:

[code]

[/code]

Esse botão direciona o comprador para o site do paypal, note que o form está direcionando para sandbox (caixa de areia), este é um servidor de testes do paypal que funciona semelhante ao paypal real. Nos testes, obviamente, você não vai gastar dinheiro, então entre no site:

Cadastre-se e depois crie duas contas, uma busines e outra buyer ou personal. Existe a opção de criar uma conta pré-configurada, porém ela não vem com o username/password/assinatura da API (mais sobre isso depois), nesse caso é interessante criar uma conta busines do zero. Porém, eles pedem um zipcode real para um estado real e só pode ser dos EUA, o phone number tem que ser correspondente ao zipcode, procure na net números de telefone para o zipcode escolhido. Criando a conta para o buyer e o seller (comprador e vendedor) você já pode usar o botão acima e fazer as compras, e checar na sua conta do sandbox as transações feitas.

Mas esse botão só funciona quando tu não quer saber em tempo real se o usuário pagou, serve só pra quando tu checa seu email do paypal. E quando tu deseja ter o resultado da compra imediatamente!? Uma das soluções é usar IPN (Instant Payment Notification) configurando mais três campos no botão e também configurando na sua conta do paypal o endereço de retorno do IPN (sandbox vocÊ configura o endereço em Test Tools e vai em Simulate IPN). Agora o botão fica assim:

[code]













[/code]

Veja que está retornando para a página retorno.jsp. Essa jsp deve tratar do retorno do IPN, e deve ser semlhante a esta página:

[code]<%@ page import=“java.util." %>
<%@ page import="java.net.
” %>
<%@ page import=“java.io.*” %>

<%
System.out.println(“Entrou!!!”);
// read post from PayPal system and add ‘cmd’
Enumeration en = request.getParameterNames();
String str = “cmd=_notify-validate”;

while(en.hasMoreElements()) {
	String paramName = (String)en.nextElement();
	String paramValue = request.getParameter(paramName);
	str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue);
}

// post back to PayPal system to validate
// NOTE: change http: to https: in the following URL to verify using SSL (for increased security).
// using HTTPS requires either Java 1.4 or greater, or Java Secure Socket Extension (JSSE)
// and configured for older versions.
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
URLConnection uc = u.openConnection();
uc.setDoOutput(true);
uc.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
PrintWriter pw = new PrintWriter(uc.getOutputStream());
pw.println(str);
pw.close();

BufferedReader in = new BufferedReader(
new InputStreamReader(uc.getInputStream()));
String res = in.readLine();
in.close();

// assign posted variables to local variables
String itemName = request.getParameter("item_name");
String itemNumber = request.getParameter("item_number");
String paymentStatus = request.getParameter("payment_status");
String paymentAmount = request.getParameter("mc_gross");
String paymentCurrency = request.getParameter("mc_currency");
String txnId = request.getParameter("txn_id");
String receiverEmail = request.getParameter("receiver_email");
String payerEmail = request.getParameter("payer_email");

//check notification validation
if(res.equals("VERIFIED")) {
	// check that paymentStatus=Completed
	// check that txnId has not been previously processed
	// check that receiverEmail is your Primary PayPal email
	// check that paymentAmount/paymentCurrency are correct
	// process payment
	System.out.println(paymentStatus);
}
else if(res.equals("INVALID")) {
	// log for investigation
}
else {
	// error
}

%>[/code]

A primeira parte tu pega os parâmetros do request e envia pra eles de volta adicionando no fim: “cmd=_notify-validate”. Depois você testa a resposta e ve se foi verificado, caso for você checa o status da transação, em especial paymentStatus.

Porém, volte no botão de novo, veja que o usuário está vendo tudo, até o email do vendedor e a quantia. Para evitar isso tu deve encriptar o botão, que é meio complicado, uma soluçao seria criar esse botão e fazer o submit programaticamente em java, assim:

[code]
StringBuilder builder = new StringBuilder();
builder.append("");
builder.append("");
builder.append("<meta http-equiv=“content-type” content=“text/html; charset=”+resp.getCharacterEncoding()+" “>”
/response.ContentEncoding.BodyName/ );

    builder.append("</head>");
    builder.append("<body onLoad=\"document.forms[0].submit()\">");
    builder.append("<form name=\"formPaypal\" target=\"" + "_self" + "\"" + "action=\""+ "https://www.sandbox.paypal.com/cgi-bin/webscr" + "\" method=\"post\">");
    
    builder.append("<input type=\"hidden\" name=\"encoding\" value=\""+resp.getCharacterEncoding()+"\">"/*response.ContentEncoding.BodyName*/);
    
    builder.append("<input type=\"hidden\" name=\""+ "cmd" +"\" value=\"_xclick"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "business" +"\" value=\"email_do_vendedor@com"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "item_name" +"\" value=\"Nome produto"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "item_number" +"\" value=\"701"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "amount" +"\" value=\"20.00"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "no_shipping" +"\" value=\"2"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "no_note" +"\" value=\"1"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "currency_code" +"\" value=\"USD"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "return" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "cancel_return" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "notify_url" +"\" value=\"http://host/retorno.jsp"+ "" +"\">");
    builder.append("<input type=\"hidden\" name=\""+ "bn" +"\" value=\"PP-BuyNowBF"+ "" +"\">");
    
    builder.append("</form>");
    builder.append("</body>");
    builder.append("</html>");
    
    resp.getWriter().write(builder.toString());
    
    
    resp.getWriter().flush();
    resp.getWriter().close();[/code]

Isso deve ficar numa servlet. Veja que quando chamamos essa servlet ela mesma faz o POST simulando o click do botão.

Com isso já podemos vender algo, mas apesar disso tudo ser muito bonito, temos uma solução melhor ainda: usar SOAP. Eles disponibilizam 3 APIs Java NVP SOAP e WPS. Usando SOAP podemos pedir os dados da compra em nosso site e em background fazemos uma chamada as APIs do paypal SOAP para comunicar com o site deles e fazer o pagamento, sem botão e sem risco.
Para isso funcionar você precisa de um username/password/assinatura da api, só pode usar a API quem tem esses dados (senão qualquer progrmaador poderia acessar - através da API - a conta de qualquer um). Vamos ver um exemplo de SOAP.

[code]CallerServices caller = new CallerServices();
APIProfile profile = ProfileFactory.createSignatureAPIProfile();
/*
* WARNING: Do not embed plaintext credentials in your application
* code. Doing so is insecure and against best practices. Your API
* credentials must be handled securely. Please consider encrypting
* them for use in any production environment, and ensure that only
* authorized individuals may view or modify them.
*/

	// Set up your API credentials, PayPal end point, and API version.
	profile.setAPIUsername("username da API");
	profile.setAPIPassword("password da API");
	profile.setSignature("assinatura da api");
	profile.setEnvironment("sandbox");
	caller.setAPIProfile(profile);
	
	SetExpressCheckoutRequestType setRequest = new SetExpressCheckoutRequestType();
	SetExpressCheckoutRequestDetailsType setDetails = new
	SetExpressCheckoutRequestDetailsType();
	// DEFINE SOME BASIC CHECKOUT PARAMETERS
	setDetails.setReturnURL("url de retorno, na verdade uma ação ou servlet");
	setDetails.setCancelURL("cancel url");
	setDetails.setPaymentAction(PaymentActionCodeType.Sale);
	setDetails.setOrderDescription("description");
	// SET THE ORDER AMOUNT
	BasicAmountType amount = new BasicAmountType();
	amount.setCurrencyID(CurrencyCodeType.USD);
	amount.set_value("99.99");
	setDetails.setOrderTotal(amount);
	setRequest.setSetExpressCheckoutRequestDetails(setDetails);
	SetExpressCheckoutResponseType setResponse =
	(SetExpressCheckoutResponseType)caller.call("SetExpressCheckout", setRequest);
	// REDIRECT THE CUSTOMER TO PAYPAL?S WEBSITE FOR AUTHENTICATION
	String token = setResponse.getToken();
	response.sendRedirect("https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=" + token);[/code]

Pronto, isso redireciona o usuário pro site do paypal para ele confirmar o pagamento com sua conta no paypal.
O retorno que será também um servlet, servirá para terminar a compra e checar o status da transação. Veja abaixo.

[code]
try {

	CallerServices caller = new CallerServices();
	APIProfile profile = ProfileFactory.createSignatureAPIProfile();
	/*
	 * WARNING: Do not embed plaintext credentials in your application
	 * code. Doing so is insecure and against best practices. Your API
	 * credentials must be handled securely. Please consider encrypting
	 * them for use in any production environment, and ensure that only
	 * authorized individuals may view or modify them.
	 */

	// Set up your API credentials, PayPal end point, and API version.
	profile.setAPIUsername("...");
	profile.setAPIPassword("...");
	profile.setSignature("...");
	profile.setEnvironment("sandbox");
	caller.setAPIProfile(profile);
	
	GetExpressCheckoutDetailsRequestType getRequest = new
	GetExpressCheckoutDetailsRequestType();
	// GET THE SESSION TOKEN FROM THE HTTP REQUEST
	String token = request.getParameter("token");
	getRequest.setToken(token);
	// MAKE THE API CALL TO GET BUYER DETAILS
	GetExpressCheckoutDetailsResponseType getResponse =
	(GetExpressCheckoutDetailsResponseType)caller.call("GetExpressCheckoutDetails",
	getRequest);
	// EXTRACT SOME DATA ABOUT THE BUYER
	GetExpressCheckoutDetailsResponseDetailsType details =
	getResponse.getGetExpressCheckoutDetailsResponseDetails();
	String total = details.getCustom();
	PayerInfoType payer = details.getPayerInfo();
	String payerID = payer.getPayerID();
	PersonNameType name = payer.getPayerName();
	AddressType address = payer.getAddress();

	DoExpressCheckoutPaymentRequestType doRequest = new
	DoExpressCheckoutPaymentRequestType();
	DoExpressCheckoutPaymentRequestDetailsType doDetails = new
	DoExpressCheckoutPaymentRequestDetailsType();
	// SET DETAILS ABOUT THE FINAL TRANSACTION AMOUNT
	doDetails.setPayerID(request.getParameter("PayerID"));
	doDetails.setPaymentAction(PaymentActionCodeType.Sale);
	doDetails.setToken(token);
	PaymentDetailsType paymentDetails = new PaymentDetailsType();
	BasicAmountType  amount = new BasicAmountType();
	amount.setCurrencyID(CurrencyCodeType.USD);
	amount.set_value("10.00");
	paymentDetails.setOrderTotal(amount);
	doDetails.setPaymentDetails(paymentDetails);
	doRequest.setDoExpressCheckoutPaymentRequestDetails(doDetails);
	DoExpressCheckoutPaymentResponseType doResponse =
	(DoExpressCheckoutPaymentResponseType)caller.call("DoExpressCheckoutPayment", doRequest);
	DoExpressCheckoutPaymentResponseDetailsType details2 =
	doResponse.getDoExpressCheckoutPaymentResponseDetails();
	if (doResponse.getAck() == AckCodeType.Success) {
		System.out.println(
				"Status" +
				doResponse.getDoExpressCheckoutPaymentResponseDetails().
				getPaymentInfo().
				getPaymentStatus());
		
		Check.transactionId = doResponse.getDoExpressCheckoutPaymentResponseDetails().getPaymentInfo().getTransactionID();
		Check check = new Check();
		check.start();
		
		System.out.println("Sucesso na transacao");
	}
	} catch(PayPalException e) {
		e.printStackTrace();
	}[/code]

Isso vai mostrar pra você o status da transação, falta ainda criar a classe Check que será uma thread, ela fica verificando o status da transação, quando for “Completed” você libera oque tá vendendo! A classe check é mostrada a seguir:

[code]public class Check extends Thread {

static public String transactionId;
public Check() {
    
}

public void run() {
	while(true)  {
		System.out.println(getTransactionDetailsCode(transactionId));
		
		try {
			sleep(20000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

public String getTransactionDetailsCode(String transactionId)
{
	CallerServices caller = new CallerServices();
	String responseValue = null;
	try {
			
		APIProfile profile = ProfileFactory.createSignatureAPIProfile();
		/*
		 WARNING: Do not embed plaintext credentials in your application code.
		 Doing so is insecure and against best practices.
		 Your API credentials must be handled securely. Please consider
		 encrypting them for use in any production environment, and ensure
		 that only authorized individuals may view or modify them.
		 */

	// Set up your API credentials, PayPal end point, and API version.
		profile.setAPIUsername("...");
		profile.setAPIPassword("..");
		profile.setSignature("...");
		profile.setEnvironment("sandbox");
		caller.setAPIProfile(profile);
		
		GetTransactionDetailsRequestType pprequest = new GetTransactionDetailsRequestType();
		pprequest.setVersion("58.0");

	// Add request-specific fields to the request.
		pprequest.setTransactionID(transactionId);

	// Execute the API operation and obtain the response.
		GetTransactionDetailsResponseType ppresponse = 
		(GetTransactionDetailsResponseType) caller.call("GetTransactionDetails", pprequest);
		
		System.out.println(ppresponse.getPaymentTransactionDetails().getPaymentInfo().getPaymentStatus());
		
		responseValue = ppresponse.getAck().toString();
			
	}catch(Exception ex)
	{
		ex.printStackTrace();
	}
	
	return responseValue;
}

}[/code]

Bom, isso é o que tenho a dizer sobre o paypal…

Muito legal os exemplos mas é importante lembrar que o paypal também tem outros produtos, sendo que para o Brasil, por enquanto, o “X” também estará disponível.

Acho que é importante também dar uma olhada nas diferenças entre “sales” (venda única) e “orders” (pedidos com multiplos itens/envios e capturas)

Prezados,

Muito bom o post, porém eu não consigo utilizar algo tipo um .jar ou api enfim algo que eu adicione a aplicação e possa fazer esta integração?

Se conhecerem algum link com ensinamentos começando do zero por favor informe.

desde já obrigado.

jeroqueiroz,

Dá uma olhada aqui: https://www.x.com/developers/paypal/documentation-tools/sdk

todas as SDKs do PayPal nesta página.

recomendo uma passada no paypal-brasil.com.br/x - lá tem um forum em português e você pode mandar dúvidas para o suporte ao desenvolvedor.

Acho que o mais complicado mesmo é o fato do PayPal ter muito mais opções que os concorrentes e distribuídos em 3 plataformas distintas.

Qual o mercado que você está trabalhando? Bens físicos, digitais, etc - físicos vá para WPS ou EC, digitais, dá uma olhada no Adaptive.

Qual volume de transações? estamos falando de dezenas/centenas ou milhares/milhões? dezenas WPS leva bem, milhares o ideal é usar solução API - EC ou Adaptive

Prezado fguazzel,

Gostaria de agradecer desde já sua ajuda atenção.

Quanto a URL que você mandou já estava até baixando a SDK, porém meio confuso.

A situação é a seguinte.

É um site de venda de serviços mensais o qual ainda não tenho como mensurar a rotatividade, mas será feito para algo de médio a grande porte.

O Cliente compra um serviço e ele pagará todo mês por aquele serviço, logo se ele modifica um serviço para mais configurações no mês, deverá ser cobrado um pro-rata do dia de inicio do serviço utilizando X + o restante dos dias após a modificação utilizando Y.

Este controle do que vai ser pago eu controlo na minha aplicação, correto?

Todo mês terei que mandar uma lista com os valores e dados de cada cliente para o serviço do PayPal correto?

Quanto ao serviço do PayPal qual o indicado a ser utilizado?

Se puder responder estes três questionamentos acima fico grato.

Oi Jeremias,

pelo que entendi o seu caso é um bem “intangível” e como você tem um valor mensal variável a minha recomendação é fazer a recorrência do seu lado usando o "pre approved payments"do AdaptivePayments: https://www.x.com/developers/paypal/documentation-tools/api/preapproval-api-operation

O que é legal do modelo - o cliente fará apenas 1 passagem do PayPal e daí para frente não terá qualquer interação, você poderá cobrá-lo a qualquer momento.

A parte ruim (e acredito que não tem como escapar disso) - Seu modelo, pelo que entendi, é pós-pago, ou seja, você pode ter problemas para cobrar a pessoa - ela pode não ter crédito no cartão no momento da captura - a vantagem deste modelo é que você tem esse controle. Outro problema que você deve estar atento é que o perfil de pré-aprovação pode ser cancelado na conta PayPal.

fguazzel,

Entendi a API que você falou, porém estou com duvidas sobre a forma de integrar o PayPal a Aplicação.

Sobre o uso do SDK você teria como ajudar como faço esta integração e qual dos SDK devo utilizar?

Agradeço sua ajuda, pois estou olhando no link que você postou, porém são muitas e fiquei confuso qual devo utilizar.

você deve escolher uma dessas:

https://www.x.com/developers/paypal/documentation-tools/sdk#2

aí você escolhe o “sabor” da implementação - NVP, SOAP, JSON ou XML.

Eu costumo usar NVP, mas isso é uma questão de gosto :stuck_out_tongue:

Vou tentar utilizar aqui…

Qualquer dúvida volto a postar, desde já muito obrigado.

Junto com a SDK vem vários modelos de como usar. dá uma olhada lá e qquer problema avise.

Prezado fguazzel,

Já percorri o fórum e alguns materiais, baixei o SDK que terei que usar JSON, porém estou perdido como devo usar…

Após baixar o SDK eu adiciono ao projeto Web que tenho?

Estou tendo dificuldades sobre a forma de implementação, achei um meio confuso.

Já sei qual terei que usar, agora queria saber com usar o mesmo no eclipse, onde tenho atualmente minha aplicação web que terei que integrar.

Agradeço a atenção.

Alguma informação?

Qualquer ajuda é bem vinda.

Dá uma olhada no paypal-brasil.com.br/x acho que lá poderão ajudar.

Obrigado!

Estou vendo com o pessoa e voltarei a postar aqui o resultado.

Estou usando o SDK do Paypal utilizando JSON, consegui fazer a comunicação e até envio usando Java Application, porém enviar através da web (redirecionar) o cliente através da própria aplicação, não obtive sucesso.

Algum pode dar algum ajuda sobre?

Gostaria de saber dos amigos do fórum, se eu estou equivocado quando li em algum lugar que não era necessário o cliente possuir uma conta no PayPal?!?

abraço

Esta certo, é uma das formas de integração do Paypal, pois o cliente pode comprar pela opção do paypal usando boleto bancário e não terá necessidade de criação de uma conta.

Valeu!

Caro Jeremias,

Estou tetando a opção Express Checkout, do ponto de vista das integrações, parece que tudo funciona, porém, quando vou acessar a página do seller e do buyer que utilizo no Sandbox, não aparece nenhuma movimentação financeira…você tem experiência nisso?

um abraço

Fiz algumas integrações, com PHP e com Java…

Como você esta usando e qual linguagem esta utilizando?