Mostrando postagens com marcador validações. Mostrar todas as postagens
Mostrando postagens com marcador validações. Mostrar todas as postagens

segunda-feira, 26 de março de 2012

Adobe Shadow - Novidades para Mobile Dev

Para quem trabalha com desenvolvimento web em mobiles, já deve ter notado quanto tempo se perde em ter um ambiente de testes, muitas vezes temos que colocar o aparelho dentro da rede local e algumas empresas acham que o celular pessoal do desenvolvedor vem no pacote de desenvolvimento.

Tirando esses fatos corporativos e de falta de noção para com a realidade, o processo de testes dentro dos aplicativos normalmente é afetado pelos emuladores, que muitas vezes apenas simulam o tamanho de tela. Mas como saber se o resultado esperado será o mesmo no produto final?

Recentemente a Adobe publicou um prodto novo no Labs (http://labs.adobe.com), o Shadow, com certeza um nome novo será dado a ele, mas o importante mesmo é o que o programa se dispoém a fazer.

A instalação é dependente de três etapas, uma instalação no desktop, uma instalação no brwoser e um App no smartphone. Ná instalação desktop, processo normal NNF para windows e Mac. No browser, a instalação de uma extenção para o Google Chrome é necessária e só funciona nele. No smartphone você precisa ter um IOS ou um Android.

O que eu achei mais legal é o fato de você usar o navegador normalmente, ir alternando abas e o conteudo ser atualizado em tempo real, ou seja a emulação é quase perfeita, só faltando o teste final no navegador do aparelho para garantir que no final de tudo certo.

Ficou curioso? então da uma olhada e teste você mesmo.

http://labs.adobe.com/downloads/shadow.html

quarta-feira, 17 de agosto de 2011

Porque não se usa Plataforma WEB para Processamento de Dados

Noite sem sono é bom para escrever e ver o que as pessoas andam falando. Agora a pouco vi uma pessoa na lista de ColdFusion, questionando o porque não se deve usar plataformas web para processamento de dados.

Bom com isso me lembrei dos tempos de segundo grau e faculdade, quando os professores falavam do assundo, e eu me esforçava para não dormir e tentar acompanhar o raciocínio.

Por sorte consegui entender e vou tentar passar o cenário da forma mais clara possível.

Quando se fala em "Processamento de Dados", estamos falando do ato de pegar dados recebidos, seja qual for o meio e processa-los para gerar informação. Com isso você vai pensar "Isso eu faço com ColdFusion, Railo, PHP, ASP, ASP.NET, JSP, etc...", e você esta certo em pensar isso.

Por outro lado, linguagens como as que eu mencionais e outras voltadas a internet possuem um fluxo de processamento próprio, todas elas vão depender de uma especificação em comum, devem estar associadas a um servidor web e serão obrigatóriamente executadas através de um navegador.

Para se processar dados temos como fluxo primário um arquivo de lote ou batch que deverá seguir um padrão que deve ser estabelecido, analisado e testado de forma a não ter necessidade de modificações que afetem versões anteriores e que levem o menor tempo possível para serem processados.

Com os dias de hoje onde tudo gira em torno de tecnologia, esses dois conceitos acabam se perdendo e tendo que ser relembrados a todo momento.

Quando se desenvolve um sistema, seja ele Mobile, Desktop ou Web, temos que realizar algo chamado analise de sistema, é onde se pensa em todo o sistema, como ele vai funcionar, quantos usuários simultaneos teremos, consumo de bande etc. Com a pratica de pastelaria de mercado, essa etapa que pode levar entre um mês até seis meses é simplesmente ignorada, e é iniciado o processo de remendos, onde a cada problema no desenvolvimento, cria-se uma forma de contornar o problema.

Essa prática, normalmente geram projetos de baixo custo e alto risco ao usuário final e aplicamos o antigo ditado popular "o barato, sai caro".

O processamento em lingaguem web não deve ser feito para não existirem erros externos como o servidor web parar, a conexão cair e coisas do tipo, a diferença é simples: O que é melhor? Mudar o canal no controle remoto da sua TV ou todas as vezes levantar do sofá para faze-lo? Ambos levam o mesmo resultado, mas em um dia de muito frio, ou quando se estiver impossibilidado de levantar do sofá por qualquer motivo, você vai pensar "Porque não me preocupei com o controle remoto".

Imagine que os dados a serem processados estão dentro de uma base em um ambiente seu, porque acessar uma página web para recuperar dados dentro do seu servidor? Porque parar o processamento quando a internet cair, se seu acesso todo é local e pior, porque consimir banda para acessar dados locais? É como tirar o carro da garagem para visitar o visinho da esquina.

Uma vez entendido o porque não fazer, vem a pergunta: E o que eu devo usar para processar os dados?

Para as pessoas que trabalham com hospedagem compartilhada e precisam fazer esse processo, a melhor opção é criar uma stored procedure na sua base de dados para realizar o processamento de dados, se seu banco de dados não tem esse suporte só posso dizer "O barato sai caro".

Para pessoas que tem servidores próprios, como VPS, Dedicados, Semi-Dedicados, Clouds etc, a melhor opção é criar um programa para ser instalado no servidor que vai fazer esse processo, afinal o banco de dados, deve apenas, validar e armazenar e não processar dados.

Com relação a linguagens para se fazer isso, as opções são muitas, mas se sua praia é web as melhores opções são: o ActionScript 3 utilizando o Adobe Air (para todas as linguagens), Java (para programadores jsp, java e ColdFusion), C ou C++ (para programadores PHP ou ColdFusion) ou .NET (para programadores .NET ou ColdFusion).

sexta-feira, 3 de junho de 2011

Carrinho de Compras - Parte 2.1 (Integração com PagSeguro do UOL - Retorno Automático)

Como eu tinha prometido vamos continuar com a série "Carrinho de Compras", quem não viu o primeiro post Carrinho de Compras - Parte 1 e Parte 2 recomendo dar uma olhada apenas para ter uma idéiade como nosso carrinho funciona e em que ponto estamos.

Ontem finalizamos o envio de dados para o PagSeguro do UOL e hoje (que rufem os tambores), vamos falar do Retorno Automático do PagSeguro.

Para isso, precisamos primeiro saber como ele funciona e definir nossa URL DE RETORNO e o TOKEN. Esse procedimento, tenta evitar dores de cabeça de pessoas comprando sem estar na sua loja. Como vimos ontem, o pagseguro, só pede um form com submit sem nenhum tipo de validação.

A validação acontece, quando o PagSeguro gera a "pergunta", que no caso chamamos de Retorno Automático. Uma observação, nesse caso seus testes devem ser online, pois vamos usar a session da sua aplicação para verificar e validar dos dados a serem confirmados com a URL de Retorno.

Para este processo vamos criar um novo componente e vamos chama-lo de PagSeguroRetorno.cfc. Este compoennte será usado na nossa página de retorno, e irá disparar ações de confirmação dos dados da compra.

PagSeguroRetorno.cfc
   1: <cfset Variable.COMMAND = "validar">
   2: <cfset Variables.VALIDATOR_URL = "https://pagseguro.uol.com.br/pagseguro-ws/checkout/NPI.jhtml">
   3: <cfset Variables.TOKEN = "SEU_TOKEN" />
   4: <cfset Variables.dsEmail = "EMAIL_CADASTRADO_PAGSEGURO" />
   5: <cfset Variables.result = structNew()>
Iniciamos o processo com nossas váriaveis que serão manipuladas pelo componente.

setReturn
   1: <cffunction name="setReturn" access="public" returntype="void" output="false">
   2:     <cfargument name="data" type="struct" required="true">
   3:     <cfset var arrForm = listToArray(arguments.data.FieldNames)>
   4:     <cfloop array="#arrForm#" index="currentItem">
   5:         <cfset Variables.result["#currentItem#"] = arguments.data[currentItem]>
   6:     </cfloop>
   7: </cffunction>
Criamos um método setReturn, que será responsável por receber o retorno do PagSeguro e manipular este resultado de acordo com nossa necessidade. Nesse momento, apenas nos preocupamos com guardar a informação. Para evitar um monte de linhas, realizamos um loop sobre a estrutura de dados recebida, guardando os dados na estrutura result.

confirm
   1: <cffunction name="confirm" access="public" returntype="void" output="false">
   2:     <cfhttp url="#VALIDATOR_URL#" method="get" resolveurl="false" charset="iso-8859-1">
   3:         <cfhttpparam name="Comando" type="url" value="#Variables.COMMAND#">
   4:         <cfhttpparam name="Token" type="url" value="#Variables.TOKEN#">
   5:         
   6:         <cfloop collection="variables.result" item="currentItem">
   7:             <cfhttpparam name="#currentItem#" type="url" value="#variables.result[currentItem]#">
   8:         </cfloop>
   9:     </cfhttp>
  10:     <cfswitch expression="#trim(cfhttp.FileContent)#">
  11:         <cfcase value="VERIFICADO">
  12:         <!--- Verifique se a TransacaoID não foi previamente processada --->
  13:         <!--- Verifique se o email recebido (VendedorEmail) é o seu email --->
  14:         <!--- Verifique se o valor do pagamento está correto --->
  15:         <!--- Processe o pagamento salvando os dados em seu banco de dados --->
  16:             <cfset FileWrite("#getDirectoryFromPath(expandPath('*.*'))#FORM_TRUE#DateFormat(Now(), 'yyyy-mm-dd-hh-mm-ss')#.htm", value)>
  17:         </cfcase>
  18:         <cfcase value="FALSO">
  19:             <!--- A Requisição não foi confirmada pelo PagSeguro e pode ser uma compra falsa --->
  20:             <cfset FileWrite("#getDirectoryFromPath(expandPath('*.*'))#FORM_FALSE#DateFormat(Now(), 'yyyy-mm-dd-hh-mm-ss')#.htm", value)>
  21:         </cfcase>
  22:     </cfswitch>
  23: </cffunction>
Finalmente, de posse dos dados, realizamos a confirmação. Para isso, enviamos um post com o comando Validar e nosso Token, junto com os dados da compra.

Lembrando que aqui estamos tratando de um exemplo, no mundo real, antes de informar a validação, verificamos o id da nossa transação no e-commerce e se o carrinho é igual ao que temos no site, para só então verificarmos se os dados conferem com a informação do PagSeguro, guardando as informações adicionais.

retornoPagSeguro.cfm
   1: <cfif structKeyExists(Form, "FieldNames")>
   2:     <cfset objPagSeguroReturn = createObject("component", "PagSeguroRetorno")>
   3:     <cfset objPagSeguroReturn.setReturn(form)>
   4:     <cfset objPagSeguroReturn.confirm()>
   5: </cfif>
Este código, deve ir na sua página de retorno, a mesma que você informou para o PagSeguro. Nesse momento, verificamos se recebemos algum retorno de POST e em seguida, iniciamos nosso componente PagSeguroRetorno.cfc informando o retorno que recebemos e confirmando a transação.

Bom é isso, espero ter ajudado alguém com este tutorial e agora só volto na próxima quarta-feira, falando da integração com Pagamento Digital do Buscapé.

E finalmente, para quem cansou de ler, esta tudo pronto para download no link http://www.flagnet.inf.br/downloads/shoppingCart-part2.1.rar

quinta-feira, 2 de junho de 2011

Carrinho de Compras - Parte 2 (Integração com PagSeguro do UOL)

Como eu tinha prometido vamos continuar com a série "Carrinho de Compras", quem não viu o primeiro post Carrinho de Compras - Parte 1, recomendo dar uma olhada apenas para ter uma idéiade como nosso carrinho funciona.

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:

  1. Criar uma conta no PagSeguro
  2. Se for usar a conta em produção, é bom validar os dados.
  3. Lembre-se de configurar o Frete, no menu Preferências/Frete
  4. Defina o link para o Retorno Automático de Dados, e gere o Token no menu Preferências/Retorno automático de dados
 Após esses passos simples, vamos a parte código da nossa integração. Na página de integração com o carrinho, é explicado que você tem duas opções para o envio de dados do comprador. Uma você deixa isso a cargo do PagSeguro, e outra você realiza este envio.

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
 PagSeguro.cfc
   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) />
Ao iniciar nosso processo, criamos algumas váriaveis que serão controladas pelos nossos métodos antes do envio. Algumas delas, já definimos um valor padrão, para evitar falhas ou necessidades de formas de uso na programação.

É 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>
Algumas observações e curiosidades para o nosso setCart. De cara algo diferente no atributo type da nossa cfargument. O tipo requerido para o nosso carrinho se chama ShoppingCart, que é o mesmo componente CFC que criamos no post anterior, isso nos facilita um pouco a vida, pois estamos manipulando algo que esta de acordo com nossa especificação inicial.

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>
Esse método, é apenas para dar opção para quem não desejar usar o Carrinho Proprio, e não afeta em nada nosso envio.

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>
Este é mais um para a lista de não temos muito o que fazer, mas vai que o UOL resolver colocar pagSeguro recebendo em outras moedas, esperança é a última que morre.

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>
Esse método é para evitar problemas entre acressimos e descontos. Na documentação do PagSeguro para o campo extras eles falam "Utilize este campo para acrescentar ao pedido um valor adicional, caso necessário. Exemplo: você pode incluir o valor da embalagem de presente. Você também pode enviar um valor negativo neste campo, caso deseje oferecer um desconto ao seu cliente.".

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>
Esse método,  pode ser melhorado, e seguir o padrão de componentes, para endereço, pessoa e telefone, além de validar algumas informações como e-mail, mas nesse caso, ele só irá servir para guardar as informações que serão enviadas ao PagSeguro.

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>
Mais um da série, não tenho nada a dizer. A única observação é o tipo "UC" que estamos criando especialmente para o nosso PagSeguro.cfc. Se o nosso tipo de envio for "UC", não informaremos o tipo, fazendo com que o PagSeguro pergunte ao usuário, como ele deseja receber.

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>
Esse método privado pega o valor e coloca em conformidade com a especificação do PagSeguro "Valor ... sem vírgulas ou pontos. Para um produto que custa R$ 1,00 você deverá informar 100 (somente números)."

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>
A programação do método send é algo que se pode chamar de realmente simples. Ele vai gerar o nosso formulário, que nesse caso estou chamando de "frmPagSeguro", e executando o submit dele via javaScript. Isso esta sendo feito, para evitar o exemplo onde um simples "exibir código fonte" pode colocar toda a transação a perder.

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>
Agora vem a pergunta: "E o retorno automático?". Bom esse mistério será desvendado no post de amanhã.

E finalmente, para quem cansou de ler, esta tudo pronto para download no link http://www.flagnet.inf.br/downloads/shoppingCart-part2.rar