VB.NET 2008 - Protótipo para Sistema de Vendas com LINQ - III


Esta é a última parte do protótipo para sistema de vendas com LINQ. Se você esta chegando agora sugiro que leia os dois artigos anteriores:

Vou começar exibindo o formulário de vendas frmvendas do sistema:

Os controles usados no formulário são:

Dados do Cliente:

  • txtCodigoCliente
  • txtNomeCliente
  • btnProcuraCliente

Dados do Produto:

  • txtNomeProduto
  • txtPrecoProduto
  • txtQuantidade
  • btnProcuraProduto

Exibição das Vendas :

  • dgvVendas

btnIncluir, btnExcluir,btnCancelar e btnSalvar

Exibição do total: txtTotal

Antes de entrar no código do formulário teremos que criar uma classe para poder tratar os detalhes do Pedido (Vendas);

Clique com o botão direito sobre o nome do projeto e selecione a opção Add new Item ;

Na janela New Item selecione o template Class e informe o nome detalhesPedidos.vb;

A seguir inclua o seguinte código nesta classe:

Public Class DetalhesPedidos

    Private _codProduto As String
    Private _nomeProduto As String
    Private _quantidade As Integer
    Private _preco As Double
    Private _subtotal As Double
    Private _estoqueProduto As Double

    Public Property EstoqueProduto() As Integer
        Get
            Return _estoqueProduto
        End Get
        Set(ByVal value As Integer)
            _estoqueProduto = value
        End Set
    End Property

    Public Property CodProduto() As String
        Get
            Return _codProduto
        End Get
        Set(ByVal value As String)
            _codProduto = value
        End Set
    End Property

    Public Property NomeProduto() As String
        Get
            Return _nomeProduto
        End Get
        Set(ByVal value As String)
            _nomeProduto = value
        End Set
    End Property

    Public Property Quantidade() As Integer
        Get
            Return _quantidade
        End Get
        Set(ByVal value As Integer)
            _quantidade = value
        End Set
    End Property

    Public Property Preco() As Double
        Get
            Return _preco
        End Get
        Set(ByVal value As Double)
            _preco = value
        End Set
    End Property

    Public Property Subtotal() As Double
        Get
            Return _subtotal
        End Get
        Set(ByVal value As Double)
            _subtotal = value
        End Set
    End Property

End Class
Na classe DetalhesPedidos definimos 4 propriedades :
  • EstoqueProduto()
  • NomeProduto()
  • Quantidade()
  • Preco()
  • Subtotal()

que serão usadas para tratarmos os detalhes dos pedidos.

Voltando ao formulário de vendas a primeira coisa que temos que fazer é declarar as variáveis que usaremos na aplicação as quais são:


    'Definir o objeto bd da classe JcmSoftDataContext
    Dim bd As New JcmSoftDataContext

    'Definir objeto da clase DetalhesPedidos
    Dim oDetalhesPedidos As DetalhesPedidos
    Dim nomeProduto As String
    Dim codProduto As String
    Dim precoProduto As Double
    Dim codigoCliente As String
    Dim estoqueProduto As Integer

    'Definir una LISTA de Objetos DetalhesPedidos
    Dim ArrDetalhesPedidos As New List(Of DetalhesPedidos)
Perceba que eu declarei um uma lista do tipo DetalhesPedidos usando Generics; apenas para lembrar:

List(Of  T) Representa uma lista fortemente tipada de objetos que podem ser
acessados através de um índice. Fornece os métodos
Search, Sort e efetua a manipulação da lista.

No evento Click do botão com 3 pontinhos ao lado do código do cliente temos o código que irá abrir o formulário frmClientes para que o usuário selecione o um cliente já cadastrado; em seguida usando o código do cliente escolhido é feita uma consulta LINQ para selecionar o Cliente que possui o código escolhido no formulário frmclientes e exibir os seus dados nos controles do formulário frmvendas;

 Private Sub btnProcuraCliente_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProcuraCliente.Click
        'Instanciamos un Objeto Formulario frmClientes
        Dim dialogo As New frmClientes
        'Mostramos o Formulario
        dialogo.ShowDialog()
        'Se o resultado do Formulario e diferente de OK
        'mostra uma mensagem que indica que não
        'há nenhum cliente selecionado
        If dialogo.DialogResult = Windows.Forms.DialogResult.OK Then
            'Usamos uma consulta LINQ para selecionar um cliente
            'do qual recuperamos a variável codigoCliente declarada no 
            'Formulario frmClientes
            Dim cliente = From cli In bd.Clientes _
                                 Where cli.clienteID = dialogo.codigo _
                                 Select cli.clienteID, cli.nome, cli.email

            'Carregamos os valores do resultado da consulta
            'LINQ nos textbox do formulario
            Me.txtCodigoCliente.Text = cliente.ToList.Item(0).clienteID.ToString
            Me.txtNomeCliente.Text = cliente.ToList.Item(0).nome
            codigoCliente = cliente.ToList.Item(0).clienteID.ToString
        Else
             'exibe mensagem ao usuário e limpa os campos do formulário
            MsgBox("Não foi selecionado nenhum cliente.")
            Me.txtCodigoCliente.Text = ""
            Me.txtNomeCliente.Text = ""
            codigoCliente = ""
        End If
    End Sub

Da mesma forma no evento Click do botão temos o código que abra o formulário para o usuário selecionar um produto já cadastrado e em seguida obtendo o valor do código do produto escolhido , seleciona o produto e exibe o seus dados no formulário frmvendas;

 Private Sub btnProcuraProduto_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProcuraProduto.Click
        'Instancia um formulario frmProdutos
        Dim dialogo As New frmProdutos
        'exibe o formulario
        dialogo.ShowDialog()
        'se o resultado do formulario é Ok 
        If dialogo.DialogResult = Windows.Forms.DialogResult.OK Then
            'cria uma consulta LINQ para exibir os produtos cadastrados
            Dim produto = From prod In bd.Produtos _
                                   Where prod.ProdutoID = dialogo.codigo _
                                   Select prod.ProdutoID, prod.Nome, prod.preco, prod.estoque

            'obtem os valores e exibe nos controles TextBox do formulario
            Me.txtNomeProduto.Text = produto.ToList.Item(0).Nome.ToString
            Me.txtPrecoProduto.Text = produto.ToList.Item(0).preco.ToString
            'atribui os valores as variáveis definidas no formulario
            nomeProduto = produto.ToList.Item(0).Nome.ToString
            codProduto = produto.ToList.Item(0).ProdutoID.ToString
            precoProduto = Convert.ToDouble(produto.ToList.Item(0).preco.ToString)
            estoqueProduto = Convert.ToInt32(produto.ToList.Item(0).estoque.ToString)
            'poe o foco no textbox quantidade
            txtQuantidade.Focus()
        Else
            'exibe mensagem ao usuário e limpa os campos do formulário
            MsgBox("Nenhum Produto foi selecionado.")
            Me.txtNomeProduto.Text = ""
            Me.txtPrecoProduto.Text = ""
            nomeProduto = ""
            codProduto = ""
            precoProduto = 0.0
        End If

O código relacionado ao botão Incluir esta descrito abaixo e usa o arrayList do tipo DetalhesPedidos para exibir os pedidos de vendas incluídos no controle DataGridView;

Private Sub btnIncluir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIncluir.Click

        'Verificamos a quantidade foi informada
        If txtQuantidade.Text = String.Empty Then
            MsgBox("Informe a quantidade requerida...")
            txtQuantidade.Focus()
            Exit Sub
        End If
        'Verificamos se o nome do produto , preco e quantidade não estão vazios
        If txtNomeProduto.Text <> "" And txtPrecoProduto.Text <> "" And txtQuantidade.Text <> "" Then
            'Verificamos se o estoque do produto não é menor do que o solicitado
            If Convert.ToInt32(estoqueProduto) < Convert.ToInt32(txtQuantidade.Text) Then
                'Mostramos uma aviso ao usuário
                MsgBox("A quantidade requerida é Superior a do estoque")
                'Como a quantidade solicitada é mario que o estoque
                'perguntamos se o usuário deseja estabelecer o estoque atual
                'com a nova quantidade informada
                If MessageBox.Show("Deseja estabelecer o estoque atual como a nova quantidade requerida",_ 
 "Vendas", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
                    'Establecemos a nova quantidade em estoque
                    txtQuantidade.Text = estoqueProduto
                    'Inicializamos o objeto da classe DetalhesPedidos
                    oDetalhesPedidos = New DetalhesPedidos
                    'Preenchemos os valores 
                    '-----------------------------------------------------------------
                    oDetalhesPedidos.Quantidade = Convert.ToInt32(txtQuantidade.Text)
                    oDetalhesPedidos.CodProduto = codProduto
                    oDetalhesPedidos.NomeProduto = nomeProduto
                    oDetalhesPedidos.Preco = precoProduto
                    oDetalhesPedidos.EstoqueProduto = estoqueProduto
                    oDetalhesPedidos.Subtotal = precoProduto * Convert.ToInt32(txtQuantidade.Text)
                    '------------------------------------------------------------------------
                    'Verificamos se o produto esta na lista de pedidos
                    'e incluimos a lista de DetalhesPedidos
                    If buscarDetalhesVendas(ArrDetalhesPedidos, oDetalhesPedidos) = False Then
                        'Agregamos o pedido a lista de DetalhesPedidos
                        ArrDetalhesPedidos.Add(oDetalhesPedidos)
                    End If
                    'Assciamos a lista de DetalhesPedidos como fonte de dados ao datagridview
                    Me.dgvVendas.DataSource = ArrDetalhesPedidos
                Else
                    'Se não deseja estabelecer o estoque atual com a quantidade solicitada
                    'voltamos ao formulario para escolher outro produto
                    btnProcuraProduto_Click(Nothing, Nothing)
                End If
            Else
                'Como a quantidade requerida e menor que o estoque
                'iniciamos o objeto da classe DetalhesPedidos
                oDetalhesPedidos = New DetalhesPedidos
                'Preenchemos os valores no objeto
                oDetalhesPedidos.Quantidade = Convert.ToInt32(txtQuantidade.Text)
                oDetalhesPedidos.CodProduto = codProduto
                oDetalhesPedidos.NomeProduto = nomeProduto
                oDetalhesPedidos.Preco = precoProduto
                oDetalhesPedidos.EstoqueProduto = estoqueProduto
                oDetalhesPedidos.Subtotal = precoProduto * Convert.ToInt32(txtQuantidade.Text)
                'Verificamos se o produto solicitado esta na lista de pedidos
                'Se não estiver incluimos na lista de DetalhesPedidos
                If buscarDetalhesVendas(ArrDetalhesPedidos, oDetalhesPedidos) = False Then
                    'Incluimos o pedido a lista de DetalhesPedidos
                    ArrDetalhesPedidos.Add(oDetalhesPedidos)
                End If
                'Associamos a lista como origem da fonte de dados
                Me.dgvVendas.DataSource = ArrDetalhesPedidos.ToList
            End If
        End If
        'Limpamos os textBox
        Me.limpar_produto()
        'Calculamos o Total do Pedido
        Me.calcular_total()
    End Sub

No botão Salvar temos o código que irá salvar os dados e atualizar o estoque de produtos; Nesta rotina estou usando um expressão lambda;

O que são Expressões Lambda ?

As expressões lambda foram incluídas no VS/VB 2008 para dar suporte a consultas LINQ. As cláusulas Where são assim compiladas como expressões lambdas e chamadas em itens aplicáveis do seu dataset. Podem ser consideradas uma forma de delegate que pode passar ou retornar outra função.

Para saber mais veja o meu artigo: ASP .NET - Usando LINQ

Private Sub btnSalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSalvar.Click
        'Vamos usar o mapeamento feito pelo LINQ
        'para efetivar as atualizações nas bases de dados
        Try
            'A expressão lambda a seguir devolve um objeto Cliente
            'Estamos usando o codigo do cliente para identificar unicamento o cliente
            Dim Cli As Cliente = bd.Clientes.Single(Function(p) p.clienteID = Me.txtCodigoCliente.Text)
            '-------------------------------------------------
            'Cria um  novo objeto Pedido
            '-------------------------------------------------
            Dim oPedido As New Pedido
            oPedido.data = Date.Now
            oPedido.clienteID = Cli.clienteID
            oPedido.Cliente = Cli
            '--------------------------------------------------
            'Obtendo os detalhes do pedido 
            'realizo a geração dos objetos Pedido
            'vou percorrer o array dos detalhes do pedido
            '----------------------------------------------------
            For Each o As DetalhesPedidos In ArrDetalhesPedidos
                'Instancio um objeto Produto selecionando pelo codigo do produto
                Dim produto As Produto = bd.Produtos.Single(Function(a) a.ProdutoID = o.CodProduto.ToString())
                'Cria um novo detalhe do pedido
                Dim detPedido As New DetalhesPedido
                detPedido.Produto = produto
                detPedido.ProdutoID = produto.ProdutoID
                detPedido.Quantidade = o.Quantidade
                detPedido.Preco = o.Preco
                'inclui os detalhes do pedido no pedido
                oPedido.DetalhesPedidos.Add(detPedido)
                '-altera a quantidade de estoque do produto
                produto.estoque = produto.estoque - o.Quantidade
            Next
            '------------------------------------------------------
            'Aqui atualizo a base de dados
            bd.SubmitChanges()
            MsgBox("Dados de Pedidos , Detalhes de Pedidos e Estoque atualizados com sucesso...")
        Catch ex As Exception
            MsgBox(ex.Message)
        Finally
           'chama as rotinas para limpar clientes e produtos e vendas
            limpar_cliente()
            limpar_produto()
            limpar_venda()
            Me.calcular_total()
        End Try
    End Sub

A função buscarDetalhesVendas recebe como parâmetro o arrayList do tipo DetalhesPedidos e pesquisa no arrayList por um determinado produto conferindo com a quantidade em estoque;

Public Function buscarDetalhesVendas(ByVal array As List(Of DetalhesPedidos), ByVal objDV As DetalhesPedidos) As Boolean
        'Vreificamos se um produto ja foi solicitado
        For Each oDetPed As DetalhesPedidos In array
            If oDetPed.CodProduto = objDV.CodProduto Then
                Dim nQuantidade As Integer
                'Se encontramos o produto na lista de pedidos
                'incrementamos a quantidade solicitada
                'com a quantidade solicitada anteriomente
                nQuantidade = oDetPed.Quantidade + objDV.Quantidade
                If nQuantidade <= oDetPed.EstoqueProduto Then
                    oDetPed.Quantidade = nQuantidade
                    oDetPed.Subtotal = oDetPed.Preco * oDetPed.Quantidade
                Else
                    MsgBox("O estoque atual é insuficiente para a quantidade solicitada.")
                End If
                Return True
            End If
        Next
        Return False
    End Function

O total exibido no formulário é calculado pela rotina calcular_total que percorre o arrayList e soma os valores dos produtos incluídos;

Sub calcular_total()
        Dim soma As Double
        'calcula o valor total dos pedidos
        'percorre o arrayList e soma o valor Subtotal 
        For Each i As DetalhesPedidos In ArrDetalhesPedidos
            soma += i.Subtotal
        Next
        Me.txtTotal.Text = soma.ToString("C")
    End Sub

Finalmente temos as rotinas para limpar os produtos, vendas e clientes;

Sub limpar_produto()
    'limpa os controles TextBox 
   Me.txtQuantidade.Clear()
   Me.txtNomeProduto.Clear()
   Me.txtPrecoProduto.Clear()
End Sub
Sub limpar_venda()
   '
Limpa a lista usando o metodo Clear
   ArrDetalhesPedidos.Clear()
  
 'Atribuir a lista como origem de dados ao datagridview
   Me.dgvVendas.DataSource = ArrDetalhesPedidos.ToList
End Sub
Sub limpar_cliente()
    '
Metodo para limpar os textBox Associados ao Cliente
     Me.txtCodigoCliente.Clear()
     Me.txtNomeCliente.Clear()
End Sub

O código esta comentado basta pegar o projeto completo e conferir o seu funcionamento. Com isso você tem um protótipo bem simples de um sistema de vendas básico que pode lhe dar algumas idéias para o seu próprio projeto.

Eu sei , é apenas VB .NET e LINQ , mas eu gosto...

referências:

  • http://www.microsoft.com/brasil/msdn/Tecnologias/arquitetura/LINQ.mspx
  • LINQ - http://msdn2.microsoft.com/en-us/netframework/aa904594.aspx
  • 101 LINQ Samples
  • VB 2008 - Criando uma aplicação completa com LINQ To SQL - III
  • VB 2008 - Criando uma aplicação completa com LINQ To SQL - II
  • VB 2008 - Criando uma aplicação completa com LINQ To SQL - I
  • LINQ To SQL - Descritor O/R, DataContext e Stored Procedures
  • ASP .NET 2008 - LINQ To SQL - operações básicas
  • LINQ - Conceitos Básicos e fundamentos III - Expressões lambda
  • LINQ - Usando ComboBox com dados relacionados
  • LINQ - Conceitos Básicos e fundamentos II - Métodos de extensão
  • LINQ - Conceitos Básicos e fundamentos I- Inferência de tipos 

  • José Carlos Macoratti