quarta-feira, 1 de junho de 2011

Carrinho de Compras - Parte 1

Faz tempo que estou longe do Blog, por pura falta de tempo. Mas estou retomando a rotina aos poucos.

Ontem na lista de ColdFusion levantaram um ponto sobre a integração com o PagSeguro que é uma das muitas ferramentas, para integração de pagamento com boleto bancário, cartões de crédito e outros meios de acordo com o integrador. Para quem desejar, pode se cadastrar por este link.

O porque utilizar estes integradores explico em outro post, porém nesse momento, resolvi iniciar uma série de posts sobre Carrinho de Compras e integrações com os mais diversos meios de pagamento disponíveis. Se você trabalha com ColdFusion e deseja integrar seu carrinho com PagSeguro, Pagamento Digital, do Buscapé, Paypal ou qualquer outro do seu interesse, basta comentar que eu monto o códido explicando como tratar cada um.

Este primeiro post, vou implementar o carrinho que irei usar durante toda a série de integrações e vou adaptando ele a medida que for necessário, apesar que não espero ter que faze-lo.

Inicialmente, vamos criar um arquivo Applicatioon.cfc para iniciar a nossa session e nosso carrinho de compras. No meu caso optei por criar um carrinho com modelo de Orientação a Objetos, ou seja , teremos DOIS componentes, um que será o nosso item e outro, que será o carrinho iniciado em session.

Application.cfc
   1: <cfcomponent output="false">
   2:     <!--- application variables --->
   3:     <cfset this.name = "ShoppingCartSample">
   4:     <cfset this.sessionManagement = true>
   5:     <cfset this.sessionTimeout = createTimeSpan(0, 0, 30, 0)>
   6:  
   7:     <cffunction name="onRequestStart" access="public" returnType="boolean" output="false">
   8:         <cfargument type="String" name="targetPage" required="true"/>
   9:  
  10:         <cfif NOT structKeyExists(session, "shoppingCart")>
  11:             <cfset session.shoppingCart = createObject("component", "ShoppingCart")>
  12:         </cfif>
  13:         <cfreturn true>
  14:     </cffunction>
  15: </cfcomponent>

Nada de muito misterioso, apenas criamos as variaveis de inicialização de session e criamos o método onRequestStart que verifica "se na estrutura Session não existir a variável shoppingCart, então crie".

Alguns podem achar estranho instanciar um componente numa session, porém estamos na verdade criando o carrinho de compras de cada usuário.

Uma vez feito isso, vamos ao carrinho de compras, propriamente dito. O que o nosso ou qualquer outro carrinho de compras deve ter?

Pensei um pouco ontem e imaginei o CRUD (Create, Retrieve, Update e Delete) básico de operações e algumas coisas extras que serão úteis para o usuário, como limpar, listar todos os produtos adicionados, obter detalhes de um produto específico, listar todos os produtos, quantidade de produtos, itens (quantidade por volume) e o valor total do carrinho.

Porque fazer assim? Simples, um carrinho de compras dificilmente vai mudar. A regra de negócios dele é simples, o que pode mudar são os itens e como eles podem ser tratados.

Melhorando a vida, vamos separar por partes o que será feito no carrinho.

ShoppingCart.cfc

O primeiro passo é criar as variáveis que serão manipuladas pelo carrrinho. Todas elas estarão no topo do nosso CFC (classe) e com scoopo Variables (privat).

   1: <cfset variables.cart = arrayNew(1)>
   2: <cfset variables.vlTotal = 0>
   3: <cfset variables.cartItem = createObject("component", "ShoppingCartItem")>
   4: <cfset variables.nbMaxCartItem = 10>

  • cart: Será o nosso array de itens, essa variável será manipulada pelo CRUD do nosso CFC
  • vlTotal: Irá receber o valor do carrinho, ou seja, o valor da soma de todos os itens do carrinho
  • cartItem: Esse nosso componente, irá acessar a base de dados e obter os detalhes do item.
  • nbMaxCartItem: Essa variavel é para evitar que alguém reserve todo o estoque.
 Bom, agora que já temos o que manipular vamos ao CRUD.

addItem
   1: <cffunction name="addItem" access="public" output="no" returntype="void">
   2:     <cfargument name="idItem" type="numeric" required="true">
   3:     <cfargument name="qtItem" type="numeric" required="false" default="1">
   4:  
   5:     <cfset var Local = StructNew()>
   6:     <cfset Local.cartItem = Duplicate(variables.cartItem)>
   7:     <cfif hasItem(Arguments.idItem)>
   8:         <cfset updateItem(Arguments.idItem, Arguments.qtItem)>   
   9:     <cfelse>
  10:         <cfset Local.cartItem.setShoppingCartItem(Arguments.idItem)>
  11:         <cfif (Arguments.qtItem GT variables.nbMaxCartItem) AND (variables.nbMaxCartItem NEQ 0)>
  12:             <cfset Local.cartItem.qtItem = variables.nbMaxCartItem>
  13:         <cfelse>
  14:             <cfset Local.cartItem.qtItem = Arguments.qtItem>
  15:         </cfif>
  16:         <cfset Local.cartItem.vlTotalItem = Local.cartItem.vlItem * Local.cartItem.qtItem>
  17:         <cfset variables.vlTotal = variables.vlTotal + Local.cartItem.vlTotalItem>
  18:         <cfset ArrayAppend(variables.cart, Local.cartItem)>
  19:     </cfif>
  20: </cffunction>

Nossa primeira ação, é adicionar o item escolhido pelo usuário no carrinho. Repare que o método só pede duas informações, o idItem e o qtItem. O idItem é o identificador na sua base de dados e a quantidade dele que você deseja.


Em nosso primeiro passo com relação ao carrinho, verificamos se esse item já não foi adicionado, se isso ocorreu, chamamos a operação de updateItem, caso contrário, seguimos o fluxo normal.

No nosso fluxo normal, utilizamos a função Duplicate do ColdFusion para criar uma cópia idêntica, do nosso componente ShoppingCartItem, isso evita o consumo de recursos da função createObject.

Após criar minha cópia, chamo o médoto setSoppingCartItem do meu ShoppingCartItem, que é responsável pelas verificações pertinentes ao item.

Verifico se a quantidade de itens esta dentro do aceitável, caso contrário defino a quantidade de itens com o máximo que aceitamos. Se alguém achar isso loucura, da uma olhada no carrinho de compras de e-commerces "pequenos" como submarino, saraiva, e outros.

Terminada toda operação, atualizamos o valor dos itens, o valor do carrinho e adicionamos ele ao nosso array de itens.

updateItem
   1: <cffunction name="updateItem" access="public" output="no" returntype="void">
   2:     <cfargument name="idItem" type="numeric" required="true">
   3:     <cfargument name="qtItem" type="numeric" required="true">
   4:     <cfset var Local = StructNew()>
   5:  
   6:     <cfif Arguments.qtItem EQ 0>
   7:         <cfset remove(arguments.productId)>
   8:     <cfelse>
   9:         <cfloop array="#variables.cart#" index="Local.currElement">
  10:             <cfif Local.currElement.idItem eq Arguments.idItem>
  11:                 <cfset Local.cartItem = Local.currElement>
  12:                 <cfbreak>
  13:             </cfif>
  14:         </cfloop>
  15:         <cfif Not StructKeyExists(Local, "cartItem")>
  16:             <cfset addItem(Arguments.idItem, Arguments.qtItem)>
  17:         <cfelse>
  18:             <cfset variables.vlTotal = variables.vlTotal - Local.cartItem.vlTotalItem>
  19:             <cfif (Arguments.qtItem GT variables.nbMaxCartItem) AND (variables.nbMaxCartItem NEQ 0)>
  20:                 <cfset Local.cartItem.qtItem = variables.nbMaxCartItem>
  21:             <cfelse>
  22:                 <cfset Local.cartItem.qtItem = Arguments.qtItem>
  23:             </cfif>
  24:             <cfset Local.cartItem.vlTotalItem = Local.cartItem.vlItem * Local.cartItem.qtItem>
  25:             <cfset variables.vlTotal = variables.vlTotal + Local.cartItem.vlTotalItem>
  26:         </cfif>
  27:     </cfif>
  28: </cffunction>
Na ação de atualizar o item, nossa primeira preocupação é com a quantidade. Se a quantidade for ZERO, então removemos o item.

Após a verificação de quantidade, partimos para localizar o item a ser atualizado e mudar sua quantidade, consequentemetne, afetando os valores.

Repare que em nenhum momento, verificamos a quantidade em estoque, até porque você não sabe se o usuário vai realmente finalizar a compra, com isso todo o processamento gira em torno do desejo do usuário, e não sobre todo o seu estoque.

remove
   1: <cffunction name="remove" access="public" returntype="void">
   2:     <cfargument name="idItem" type="numeric" required="true">
   3:     <cfset var Local = StructNew()>
   4:     <cfloop from="1" to="#ArrayLen(variables.cart)#" index="Local.i">
   5:         <cfif variables.cart[Local.i].idItem eq Arguments.idItem>
   6:             <cfbreak>
   7:         </cfif>
   8:     </cfloop>
   9:     <cfset variables.vlTotal = variables.vlTotal - (variables.cart[Local.i].vlItem * variables.cart[Local.i].qtItem)>
  10:     <cfset arrayDeleteAt(variables.cart, Local.i)>
  11: </cffunction>

Bom acredito eu que este seja um dos métodos mais simples do nosso ShoppingCart.cfc, ele simplesmete "localiza e destroi", a diferença que depois ele arruma os valores.

list
   1: <cffunction name="list" access="public" returntype="array">
   2:     <cfreturn variables.cart>
   3: </cffunction>

Ok, esse sim é o mais simples, só posso dizer.... "Ahhh Mulequeeee" rsrs. Para aqueles que não entenderam a piada, veja o video


clear
   1: <cffunction name="clear" access="public" returntype="void">
   2:     <cfset ArrayClear(variables.cart)>
   3:     <cfset variables.vlTotal = 0>
   4: </cffunction>
Bom agora virou festa, depois falam que Orientação a Objetos é ruim.

getTotalProducts
   1: <cffunction name="getTotalProducts" access="public" returntype="numeric">
   2:     <cfreturn arrayLen(variables.cart)>
   3: </cffunction>
Esse eu desisto, estou a mais tempo pensando o que escrever sobre o que ele faz do que para faze-lo

getTotalItems
   1: <cffunction name="getTotalItems" access="public" returntype="numeric">
   2:     <cfset var Local = StructNew()>
   3:     <cfset Local.qtItem = 0>
   4:     <cfloop array="#variables.cart#" index="Local.current">
   5:         <cfset Local.qtItem = Local.qtItem + Local.current.qtItem>
   6:     </cfloop>
   7:     <cfreturn Local.qtItem>
   8: </cffunction>
A diferença entre getTotalItens e getTotalProducts esta em volume, posso ter 1 produto, porém quero 10 dele, isso afeta o meu frete, que alias será um dos nosso assuntos nesta série de posts também.

getTotal
   1: <cffunction name="getTotal" access="public" returntype="numeric">
   2:     <cfreturn variables.vlTotal>
   3: </cffunction>
Esse é mais um método da série "O que dizer?"

hasItem
   1: <cffunction name="hasItem" access="private" output="no" returntype="boolean">
   2:     <cfargument name="idItem" type="numeric" required="true">
   3:     <cfset var Local = StructNew()>
   4:     <cfset Local.hasItemReturn = false>
   5:     <cfloop array="#variables.cart#" index="Local.currElement">
   6:         <cfif Local.currElement.idItem eq Arguments.idItem>
   7:             <cfset Local.hasItemReturn = true>
   8:             <cfbreak>
   9:         </cfif>
  10:     </cfloop>
  11:     <cfreturn Local.hasItemReturn>
  12: </cffunction>
Por ultimo, porém não menos importante, temos o método hasItem, que só serve para verificar se o item que estamos tentando adicionar ao carrinho já existe. Por este motivo ele é definido com access="private"

Resultado ShoppingCart.cfc
Bom, para evitar os copy and paste, ai esta como o nosso carrinho irá ficar no final.
   1: <cfcomponent output="false">
   2:     <cfset variables.cart = arrayNew(1)>
   3:     <cfset variables.vlTotal = 0>
   4:     <cfset variables.cartItem = createObject("component", "ShoppingCartItem")>
   5:     <cfset variables.nbMaxCartItem = 10>
   6:     
   7:     <cffunction name="addItem" access="public" output="no" returntype="void">
   8:         <cfargument name="idItem" type="numeric" required="true">
   9:         <cfargument name="qtItem" type="numeric" required="false" default="1">
  10:  
  11:         <cfset var Local = StructNew()>
  12:         <cfif hasItem(Arguments.idItem)>
  13:             <cfset updateItem(Arguments.idItem, Arguments.qtItem)>   
  14:         <cfelse>
  15:             <cfset Local.cartItem = Duplicate(variables.cartItem)>
  16:             <cfset Local.cartItem.setShoppingCartItem(Arguments.idItem)>
  17:             <cfif (Arguments.qtItem GT variables.nbMaxCartItem) AND (variables.nbMaxCartItem NEQ 0)>
  18:                 <cfset Local.cartItem.qtItem = variables.nbMaxCartItem>
  19:             <cfelse>
  20:                 <cfset Local.cartItem.qtItem = Arguments.qtItem>
  21:             </cfif>
  22:             <cfset Local.cartItem.vlTotalItem = Local.cartItem.vlItem * Local.cartItem.qtItem>
  23:             <cfset variables.vlTotal = variables.vlTotal + Local.cartItem.vlTotalItem>
  24:             <cfset ArrayAppend(variables.cart, Local.cartItem)>
  25:         </cfif>
  26:     </cffunction>
  27:  
  28:     <cffunction name="updateItem" access="public" output="no" returntype="void">
  29:         <cfargument name="idItem" type="numeric" required="true">
  30:         <cfargument name="qtItem" type="numeric" required="true">
  31:         <cfset var Local = StructNew()>
  32:  
  33:         <cfif Arguments.qtItem EQ 0>
  34:             <cfset remove(arguments.productId)>
  35:         <cfelse>
  36:             <cfloop array="#variables.cart#" index="Local.currElement">
  37:                 <cfif Local.currElement.idItem eq Arguments.idItem>
  38:                     <cfset Local.cartItem = Local.currElement>
  39:                     <cfbreak>
  40:                 </cfif>
  41:             </cfloop>
  42:             <cfif Not StructKeyExists(Local, "cartItem")>
  43:                 <cfset addItem(Arguments.idItem, Arguments.qtItem)>
  44:             <cfelse>
  45:                 <cfset variables.vlTotal = variables.vlTotal - Local.cartItem.vlTotalItem>
  46:                 <cfif (Arguments.qtItem GT variables.nbMaxCartItem) AND (variables.nbMaxCartItem NEQ 0)>
  47:                     <cfset Local.cartItem.qtItem = variables.nbMaxCartItem>
  48:                 <cfelse>
  49:                     <cfset Local.cartItem.qtItem = Arguments.qtItem>
  50:                 </cfif>
  51:                 <cfset Local.cartItem.vlTotalItem = Local.cartItem.vlItem * Local.cartItem.qtItem>
  52:                 <cfset variables.vlTotal = variables.vlTotal + Local.cartItem.vlTotalItem>
  53:             </cfif>
  54:         </cfif>
  55:     </cffunction>
  56:     
  57:     <cffunction name="remove" access="public" returntype="void">
  58:         <cfargument name="idItem" type="numeric" required="true">
  59:         <cfset var Local = StructNew()>
  60:         <cfloop from="1" to="#ArrayLen(variables.cart)#" index="Local.i">
  61:             <cfif variables.cart[Local.i].idItem eq Arguments.idItem>
  62:                 <cfbreak>
  63:             </cfif>
  64:         </cfloop>
  65:         <cfset variables.vlTotal = variables.vlTotal - (variables.cart[Local.i].vlItem * variables.cart[Local.i].qtItem)>
  66:         <cfset arrayDeleteAt(variables.cart, Local.i)>
  67:     </cffunction>
  68:     
  69:     <cffunction name="clear" access="public" returntype="void">
  70:         <cfset ArrayClear(variables.cart)>
  71:         <cfset variables.vlTotal = 0>
  72:     </cffunction>
  73:     
  74:     <cffunction name="getProductDetail" access="public" returntype="ShoppingCartItem">
  75:         <cfargument name="idItem" type="numeric" required="true">
  76:         <cfset var Local = StructNew()>
  77:         <cfloop array="#variables.cart#" index="Local.currElement">
  78:             <cfif Local.currElement.idItem eq Arguments.idItem>
  79:                 <cfset Local.cartItem = Local.currElement>
  80:                 <cfbreak>
  81:             </cfif>
  82:         </cfloop>
  83:         <cfreturn Local.cartItem>
  84:     </cffunction>
  85:     
  86:     <cffunction name="list" access="public" returntype="array">
  87:         <cfreturn variables.cart>
  88:     </cffunction>
  89:     
  90:     <cffunction name="getTotalProducts" access="public" returntype="numeric">
  91:         <cfreturn arrayLen(variables.cart)>
  92:     </cffunction>
  93:     
  94:     <cffunction name="getTotalItems" access="public" returntype="numeric">
  95:         <cfset var Local = StructNew()>
  96:         <cfset Local.qtItem = 0>
  97:         <cfloop array="#variables.cart#" index="Local.current">
  98:             <cfset Local.qtItem = Local.qtItem + Local.current.qtItem>
  99:         </cfloop>
 100:         <cfreturn Local.qtItem>
 101:     </cffunction>
 102:  
 103:     <cffunction name="getTotal" access="public" returntype="numeric">
 104:         <cfreturn variables.vlTotal>
 105:     </cffunction>
 106:  
 107:     <cffunction name="hasItem" access="private" output="no" returntype="boolean">
 108:         <cfargument name="idItem" type="numeric" required="true">
 109:         <cfset var Local = StructNew()>
 110:         <cfset Local.hasItemReturn = false>
 111:         <cfloop array="#variables.cart#" index="Local.currElement">
 112:             <cfif Local.currElement.idItem eq Arguments.idItem>
 113:                 <cfset Local.hasItemReturn = true>
 114:                 <cfbreak>
 115:             </cfif>
 116:         </cfloop>
 117:         <cfreturn Local.hasItemReturn>
 118:     </cffunction>
 119: </cfcomponent>

ShoppingCartItem.cfc
Ok, agora vem a pergunta: "E como fica o Item do meu carrinho?" Nesse caso, a resposta é "cada um faz o seu", mas a título de exemplo vou montar um aqui como modelo e idéia.

Lembrando que modelo não é regra!! A única regra, são os métodos getShoppingCartItem e setShoppingCartItem respectivamente, para manter um padrão de integração com o nosso carrinho.

Uma dica é criar um outro CFC que terá seu acesso ao DB para verificar se o item existe, e recuperar os detalhes dele. Para nosso teste, estou gerando valores ficticios.
   1: <cfcomponent output="false">
   2:     <cfproperty name="idItem" type="numeric">
   3:     <cfproperty name="cdItem" type="string">
   4:     <cfproperty name="nmItem" type="string">
   5:     <cfproperty name="vlItem" type="numeric">
   6:     <cfproperty name="nbWeight" type="numeric">
   7:     <cfproperty name="flFreeShipping" type="boolean">
   8:     <cfproperty name="dtCreate" type="date">
   9:     <cfproperty name="dtLastUpdate" type="date">
  10:  
  11:     <cfparam name="This.idItem" default="">
  12:     <cfparam name="This.cdItem" default="">
  13:     <cfparam name="This.nmItem" default="">
  14:     <cfparam name="This.vlItem" default="">
  15:     <cfparam name="This.nbWeight" default="">
  16:     <cfparam name="This.flFreeShipping" default="">
  17:     <cfparam name="This.dtCreate" default="#DateConvert('local2utc', Now())#">
  18:     <cfparam name="This.dtLastUpdate" default="#DateConvert('local2utc', Now())#">
  19:     
  20:     <cffunction name="getShoppingCartItem" access="public" output="no" returntype="ShoppingCartItem">
  21:         <cfreturn This>
  22:     </cffunction>
  23:  
  24:     <cffunction name="setShoppingCartItem" access="public" output="no" returntype="void">
  25:         <cfargument name="idItem" type="numeric" required="yes">
  26:  
  27:         <cfset This.idItem = numberFormat(arguments.idItem, "00")>
  28:         <cfset This.cdItem = "CI" &amp; numberFormat(arguments.idItem, "00000000")>
  29:         <cfset This.nmItem = "Nome do Item " &amp; arguments.idItem>
  30:         <cfset This.vlItem = randRange(5.40, 123.80)>        
  31:         <cfset This.nbWeight = randRange(0.25, 2)>
  32:         <cfset This.flFreeShipping = iif(This.vlItem GT 59.20, true, false)>
  33:         <cfset This.dtCreate = now()>
  34:         <cfset This.dtLastUpdate = now()>
  35:     </cffunction>
  36: </cfcomponent>

Juntando tudo
Para evitar dores de cabeça criei um index.cfm de teste, só para vermos as ações funcionando.
   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>Untitled Document</title>
   5: </head>
   6: <body>
   7:     <cfif structKeyExists(form, "add")>
   8:         <cfset session.shoppingCart.addItem(form.idItem, form.qtItem)>
   9:     </cfif>
  10:     <cfif structKeyExists(form, "upd")>
  11:         <cfset session.shoppingCart.updateItem(form.idItemUpd, form.qtItemUpd)>
  12:     </cfif>
  13:     <cfif structKeyExists(form, "rem")>
  14:         <cfset session.shoppingCart.remove(form.idItemRem)>
  15:     </cfif>
  16:     <cfif structKeyExists(form, "clear")>
  17:         <cfset session.shoppingCart.clear()>
  18:     </cfif>
  19:     <cfif structKeyExists(form, "reset")>
  20:         <cfset structClear(session)>
  21:         <cfset session.shoppingCart = createObject("component", "ShoppingCart")>
  22:     </cfif>
  23:     
  24:     <form method="post">
  25:         <div style="float: left;">
  26:             <input type="submit" name="reset" value="Limpar Session" />
  27:             <input type="submit" name="clear" value="Limpar Carrinho" />
  28:         <fieldset>
  29:             <legend>Adicionar Itens</legend>
  30:             <div style="float: left;">
  31:                 <label for="idItem">Código:</label>
  32:                 <input type="text" id="idItem" name="idItem" size="4"/>
  33:                 <label for="qtItem">Quantidade:</label>
  34:                 <input type="text" id="qtItem" name="qtItem" size="4"/>
  35:                 <input type="submit" name="add" value="Adicionar" />
  36:             </div>
  37:         </fieldset>
  38:     
  39:         <fieldset>
  40:             <legend>Atualizar Itens</legend>
  41:             <div style="float: left;">
  42:                 <label for="idItemUpd">Código:</label>
  43:                 <input type="text" id="idItemUpd" name="idItemUpd" size="4"/>
  44:                 <label for="qtItemUpd">Nova Quantidade:</label>
  45:                 <input type="text" id="qtItemUpd" name="qtItemUpd" size="4"/>
  46:                 <input type="submit" name="upd" value="Atualizar" />
  47:             </div>
  48:         </fieldset>
  49:     
  50:         <fieldset>
  51:             <legend>Remover Itens</legend>
  52:             <div style="float: left;">
  53:                 <label for="idItemRem">Código:</label>
  54:                 <input type="text" id="idItemRem" name="idItemRem" size="4"/>
  55:                 <input type="submit" name="rem" value="Remover" />
  56:             </div>
  57:         </fieldset>
  58:         
  59:         <fieldset>
  60:             <legend>Detalhes do Item</legend>
  61:             <div style="float: left;">
  62:                 <label for="idItemDet">Código:</label>
  63:                 <input type="text" id="idItemDet" name="idItemDet" size="4"/>
  64:                 <input type="submit" name="det" value="Detalhes" />
  65:             </div>
  66:             <cfif structKeyExists(form,"idItemDet") and isNumeric(form.idItemDet)>
  67:                 <cfset details = session.shoppingCart.getProductDetail(form.idItemDet)>
  68:                 <cfdump var="#details#" label="Detalhe do Item">
  69:             </cfif>
  70:         </fieldset>
  71:         
  72:         <fieldset>
  73:             <legend>Detalhes do Carrinho</legend>
  74:             <div>
  75:                 <strong>Total de Produtos no Carrinho:</strong>
  76:                 <cfoutput>#session.shoppingCart.getTotalProducts()#</cfoutput>
  77:             </div>
  78:             <div>
  79:                 <strong>Total de Itens no Carrinho:</strong>
  80:                 <cfoutput>#session.shoppingCart.getTotalItems()#</cfoutput>
  81:             </div>
  82:             <div>
  83:                 <strong>Valor Total do Carrinho:</strong>
  84:                 <cfoutput>#lsCurrencyFormat(session.shoppingCart.getTotal())#</cfoutput>
  85:             </div>
  86:             <h3>Dump do Carrinho</h3>
  87:             <cfdump var="#session.shoppingCart.list()#">
  88:         </fieldset>
  89:     </form>
  90: </body>
  91: </html>

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

6 comentários:

  1. Show de bola Rafael, a tempos atraz vc me deu umas dicas de shoppingCard e eu monteu meu carrinho, olhando o seu vejo que fui um bom aluno.
    To ancioso pra ver agora o retorno automatico do pagseguro.
    Abraço Mestre.

    ResponderExcluir
  2. É sempre bom ler de quem realmente sabe!
    Parabéns!

    ResponderExcluir
  3. Animal... tive varias ideias, obrigado mesmo...
    Assim como o Anderson, fico aguardando o retorno automárico anciosamente xD

    Abraço

    ResponderExcluir
  4. Parabens Rafal!

    Eu sempre apoio esse tipo de iniciativa. O código está muito bem feito e simples leitura e com compatibilidade entre as versões 8 e 9, embora alguns recursos facilitadores da versão 9 trouxesse maior simplicidade ao código.


    Abraço,
    Jeff

    ResponderExcluir
  5. Esses códigos não dá para colocar no Blogspot.com que pena !!

    ResponderExcluir
    Respostas
    1. Esses códigos são para quem utiliza a lingagem ColdFusion. no caso do BlogSpot ele não utiliza nenhuma linguagem de programação, a não ser o HTML. Se a tua intenção é ter o pagseguro em um blog, só utilizando a API de HTML que você encontra no site do pag seguro

      Excluir