Hoje a idéia é falar da integração com o PagSeguro do UOL através do nosso ColdFusion. O primeiro desafio é documentação em ColdFusion, que por ser uma linguagem extremamente fácil e produtiva, as pessoas acabam esquecendo de criar documentação, meu objetivo é mudar isso radicalmente.
Para a integração, vamos precisar de dois manuais no site do PagSeguro. O primeiro é o da integração com Carrinho Próprio e o segundo que é o Retorno Automático de Dados
Apenas lembrando que a mágica depende da configuração correta na sua conta PagSeguro, se você ainda não o fez ou quer revizar vamos aos passos:
- Criar uma conta no PagSeguro
- Se for usar a conta em produção, é bom validar os dados.
- Lembre-se de configurar o Frete, no menu Preferências/Frete
- Defina o link para o Retorno Automático de Dados, e gere o Token no menu Preferências/Retorno automático de dados
Para este post vamos fazer o modelo de enviarmos todos os dados, até porque você provavelmente nesse ponto, já esta com o usuário logado no seu e-commerce e cadastrado. Lembre-se, esse é o momento de finalização da compra, então você já deve verificar seu estoque e estar com tudo pronto.
Para facilitar nossa vida, vamos criar um novo componente chamado PagSeguro.cfc, que espero que ajude na integração da maioria dos projetos. Os métodos que percebi são:
- setCart: vai ser o método responsável por receber os dados a serem enviados ao PagSeguro;
- setType: para informar o tipo do carrinho, seja próprio, ou PagSeguro
- setCoin: serve para informar o tipo de moeda, hoje o pagSeguro só trabalha com Real
- setExtras: será utilizado para valores adicionais ou descontos
- setClient: irá servir para informar os dados do fulano que esta fazendo a compra
- setShipping: informaremos o tipo de envio do produto
- parseCurrency: esse método irá converter o valor para o padrão PagSeguro
- send: esse método irá realizar a mágica de enviar os dados para o PagSeguro
1: <cfset Variables.ACTION = "https://pagseguro.uol.com.br/checkout/checkout.jhtml" />
2: <cfset Variables.dsEmail = "EMAIL_CADASTRADO_PAGSEGURO" />
3: <cfset Variables.tpCart = "CP" />
4: <cfset Variables.tpCoin = "BRL" />
5: <cfset Variables.tpShipping = "UC" />
6: <cfset Variables.vlExtras = 0 />
7: <cfset Variables.userData = structNew()>
8: <cfset variables.cart = ArrayNew(1) />
É importante lembrar que um componente deve ser simples a ponto de não termos que "adaptar" nossa programação ao funcionamento dele.
setCart
1: <cffunction name="setCart" access="public" returntype="void" output="false">
2: <cfargument name="cart" type="ShoppingCart" required="true">
3: <cfargument name="nmLogin" type="String" default="" required="false">
4:
5: <cfif len(trim(arguments.nmLogin)) and isValid("email", arguments.nmLogin)>
6: <cfset Variables.dsEmail = arguments.nmLogin />
7: </cfif>
8: <cfset variables.cart = Arguments.cart.list()>
9: </cffunction>
Muitos podem achar que o post sai do nada, porém antes de começar essa maratona, desenhei todo o fluxo UML para o nosso projeto. O único motivo dos arquivos estarem todos juntos é para facilitar o entendimento e ajudar vocês a executarem o projeto em seu próprio servidor local.
Na verificação do login, repare que não faço uso de isDefined ou structKeyExist, isso, porque defini o cfargument com a propriedade default="", que faz o nosso cfargument funcionar como um cfparam, cria a variável que você pediu com um valor padrão, caso ela não exista. Com isso, verificamos se a quantidade de caracteres é superior a zero e se o valor que temos em mãos é um e-mail.
A técnica do len(trim("STRING")) é baseada numa regra da lógica boleana que diz "Todo número diferente de zero verdadeiro". Cuidado com as entrelinhas, 1 e -1 são verdadeiro apenas 0 é falso.
A função isValid do ColdFusion é uma das mais legais e menos conhecidas, vale a pena dar uma olhada na documentação, para as possibilidades!
setType
1: <cffunction name="setType" access="public" returntype="void" output="false">
2: <cfargument name="type" type="string" required="true">
3: <cfset var lValidTypes = "CP,CBR">
4: <cfif listContainsNoCase(lValidTypes, arguments.type)>
5: <cfset Variables.tpCart = arguments.type>
6: <cfelse>
7: <cfset Variables.tpCart = listFirst(lValidTypes)>
8: </cfif>
9: </cffunction>
setCoin
1: <cffunction name="setCoin" access="public" returntype="void" output="false">
2: <cfargument name="coin" type="string" required="true">
3: <cfset var lValidTypes = "BRL">
4: <cfif listContainsNoCase(lValidTypes, arguments.coin)>
5: <cfset Variables.tpCoin = arguments.type>
6: <cfelse>
7: <cfset Variables.tpCoin = listFirst(lValidTypes)>
8: </cfif>
9: </cffunction>
setExtras
1: <cffunction name="setExtras" access="public" returntype="void" output="false">
2: <cfargument name="value" type="numeric" required="true">
3: <cfargument name="isDiscount" type="boolean" default="false" required="false">
4:
5: <cfif arguments.isDiscount>
6: <cfset Variables.vlExtras = arguments.value * -1>
7: <cfelse>
8: <cfset Variables.vlExtras = arguments.value>
9: </cfif>
10: </cffunction>
Pensando nisso, o método recebe o valor e um boleano informando se é desconto ou não. Isso evita que você tenha que fazer a conversão de desconto
setClient
1: <cffunction name="setClient" access="public" returntype="void" output="false">
2: <cfargument name="nmPerson" type="string" required="true">
3: <cfargument name="dsEmail" type="string" required="true">
4: <cfargument name="nbPostalCode" type="string" required="true">
5: <cfargument name="dsAddress" type="string" required="true">
6: <cfargument name="dsDistrict" type="string" required="true">
7: <cfargument name="dsCity" type="string" required="true">
8: <cfargument name="cdState" type="string" required="true">
9: <cfargument name="cdDDD" type="numeric" required="true">
10: <cfargument name="nbTelephone" type="string" required="true">
11: <cfargument name="nbAddress" type="string" required="false" default="S/N">
12: <cfargument name="dsComplement" type="string" required="false" default="">
13: <cfargument name="cdCountry" type="string" required="false" default="BRA">
14:
15: <cfset Variables.userData.nmPerson = arguments.nmPerson>
16: <cfset Variables.userData.dsEmail = arguments.dsEmail>
17: <cfset Variables.userData.nbPostalCode = arguments.nbPostalCode>
18: <cfset Variables.userData.dsAddress = arguments.dsAddress>
19: <cfset Variables.userData.dsDistrict = arguments.dsDistrict>
20: <cfset Variables.userData.dsCity = arguments.dsCity>
21: <cfset Variables.userData.cdState = arguments.cdState>
22: <cfset Variables.userData.cdDDD = arguments.cdDDD>
23: <cfset Variables.userData.nbTelephone = arguments.nbTelephone>
24: <cfset Variables.userData.nbAddress = arguments.nbAddress>
25: <cfset Variables.userData.dsComplement = arguments.dsComplement>
26: <cfset Variables.userData.cdCountry = arguments.cdCountry>
27: </cffunction>
setShipping
1: <cffunction name="setShipping" access="public" returntype="void" output="false">
2: <cfargument name="shipping" type="string" required="true">
3: <cfset var lValidTypes = "UC,EN,SD">
4: <cfif listContainsNoCase(lValidTypes, arguments.shipping)>
5: <cfset Variables.tpShipping = arguments.type>
6: <cfelse>
7: <cfset Variables.tpShipping = listFirst(lValidTypes)>
8: </cfif>
9: </cffunction>
parseCurrency
1: <cffunction name="parseCurrency" access="private" returntype="String" output="false">
2: <cfargument name="value" type="numeric" required="yes">
3:
4: <cfset var strResult = LSCurrencyFormat(Arguments.value, "none")>
5: <cfset strResult = trim(REReplace(strResult, "[^[:digit:]]", "", "ALL"))/>
6: <cfreturn strResult>
7: </cffunction>
send
Por último e talvez mais importante, a nossa "fronteira final" que é o envio dos dados para após a operação termos o nosso retorno automático.
Muitos podem pensar de cara em usar o cfhttp para envio dos dados, mas no caso do pagSeguro, o objetivo é ser uma ferramenta simples a ponto do usuário que só sabe html, também possa usar. Para o mundo ColdFusion o CFHTTP soa até natural, porém em linguens como .NET, PHP e Java a coisa não é tão simples.
Por conta disso, o envio é feito por um formulário simples o que gera algumas dores de cabeça com pessoas fazendo compras sem passar pelo seu site. A solução proposta pelo pagseguro é a utilização do token, que eu recomendo trocar pelo menos uma vez por mês ou ao dia dependendo do volume da acessos do seu e-commerce. Depois se vocês desejarem, podemos fazer uma ferramenta com essa finalidade.
1: <cffunction name="send" access="public" returntype="string" output="no">
2: <cfargument name="idTransaction" type="string" required="false" default="">
3: <cfsavecontent variable="returnVal">
4: <cfoutput>
5: <form id="frmPagSeguro" action="#Variables.action#" method="post">
6: <input type="hidden" name="encoding" value="#Variables.ENCODING#">
7: <input type="hidden" name="email_cobranca" value="#Variables.dsEmail#">
8: <input type="hidden" name="tipo" value="#Variables.tpCart#">
9: <input type="hidden" name="moeda" value="#Variables.tpCoin#">
10:
11: <cfif len(trim(arguments.idTransaction))><input type="hidden" name="ref_transacao" value="#arguments.idTransaction#"></cfif>
12: <cfif Variables.tpShipping NEQ "UC"><input type="hidden" name="tipo_frete" value="#Variables.tpShipping#"></cfif>
13: <cfif Variables.vlExtras NEQ 0><input type="hidden" name="extras" value="#parseCurrency(Variables.vlExtras)#"></cfif>
14:
15: <cfloop from="1" to="#ArrayLen(variables.cart)#" index="i">
16: <input type="hidden" name="item_id_#i#" value="#variables.cart[i].idItem#">
17: <input type="hidden" name="item_descr_#i#" value="#variables.cart[i].nmItem#">
18: <input type="hidden" name="item_quant_#i#" value="#variables.cart[i].qtItem#">
19: <input type="hidden" name="item_valor_#i#" value="#parseCurrency(variables.cart[i].vlItem)#">
20: <cfif variables.cart[i].flFreeShipping>
21: <input type="hidden" name="item_frete_#i#" value="0">
22: <input type="hidden" name="item_peso_#i#" value="0">
23: <cfelse>
24: <input type="hidden" name="item_peso_#i#" value="#variables.cart[i].nbWeight#">
25: </cfif>
26: </cfloop>
27: <cfif NOT structIsEmpty(Variables.userData)>
28: <input type="hidden" name="cliente_nome" value="#Variables.userData.nmPerson#">
29: <input type="hidden" name="cliente_email" value="#Variables.userData.dsEmail#">
30: <input type="hidden" name="cliente_cep" value="#Variables.userData.nbPostalCode#">
31: <input type="hidden" name="cliente_end" value="#Variables.userData.dsAddress#">
32: <input type="hidden" name="cliente_num" value="#Variables.userData.nbAddress#">
33: <input type="hidden" name="cliente_compl" value="#Variables.userData.dsComplement#">
34: <input type="hidden" name="cliente_bairro" value="#Variables.userData.dsDistrict#">
35: <input type="hidden" name="cliente_cidade" value="#Variables.userData.dsCity#">
36: <input type="hidden" name="cliente_uf" value="#Variables.userData.cdState#">
37: <input type="hidden" name="cliente_pais" value="#Variables.userData.cdCountry#">
38: <input type="hidden" name="cliente_ddd" value="#Variables.userData.cdDDD#">
39: <input type="hidden" name="cliente_tel" value="#Variables.userData.nbTelephone#">
40: </cfif>
41: </form>
42: </cfoutput>
43: <script type="text/javascript">1:
2: var objForm = document.getElementById("frmPagSeguro");3: objForm.submit();
4:
</script>
44: </cfsavecontent>
45: <cfreturn returnVal>
46: </cffunction>
Com isso estamos integrados ao PagSeguro, a página pagSeguro.cfm mostra, como o envio fica realmente simples.
pagSeguro.cfm
1: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2: <html xmlns="http://www.w3.org/1999/xhtml">
3: <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4: <title>Confirmação de Compra</title>
5: </head>
6: <body>
7: <cfsetting showdebugoutput="false">
8: <cfset aCart = session.shoppingCart.list()>
9: <table border="1">
10: <thead>
11: <tr>
12: <th>Cód</th>
13: <th>Nome</th>
14: <th>Valor</th>
15: <th>Quantidade</th>
16: <th>Sub-Total</th>
17: </tr>
18: </thead>
19: <tfoot>
20: <tr>
21: <td colspan="5"><strong>Valor Total:</strong><cfoutput>#lsCurrencyFormat(session.shoppingCart.getTotal())#</cfoutput></td>
22: </tr>
23: </tfoot>
24: <cfoutput>
25: <tbody>
26: <cfloop array="#aCart#" index="cartItem">
27: <tr>
28: <td>#cartItem.cdItem#</td>
29: <td>#cartItem.nmItem#</td>
30: <td>#lsCurrencyFormat(cartItem.vlItem)#</td>
31: <td>#cartItem.qtItem#</td>
32: <td>#lsCurrencyFormat(cartItem.vlTotalItem)#</td>
33: </tr>
34: </cfloop>
35: </tbody>
36: </cfoutput>
37: </table>
38: <form method="post">
39: <input type="submit" name="go" value="Confirmar Compra"/>
40: </form>
41: <cfif structKeyExists(form, "go")>
42: <cfset objPagSeguro = createObject("component", "PagSeguro")>
43: <cfset objPagSeguro.setCart(session.shoppingCart)>
44: <cfset objPagSeguro.setClient("Rafael Bandeira Rodrigues"
45: , "rafael_rodrigues@flagnet.inf.br"
46: , "00000000"
47: , "R. Onde eu moro"
48: , "Bairro"
49: , "Rio de Janeiro"
50: , "RJ"
51: , "21"
52: , "3333-3333")>
53: <cfoutput>#objPagSeguro.send()#</cfoutput>
54: </cfif>
55:
56: </body>
57: </html>
E finalmente, para quem cansou de ler, esta tudo pronto para download no link http://www.flagnet.inf.br/downloads/shoppingCart-part2.rar
Nenhum comentário:
Postar um comentário