ASP .NET - MVC Music Store - Registro de usuário e Checkout


Neste tutorial vamos criar o controlador CheckoutController que irá coletar as informações de endereço e pagamento do comprados. Antes de iniciar o processo de checkout vamos requerer que o usuário seja registrado de forma que o controlador possa requerer a autorização para completar o processo de compra.

Inicialmente, ao acessar o nosso site, o usuário poderá acessar os produtos e incluir itens em sua cesta de compras como usuário anônimo, quando o usuário desejar encerrar a comprar ele pode clicar no botão - Concluir Compra >>> - existente na sua cesta de compras, e, neste momento será solicitado seu registro e login. Como os usuários esperam que suas cesta de compras sejam mantidas entre as suas visitas ao site vamos precisar associar a cesta de compra de cada usuário com a sua informação de registro e login.

Felizmente nossa classe CestaCompras já possui um método que associa todos os itens na cesta atual com o nome do usuário. Precisamos apenas chamar este método quando o usuário completar o registro ou o login.

Abra a classe AccountController na pasta Controllers e inclua uma referência a Imports MvcMusicStore.MvcMusicStore.Models e a seguir inclua o método MigrarCestaCompras:

    Private Sub MigrarCestaCompras(NomeUsuario As String)
        ' Associa os itens da cesta de compras com o usuário logado
        Dim cesta = CestaCompras.GetCesta(Me.HttpContext)
        cesta.MigraCesta(NomeUsuario)
        Session(CestaCompras.CestaSessionKey) = NomeUsuario
    End Sub

A seguir vamos modificar a Action Post LogOn para chamar o método MigrarCestaCompras depois que o usuário foi validado incluindo a linha de código no arquivo conforme mostrado no código abaixo:

Vamos fazer a mesma alteração para Action Post Register, incluindo a linha de código imediatamente após a conta do usuário ser criada com sucesso:

E pronto ! agora uma cesta de compras anônima será automaticamente transferida para um conta de usuário após o registro ou o login ser feito com sucesso.

Criando o controlador CheckoutController

Clique com o botão direito do mouse sobre a pasta Controllers e selecione Add -> Controller;

A seguir informe o nome CheckoutController e escolha o template Empty Controller e clique no botão Add;

A primeira coisa que vamos fazer é incluir no arquivo CheckoutController.vb o atributo Authorize no topo da declaração da classe para requerer que o usuário se registre antes de realizar o checkout:

Para manter as coisas simples nós não vamos tratar com a informação de pagamento neste tutorial. Vamos permitir que os usuários realizem o check out usando um código promocional. Vamos armazenar este código promocional usando uma constante chamada PromoCode.

Vamos declarar um campo chamado storedDB para tratar uma instância da classe MusicStoreEntities que nosso contexto e vamos declarar o namespace MvcMusicStore.Models de forma que no topo do arquivo CheckoutController teremos o seguinte código:

O controlador CheckoutController irá posuir as seguintes Actions:

Primeiro vamos renomear a Action Index do controlado (que foi gerada por padrão) pra EnderecoPagamento. Esta Action apenas exibir o formulário de checkout logo ela não requer qualquer informação do modelo.

Nosso método POST EnderecoPagamento irá seguir o mesmo padrão usado no controlador StoreManagerController: ela irá tentar aceitar a submissão do formulário e completar o pedido e irá reexibir o formulário se houver algum erro.

Após a validação se o formulário de entrada possui os requisitos de validação exigidos por um pedido vamos verificar o valor do código de promoção diretamente. Se tudo estiver correto vamos salvar e atualizar a informação com o pedido informando ao objeto CestaCompras para completar o processo do pedido e redirecionar para Action Complete.

        ' POST: /Checkout/EnderecoPagamento
        <HttpPost> _
        Public Function EnderecoPagamento(values As FormCollection) As ActionResult
            Dim _pedido = New Pedido()
            TryUpdateModel(_pedido)

            Try
                If String.Equals(values("PromoCode"), PromoCode, StringComparison.OrdinalIgnoreCase) = False Then
                    Return View(_pedido)
                Else
                    _pedido.Usuario = User.Identity.Name
                    _pedido.PedidoData = DateTime.Now
                    'Salva o pedido
                    storeDB.Pedidos.Add(_pedido)
                    storeDB.SaveChanges()
                    'Processa o pedido
                    Dim _cesta = CestaCompras.GetCesta(Me.HttpContext)
                    _cesta.CriaPedido(_pedido)
                    Return RedirectToAction("Complete", New With { _
                         .id = _pedido.PedidoId _
                    })
                End If
            Catch
                'Invalido - reexibe com erros
                Return View(_pedido)
            End Try
        End Function

Após a conclusão do processo de compra, os usuários serão redirecionados para a Action Complete. Esta ação irá executar uma verificação simples para validar que o pedido, de fato, pertence ao usuário logado antes de mostrar o número do pedido como uma confirmação.

     ' GET: /Checkout/Complete
        Public Function Complete(id As Integer) As ActionResult
            ' Valida o cliente
            Dim isValid As Boolean = storeDB.Pedidos.Any(Function(o) o.PedidoId = id AndAlso o.Usuario = User.Identity.Name)

            If isValid Then
                Return View(id)
            Else
                Return View("Erro")
            End If
        End Function

Adicionando a view EnderecoPagamento

Vamos criar a view EnderecoPagamento. Clique com o botão direito em uma das Actions do controlador EnderecoPagamento e selecione Add View informando o nome EnderecoPagamento e marcando a opção Create a strongly-type view , selecione o Model Class - Pedido (MvcMusicStore) e o template Edit e clique no botão Add;

Esta view vai fazer uso de duas técnicas :

Vamos iniciar atualizando o código formulário para usar Html.EditorForModel(), seguida por uma caixa de texto adicional para o código da promoção PromoCode. O código completo para a view EnderecoPagamento pode ser visto a seguir:

@ModelType MvcMusicStore.Pedido

@Code
    ViewBag("Title") = "Endereço e Pagamento"
End Code

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@Using Html.BeginForm()
    
    @<h2>Endereco e Pagamento</h2>
    
    @<fieldset>
        <legend>Endereço</legend>
         @Html.EditorForModel()
    </fieldset>

        @<fieldset>
            <legend>Pagamento</legend>
            <p>
                Estamos em promoção : Toda música é grátis usando o 
                código promocional : "GRATIS"
            </p>
            <div class="editor-label">
                 @Html.Label("Código Promoção")
             </div>
            <div class="editor-field">
                @Html.Label("Código PromoCode")
            </div>
        </fieldset>
    
        @<input type="submit" value="Salvar" />
    
End Using

Definindo as regras de validação para o pedido

Agora que nossa view esta definida , vamos definir as regras de validação para nosso model Pedido como fizemos anteriormente para o model Album.

Na pasta Models e selecione a o arquivo Pedido.vb e inclua os atributos data annotations conforme o código abaixo:

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.DataAnnotations
Imports System.Web.Mvc

<Bind(Exclude:="OrderId")> _
Public Class Pedido

    <ScaffoldColumn(False)> _
    Public Property PedidoId As Integer
    <ScaffoldColumn(False)> _
    Public Property Usuario As String

    <Required(ErrorMessage:="O nome é obrigatório")> _
    <DisplayName("Nome")> _
    <StringLength(160)> _
    Public Property Nome As String

    <Required(ErrorMessage:="O Sobrenome é obrigatório")> _
    <DisplayName("Sobrenome")> _
    <StringLength(160)> _
    Public Property Sobrenome As String

    <Required(ErrorMessage:="O Endereço é obrigatório")> _
    <StringLength(70)> _
    Public Property Endereco As String

    <Required(ErrorMessage:="A cidade é obrigatória")> _
    <StringLength(40)> _
    Public Property Cidade As String

    <Required(ErrorMessage:="O estado é obrigatório")> _
    <StringLength(40)> _
    Public Property Estado As String

    <Required(ErrorMessage:="O código postal é obrigatório")> _
    <DisplayName("Postal Code")> _
    <StringLength(10)> _
    Public Property CodigoPostal As String

    <Required(ErrorMessage:="O pais é obrigatório")> _
    <StringLength(40)> _
    Public Property Pais As String

    <Required(ErrorMessage:="O telefone é obrigatório")> _
    <StringLength(24)> _
    Public Property Telefone As String

    <Required(ErrorMessage:="O Email é obrigatório")> _
    <DisplayName("Email Address")> _
    <RegularExpression("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage:="O Email é inválido.")> _
    <DataType(DataType.EmailAddress)> _
    Public Property Email As String

    <ScaffoldColumn(False)> _
    Public Property Total As Decimal

    <ScaffoldColumn(False)> _
    Public Property PedidoData As System.DateTime

    Public Property PedidoDetalhes() As List(Of PedidoDetalhe)
End Class

Adicionando a view Complete

A view Complete usada no checkout é muito simples; ela precisa apenas exibir o ID do pedido. Clique com o botão direito do mouse sobre a action Complete do controlador CheckoutController e selecione Add View;

A seguir aceite o nome Complete para a view e defina que a ela será fortemente tipada para um int:

Agora atualize o código da view para exibir o código do Pedido (ID) conforme abaixo:

@Model int

@Code
    ViewBag("Title") = "Checkout Completo"
End Code

<h2>Checkout Completo</h2>

<p>Obrigado pelo seu pedido ! 
 <br />
  O número do seu pedido é : @Model
</p>
<p>
    Para mais novidades sobre música visite @Html.ActionLink("store","Index","Home")
</p>	

Atualizando a view de erros

O template padrão inclui uma view Error na pasta Shared que pode ser reusada em qualquer lugar do site. Esta view Error contém não usa o leiaute adotado por nosso site então vamos atualizá-la.

Como esta é uma página de erro genérica, o conteúdo deve ser muito simples. Vamos incluir uma mensagem e um link para navegar para a página anterior no histórico se o usuário desejar reentrar sua ação.

@Code
    ViewBag.Titulo = "Error"
End Code

<h2>Error</h2>
 
<p>Ocorreu um erro durante o processamento de sua requisição.

<a href="javascript:history.go(-1)">Clique Aqui</a>
Se você deseja retornar a página anterior e tentar novamente.</p>

Agora já podemos testar todas as implementações feitas.

Execute o projeto e navegue para a url /Store e escolha alguns itens de forma obter uma cesta de compras conforme abaixo:

Clique no botão - Concluir Compra >>> , se o usuário não estiver logado será apresentada a tela para autenticação onde o usuário deve informar nome e senha:

Se o usuário já estiver logado com sucesso ele será apresentado ao formulário para preencher os seus dados de endereço e pagamento:

Clicando no botão - Incluir na Cesta - teremos a execução da view Index da Cesta de Compras exibindo um resumo dos itens:

Vamos repetir o procedimento e incluir mais alguns itens na cesta de compras:

Temos assim a implementação da nossa cesta de compras funcionando onde já podemos selecionar e incluir e remover itens da cesta de compras.

No próximo tutorial vamos concluir a nossa aplicação com atualização na navegação e no design do site: ASP .NET - MVC Music Store - Atualizações finais na navegação e design to site

Referências:


José Carlos Macoratti