Utilizando Classe no Access - A Classe Produto
Nota importante: para ter acesso aos vídeos e arquivos exemplos deste site, adquira um dos planos apresentados abaixo. Você pode comprar em até 5x no Cartão de Crédito, através do Paypal.
Veja como comprar e saiba mais sobre o material oferecido, clicando aqui.

Por: Plinio Mabesi
Continuando a inclusão de funcionalidade em nosso sistema vamos agora ao próximo passo.
A próxima classe a ser codificada será a classe Produto. Após apresentar a estrutura da classe faremos a implementação da interface gráfica que manipulará os dados dos objetos.
Mais uma vez, caso necessário, relembre os conceitos anteriores sobre atributos, métodos, acesso às propriedades do objeto, instâncias e demais ensinamentos sobre a programação orientada a objetos, vistos nos primeiros artigos.
A Classe Produto
O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de inclusão, consulta, atualização e exclusão dos objetos do tipo produto.
Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de funções próprias, bem como dos métodos do objeto da classe ConexaoBD.
Código da classe:
Option Compare Database
Option Explicit
'Atributos da Classe
'Atributo de backup e atributo identificador da Classe
'PK - Código que identifica o produto.
Private bkpCodProduto As Variant
Private lngCodProduto As Variant
'Descrição do produto.
Private strDescricao As Variant
'Quantidade mínima desejada no estoque.
Private dblEstoqueMinimo As Variant
'Quantidade atual do estoque.
Private dblQtdEstoque As Variant
'Unidade de comercialização do produto.
Private strUnidade As Variant
'Valor unitário do produto.
Private curValorUnitario As Variant
'Métodos Get, Set e Let da Classe
Property Get codProduto() As Variant
    codProduto = lngCodProduto
End Property
Property Let codProduto(argCodProduto As Variant)
    lngCodProduto = argCodProduto
    
    If IsEmpty(bkpCodProduto) Then
      bkpCodProduto = lngCodProduto
    End If
End Property
Property Get descricao() As Variant
    descricao = strDescricao
End Property
Property Let descricao(argDescricao As Variant)
    strDescricao = argDescricao
End Property
Property Get estoqueMinimo() As Variant
    estoqueMinimo = dblEstoqueMinimo
End Property
Property Let estoqueMinimo(argEstoqueMinimo As Variant)
    dblEstoqueMinimo = argEstoqueMinimo
End Property
Property Get qtdEstoque() As Variant
    qtdEstoque = dblQtdEstoque
End Property
Property Let qtdEstoque(argQtdEstoque As Variant)
    dblQtdEstoque = argQtdEstoque
End Property
Property Get unidade() As Variant
    unidade = strUnidade
End Property
Property Let unidade(argUnidade As Variant)
    strUnidade = Ucase(argUnidade)
End Property
Property Get valorUnitario() As Variant
    valorUnitario = curValorUnitario
End Property
Property Let valorUnitario(argValorUnitario As Variant)
    curValorUnitario = argValorUnitario
End Property
'Método Existe [Com conhecimento de SQL]
'Verifica a existência do objeto Produto na tabela 
'correspondente no Banco de Dados.
Function existe(argCodProduto As Variant) As Boolean
On Error GoTo Err_existe
    Dim objCon As New aclConexaoBD
    Dim rstExiste As Recordset
    Dim strSql As String
    existe = False
    strSql = "Select * " & _
            "From Produto " & _
            "Where codProduto = " & objCon.valorSql(argCodProduto)
    Set rstExiste = objCon.consulta(strSql)
    If rstExiste.RecordCount > 0 Then
        existe = True
    End If
    'Fecha o Recordset existe
    rstExiste.close
Exit_existe:
    Set rstExiste = Nothing
    Exit Function
Err_existe:
    existe = False
    GoTo Exit_existe
End Function
'Método Incluir [Com conhecimento de SQL]
'Inclui um novo objeto na tabela correspondente dentro do Banco de dados
Function incluir() As Boolean
On Error GoTo Err_incluir
    Dim objCon As New aclConexaoBD
    Dim strSql As String
    strSql = "Insert Into " & _
            "Produto(codProduto,descricao,estoqueMinimo,qtdEstoque, _
            unidade,valorUnitario) " & _
            "Values(" & objCon.valorSql(codProduto) & "," & _ 
            objCon.valorSql(descricao) & "," & _
            objCon.valorSql(estoqueMinimo) & "," & _ 
            objCon.valorSql(qtdEstoque) & "," & _
            objCon.valorSql(unidade) & "," & _
            objCon.valorSql(valorUnitario) & ")"
    incluir = (objCon.executa(strSql) > 0)
    If incluir Then
        'Atualiza os campos de backup
        bkpCodProduto = codProduto
    End If
Exit_incluir:
    Exit Function
Err_incluir:
    incluir = False
    GoTo Exit_incluir
End Function
'Método Excluir [Com conhecimento de SQL]
'Exclui o objeto atual na tabela correspondente dentro do Banco de dados
Function excluir() As Boolean
On Error GoTo Err_excluir
    Dim objCon As New aclConexaoBD
    Dim strSql As String
    strSql = "Delete From Produto " & _
            "Where codProduto = " & objCon.valorSql(codProduto)
    excluir = (objCon.executa(strSql) > 0)
Exit_excluir:
    Exit Function
Err_excluir:
    excluir = False
    GoTo Exit_excluir
End Function
'Método Obter [Com conhecimento de SQL]
'Recupera o objeto Produto através dos argumentos informados
Function obter(argCodProduto As Variant) As Boolean
On Error GoTo Err_obter
    Dim objCon As New aclConexaoBD
    Dim rstObter As Recordset
    Dim strSql As String
    strSql = "Select * " & _
            "From Produto " & _
            "Where codProduto = " & objCon.valorSql(argCodProduto)
    Set rstObter = objCon.consulta(strSql)
    If rstObter.RecordCount = 0 Then
        obter = False
        Exit Function
    End If
    'Atualiza os campos de backup e os identificadores
    codProduto = argCodProduto
    bkpCodProduto = argCodProduto
    'Atualiza os campos restantes
    descricao = rstObter.Fields("descricao")
    estoqueMinimo = rstObter.Fields("estoqueMinimo")
    qtdEstoque = rstObter.Fields("qtdEstoque")
    unidade = rstObter.Fields("unidade")
    valorUnitario = rstObter.Fields("valorUnitario")
    obter = True
    'Fecha o Recordset obter
    rstObter.close
Exit_obter:
    Set rstObter = Nothing
    Exit Function
Err_obter:
    obter = False
    GoTo Exit_obter
End Function
'Método Salvar [Com conhecimento de SQL]
'Salva o objeto atual na tabela correspondente dentro do Banco de dados
Function salvar() As Boolean
On Error GoTo Err_salvar
    Dim objCon As New aclConexaoBD
    Dim strSql As String
    If existe(bkpCodProduto) Then
        strSql = "Update Produto " & _
            "Set codProduto = " & objCon.valorSql(codProduto) & _
                ", descricao = " & objCon.valorSql(descricao) & _
                ", estoqueMinimo = " & objCon.valorSql(estoqueMinimo) & _
                ", qtdEstoque = " & objCon.valorSql(qtdEstoque) & _
                ", unidade = " & objCon.valorSql(unidade) & _
                ", valorUnitario = " & objCon.valorSql(valorUnitario) & _
            " Where codProduto = " & objCon.valorSql(bkpCodProduto)
        salvar = (objCon.executa(strSql) > 0)
    Else
        salvar = incluir
    End If
    If salvar Then
        'Atualiza as variáveis de backup com o novo valor da chave
        bkpCodProduto = codProduto
    End If
Exit_salvar:
    Exit Function
Err_salvar:
    salvar = False
    GoTo Exit_salvar
End Function
'Método baixarEstoque()
'Atualiza o estoque diminuindo a quantidade informada como parâmetro
'e devolve um valor booleano que indica o sucesso da operação;
Function baixarEstoque(argQtd As Double) As Boolean
    
    If dblQtdEstoque - Abs(argQtd) < 0 Then
        baixarEstoque = False
    Else
        dblQtdEstoque = dblQtdEstoque - Abs(argQtd)
        baixarEstoque = salvar
    End If
End Function
'Método subirEstoque()
'Atualiza o estoque acrescentando a quantidade informada como
'parâmetro e devolve um valor booleano que indica o sucesso
'da operação;
Function subirEstoque(argQtd As Double) As Boolean
    
    dblQtdEstoque = dblQtdEstoque + Abs(argQtd)
    subirEstoque = salvar
End Function
'Método estoqueBaixo
'Verifica o estoque atual e compara com o valor de estoque mínimo
'cadastrado para produto e devolve um valor booleano que indica
'se o valor atual está abaixo do previsto.
Function estoqueBaixo() As Boolean
    
    If dblQtdEstoque < dblEstoqueMinimo Then
        estoqueBaixo = True
    End If
End Function
'Fim da classe...
Pontos Importantes
Desta vez, complementando os itens tratados no artigo anterior, vamos destacar o pontos a seguir.
1. Controle do estoque: Ao baixarmos o estoque de um produto, devemos verificar se é possível diminuir a quantidade informada, pois seria impossível retirar mais do que a quantidade existente em estoque. Além disso, não podemos baixar quantidades negativas de produto, pois isto significa que estaríamos aumentando a quantidade ao invés de diminuir. O método somente retornará True se for possível realizar a operação.
Function baixarEstoque(argQtd As Double) As Boolean
    
    If dblQtdEstoque - Abs(argQtd) <= 0 Then
        baixarEstoque = False
    Else
        dblQtdEstoque = dblQtdEstoque - Abs(argQtd)
        baixarEstoque = salvar
    End If
End Function
2. Conversão de dados no momento da atribuição do valor: Para a atribuição de algumas propriedades será realizada uma conversão dos dados. No caso da unidade o valor será convertido em letras maiúsculas para que fique padronizado. Para os atributos que armazenas a quantidade de produto em estoque e estoque mínimo não serão aceitos valores negativos, sendo assim todas as quantidades serão convertidas para seus respectivos valores absolutos.
Property Let estoqueMinimo(argEstoqueMinimo As Variant)
    dblEstoqueMinimo = Abs(argEstoqueMinimo)
End Property
Property Let qtdEstoque(argQtdEstoque As Variant)
    dblQtdEstoque = Abs(argQtdEstoque)
End Property
Property Let unidade(argUnidade As Variant)
    strUnidade = UCase(argUnidade)
End Property
A Interface Gráfica
Assim como no artigo anterior, para que possamos visualizar e manipular os dados dos produtos devemos criar um formulário com campos para preenchimento e botões de comando que coordenem as ações sobre os dados.
A seguir serão definidas as características para o formulário no qual iremos trabalhar com os dados dos objetos relativos aos produtos. Neste caso as especificações de design também são apenas sugestões, porém as informações de origem de dados, bloqueio de campos e formatos de dados são obrigatórias, sob pena de não obter a funcionalidade desejada. Estas especificações estarão marcadas com um asterisco vermelho ao lado.
No formulário teremos uma lista contendo os produtos cadastrados, um campo de texto para realizar buscas, alguns campos de texto para digitação das informações e os botões de comando para criar, salvar e excluir registros.
Obs: Somente as propriedades que foram alteradas para um valor diferente do padrão serão apresentadas. Para as demais utilize o padrão do sistema ou o valor que desejar, desde que não comprometa a funcionalidade do sistema.
Formulário
Nome: FProduto Largura: 19cm Altura: Cabeçalho (1cm) / Detalhe (10cm) Legenda: Sistema de Vendas Estilo da borda: fino Seletores de registro: Não Botões de navegação: Não Linhas divisórias: Não Barras de rolagem: Nenhuma Caixa de controle: Sim Botão Fechar: Sim Botões Min Max: Nenhum Popup: Sim Janela Restrita: Não
Controle Listbox
Nome: lstProduto * Origem da linha: SELECT Produto.codProduto, Produto.descricao,
                 Produto.unidade, Produto.valorUnitario, Produto.estoqueMinimo,
                 Produto.qtdEstoque FROM Produto ORDER BY Produto.descricao; *
Tipo de Origem da Linha: Tabela/Consulta *
Coluna acoplada: 1 *
Número de colunas: 6 *
Largura das colunas: 0cm;5cm;1cm;2cm;1cm;1cm *
Largura: 10cm
Cor do fundo: Cinza claro
Controles Textbox
Nome: txtPesquisa * Cor do fundo: Amarelo Alinhamento: Esquerda Nome: txtCodigo * Ativado: Não * Bloqueado: Sim * Cor do fundo: Cinza Alinhamento: Centro Nome: txtDescricao * Cor do fundo: Azul claro Alinhamento: Esquerda Nome: txtUnidade * Cor do fundo: Azul claro Alinhamento: Esquerda Nome: txtValorUnitario * Cor do fundo: Azul claro Alinhamento: Direita Formato: Unidade Monetária Nome: txtQtdEstoque * Cor do fundo: Azul claro Alinhamento: Centro Formato: 00 Nome: txtEstoqueMinimo * Cor do fundo: Cinza Alinhamento: Centro Formato: 00
Botões de Comando
Nome: btnNovo * Legenda: Novo Cor da Fonte: Azul escuro Nome: btnSalvar * Legenda: Salvar Cor da Fonte: Azul escuro Nome: btnExcluir * Legenda: Excluir Cor da Fonte: Vermelho escuro
Como sugestão de design os campos deverão estar posicionados conforme demonstrado na figura a seguir, assim como devem ser adicionadas as legendas dos campos, as quais não foram descritas anteriormente:

Códigos do Formulário
Para que nosso formulário seja capaz de manipular os dados dos objetos produto deveremos implementar as funcionalidades necessárias que permitam criar um novo produto, buscar um produto já cadastrado, editar seus dados, salvá-lo ou excluí-lo.
Sendo assim criaremos algumas funções genéricas que sejam úteis para quantos procedimentos delas necessitem, reaplicando o conceito da reutilização de código. Além disso incluiremos os códigos dos campos que possuem eventos, além dos botões de comando.
Todos os códigos a seguir deverão ser colocados no módulo do formulário FProduto.
1. Pesquisa de produtos: Para facilitar a busca de produtos por qualquer parte do nome utilizaremos um campo de texto cujo valor será o elemento condicional para o código SQL que será atribuído ao controle lstProduto, atualizando sua propriedade Origem da Linha após cada alteração realizada no campo de pesquisa. Para isto devemos colocar o código no evento Ao Alterar do campo txtPesquisa.
Private Sub txtPesquisa_Change()
 
  lstProduto.RowSource = "SELECT codProduto, descricao, " & _
        "unidade, valorUnitario, estoqueMinimo, qtdEstoque " & _
        "FROM Produto " & _
        "WHERE descricao Like '*" & txtPesquisa.Text & "*' " & _
        "ORDER BY Produto.descricao;"
  lstProduto.Requery
 
End Sub
2. Limpeza dos campos: Para efetuar a limpeza dos campos de preenchimento utilizaremos um procedimento genérico cuja função será a de atribuir o valor nulo a todos os campos de texto e enviar o foco ao campo txtDescricao.
Private Sub limpaCampos() txtCodigo = Null txtDescricao = Null txtUnidade = Null txtValorUnitario = Null txtQtdEstoque = Null txtEstoqueMinimo = Null txtDescricao.SetFocus End Sub
3. Novo registro: Para a criação de um novo registro em branco simplesmente iremos chamar o procedimento limpaCampos() no evento Ao Clicar do botão btnNovo.
Private Sub btnNovo_Click() Call limpaCampos End Sub
4. Atualização de campos: Assim como fizemos um procedimento genérico que limpa os campos para a criação de um novo registro teremos também um que preencha os campos com as informações de um objeto produto passadas como parâmetro, ou seja, o procedimento recebe um objeto completo e lança os valores de seus atributos nos campos do formulário.
Private Sub atualizaCampos(argProduto As clsProduto) txtCodigo = argProduto.codProduto txtDescricao = argProduto.descricao txtUnidade = argProduto.unidade txtValorUnitario = argProduto.valorUnitario txtQtdEstoque = argProduto.qtdEstoque txtEstoqueMinimo = argProduto.estoqueMinimo End Sub
5. Escolha de produto: Já que teremos também que trabalhar com produtos já cadastrados, devemos implementar alguma maneira de recuperar suas informações. Faremos isto utilizando a Listbox lstProduto, que utilizará o procedimento atualizaCampos() para preencher os campos com as informações do objeto do produto que foi clicado.
Private Sub lstProduto_Click()
  Dim objProduto As New clsProduto
  Dim codigoProduto As Long
  
  codigoProduto = lstProduto.Value
  
  If objProduto.obter(codigoProduto) Then
    Call atualizaCampos(objProduto)
  End If
End Sub
6. Montagem de um objeto: Esta também é uma função genérica que será utilizada por outros procedimentos ou funções. Seu objetivo é criar um novo objeto produto, coletar os dados digitados nos campos, atribuir ao objeto criado, e devolvê-lo para quem chamou a função.
Private Function buscaCampos() As clsProduto
  Set buscaCampos = New clsProduto
  If IsNull(txtCodigo) Then
    txtCodigo = proximoCodigo("codProduto", "Produto")
  End If
  
  buscaCampos.codProduto = txtCodigo
  buscaCampos.descricao = txtDescricao
  buscaCampos.unidade = txtUnidade
  buscaCampos.valorUnitario = txtValorUnitario
  buscaCampos.qtdEstoque = txtQtdEstoque
  buscaCampos.estoqueMinimo = txtEstoqueMinimo
End Function
7. Salvando um produto: Depois de informados os dados de um novo produto, ou alterados os dados de um produto já cadastrado, necessitaremos de um procedimento que efetue a gravação destes dados. Para isto o botão btnSalvar conterá o código necessário no evento Ao Clicar. Ele fará uso da função buscaCampos(), a qual montará o objeto a ser salvo, e também o método salvar() do objeto, apresentando uma mensagem ao usuário com o resultado da operação. Após salvar os dados de um produto também deveremos atualizar a Listbox para que apresente estes dados, sejam eles novos ou apenas alterados.
Private Sub btnSalvar_Click() Dim objProduto As clsProduto If Not IsNull(txtDescricao) And Not IsNull(txtUnidade) And _
  Not IsNull(txtValorUnitario) Then
    
    Set objProduto = buscaCampos
    
    If objProduto.salvar Then
      MsgBox "O produto foi salvo com sucesso.",vbInformation,"Salvar produto"
      lstProduto.Requery
      Call atualizaCampos(objProduto)
    Else
      MsgBox "Ocorreu um erro durante o salvamento.", vbExclamation, _ 
      "Salvar produto"
    End If
  Else
    MsgBox "Informe os dados do produto.", vbExclamation, "Salvar produto"
  End If
End Sub
8. Excluindo um produto: Além de criar e alterar os dados de um produto, é importante que também possamos excluí-lo definitivamente de nosso cadastro. Logo devemos também implementar a funcionalidade para o botão btnExcluir, que conterá o código necessário também no evento Ao Clicar. Ele também deverá fazer uso da função buscaCampos() para a montagem do objeto a ser excluído, pois caso contrário a classe não saberá que objeto deve ser excluído. Em seguida utilizaremos o método excluir() do objeto, apresentando uma mensagem ao usuário com o resultado da operação. É claro que após excluir um produto também deveremos atualizar a Listbox para que a mesma reflita as alterações realizadas.
Private Sub btnExcluir_Click()
 
  Dim objProduto As clsProduto
  
  If Not IsNull(txtCodigo) Then
    
    If MsgBox("Confirma a exclusão do registro?", vbQuestion + vbYesNo, _ 
    "Excluir produto") = vbYes Then
      
      Set objProduto = buscaCampos
      
      If objProduto.excluir Then
        MsgBox "O registro foi excluído com sucesso.", vbInformation, _
        "Excluir produto"
        lstProduto.Requery
        Call limpaCampos
      Else
        MsgBox "Ocorreu um erro durante a exclusão.", vbExclamation, _
        "Excluir produto"
      End If
      
    End If
    
  End If
   
End Sub
Sistema de Exemplo
Novamente será disponibilizado o link para download do sistema de vendas, já atualizado com todos os recursos do estado de desenvolvimento em que se encontrar o projeto.
Mais uma vez recomendo aos desenvolvedores que o consultem apenas para tirar dúvidas e realizar comparações. Aqueles que realmente quiserem aprender façam toda a codificação e a montagem das telas manualmente. Somente assim a sua mente irá se defrontar com as dificuldades do processo e assimilará os passos necessários para a resolução dos problemas e a conclusão dos objetivos.
Segue o link para download:
Caso ainda não esteja com uma tela principal abra o formulário FProduto diretamente na janela Banco de Dados (Access 2003-) ou no Painel de Navegação (Access 2007+).
Conclusão
Nesta fase não encontramos praticamente nada de novo, mas tivemos a chance de relembrar a maioria dos procedimentos vistos até o momento. A codificação das funcionalidades da classe Produto são muito semelhantes à codificação da classe Cliente. Porém este era o nosso objetivo: relembrar o passo-a-passo necessário para utilizar objetos em sistemas informatizados no MS-Access/VBA.
Com relação à parte realmente prática da série de artigos estamos chegando na reta final. No próximo artigo, que será o último em que trabalharemos com a programação de classes, poderemos perceber um pouco mais da dinâmica de troca de informações entre os objetos de um sistema. Ao realizarmos vendas de produtos para clientes estaremos englobando a utilização de todas as nossas classes de uma só vez, trabalhando com vários objetos instanciados simultaneamente para a conclusão das tarefas.
Com toda certeza você, caro leitor que nos acompanha, já deve estar imaginando os objetos se interagindo, os métodos realizando tarefas e retornando valores, os atributos recebendo e fornecendo valores, os objetos sendo enviados inteiramente para métodos de outros objetos, e assim sucessivamente.
É isto aí, orgulhe-se de dizer: Agora estou quase dominando essa tal de OO!
Encontro vocês no próximo então...
Artigos Relacionados
Utilizando Classe no Access - Introdução
Utilizando Classe no Access - Parte 1 - Orientação a Objetos
Utilizando Classe no Access - Parte 2 - Programação OO no Access/Vba
Utilizando Classe no Access - Parte 4 - As Classes Auxiliares
Utilizando Classe no Access - Parte 5 - A Classe Cliente
Utilizando Classe no Access - Parte 6 - A Classe Produto
Utilizando Classe no Access - Parte 7 - As Classes Venda e Detalhe de Venda
Utilizando Classe no Access - Parte 8 - Finalização do Sistema
Utilizando Classe no Access - Parte 9 - Genesis: A Ferramenta Case
Utilizando Classe no Access - Parte 10 - Conclusão
Como estudar com o Pesquisador de Objetos
| 
			4 comentários Adelmo    10/08/2023 05:23:22 Bom dia! Você tem a planilha pronta, eu sou leigo no assunto mais tenho alguns conhecimento achei muito interessante suas informações. obrigado. meu e-mail nab875@hotmail.com Lázaro Kiosa   29/06/2021 07:46:31 ainda não explorei o site porque so descobri agora, mais ja da para ti parabenizar pelo site Sr Plinio Plinio Mabesi   09/02/2021 11:27:15 Obrigado Luis... Eu é que agradeço a sua visita no site do amigo Avelino. Visite também meu site: www.mabesi.com Luis Eugenio Riquelme Pino   09/02/2021 02:08:07 Este é um dos melhores sites sobre MS Access, muito bom e profundo, bem explicado, Obrigado Sr Plinio  | 

