Controle de estoque eficiente no MS Access
Matéria da extinta revista FórumAccess
Autora: Andréa Tikhomiroff
Uma das situações que mais gera dúvidas em fóruns de discussão é, sem dúvida, o controle de estoque. Como fazê-lo de forma clara e funcional? Como obter uma posição correta do meu estoque? Como calcular o valor empenhado? Como calcular o preço de venda dos meus produtos? Essas são apenas algumas das questões colocadas repetidas vezes nos muitos fóruns espalhados pela internet.
A abordagem que tratarei aqui visa, exclusivamente, o controle de estoque propriamente dito. Desta forma com uma tabela de produtos e uma de movimentação, não me preocupando com a modelagem de outras entidades (clientes e fornecedores, pedidos, notas fiscais de entrada e saída e outros mais) que geralmente existem em uma aplicação completa.
Vamos então pensar única e exclusivamente no controle de estoque. A primeira coisa que precisamos é ter uma tabela de produtos (tblProdutos) com os seguintes campos:
IdProduto autonumeração, chave primária
NomeProduto texto
EmbalagemProduto texto (ex: 500g, 1L, etc.)
EstoqueMinimo número, inteiro longo
Ativo sim/não
Vamos precisar também de uma tabela para registrar a movimentação do estoque (tblMovimentacao):
IDMovimentacao autoNumeração, chave primária
IDProduto número,inteiro longo, chave estrangeira
TipoMovimentacao número,inteiro (será usado apenas 1 para entrada e 2 para saída
DataMovimentacao data/hora, data abreviada
QuantidadeMovimentacao número, inteiro longo
ValorMovimentacao moeda
As duas tabelas deverão estar unidas num relacionamento um-para-muitos através do campo IDProduto. É importante, nesse caso, definir a integridade referencial com a exclusão em cascata. A integridade referencial garante que só haverá movimentação para produtos realmente cadastrados; e a exclusão em cascata elimina automaticamente toda a movimentação existente para um produto que porventura venha a ser excluído.
Com relação à exclusão, é importante verificar se a exclusão de produtos com movimentação registrada deve ser permitida ou não. Em caso negativo, deve-se criar uma regra que impeça essa exclusão. Veremos como fazer isso mais à frente.
Para a entrada de dados, criaremos três formulários: frmProduto, frmEntrada e frmSaida. O formulário frmProduto conterá todos os campos da tabela tblProduto, assim como o formulário frmEntrada e o frmSaida terão como origem as consultas qryEntrada e qrySaida, ambas com todos os campos da tblMovimentacao. A diferença entre esses será o critério no campo TipoMovimentacao, que na qryEntrada será igual a 1 e na qrySaida será igual a 2.
Mais alguns ajustes:
1. Tanto no frmEntrada quanto no frmSaida, alteraremos o campo IDPorduto para caixa de combinação. Essa caixa será baseada na tblProduto e terá dois campos: IDProduto e NomeProduto (este em ordem crescente). Na propriedade Largura da Coluna, a primeira deverá ter tamanho 0 e a segunda tamanho suficiente para conter o nome dos produtos. Talvez seja necessário, também, alterar a propriedade Largura da Lista, para que o segundo campo apareça corretamente.
2. Ainda nos formulários frmEntrada e frmSaida, alteraremos algumas propriedades do campo TipoMovimentacao: Valor Padrão, como já foi falado, será 1 para entrada e 2 para saída. Ativado deve ser setado para NÃO e bloqueado para SIM. Assim, evitaremos que esse campo possa ser editado. Vale dizer que em uma aplicação profissional bem acabada esse campo poderá estar oculto, mas, como estamos apenas fazendo um modelo, é interessante deixá-lo visível. Desta forma, podemos facilmente ver o seu valor à medida que testamos a aplicação.
Apenas para facilitar, criei um botão de comando cmdSair (com a ajuda do assistente) para fechar cada formulário e alterei a propriedade Permitir Alterações de Estrurura "Somente modo estrutura"
Para podermos analisar o funcionamento do sistema é fundamental que tenhamos um bom número de registros cadastrados. Eu inseri alguns dados para garantir consistência e entendimento nos cálculos a serem efetuados. Os dados lançados na tabela tblMovimentacao abrangem o período de 01/01/2005 a 31/12/2005
Verificando o saldo atual de estoque (em quantidade)
Para verificar o saldo atual do seu estoque, você pode criar duas consultas de agrupamento unidas a uma terceira consulta. Para fazer isso, crie uma consulta em modo estrutura usando a tblProduto e a consulta qryEntrada.
Ligue o campo IDProduto da tabela ao campo correspondente da consulta, alterando o relacionamento para que sejam exibidos todos os produtos da tabela e apenas os registros relacionados da consulta.
Arraste para a grade de consulta:
1. o campo IDProduto da tblProduto
2. o campo QuantidadeMovimentacao da qryEntrada
3. o campo ValorMovimentacao da qryEntrda
Para diferenciar o campo de quantidade e de valor na consulta que criaremos à frente, nomeie-os como QtEntrada e VlEntrada.
Clique no simbolo da somatória E para definir os agrupamentos:
1. IDProduto - Agrupar por
2. QtEntrada - Soma
3. VlEntrada - Soma
Salve a consulta com o nome qryAgrupaEntrada.
Faça a mesma coisa para criar a qryAgrupaSaida, apenas usando a qrySaida no lugar da qryEntrada e substituindo os nomes qtEntrada e VlEntrada para QtSaida e VlSaida.
Calcular o saldo agora se tornou simples. Crie uma nova consulta em modo estrutura. Inclua a tblProduto, a qryAgrupaEntrada e a qryAgrupaSaida, arrumando os relacionamentos para que todos os registros da tabela apareçam, independente de haver itens relacionados nas consultas.
Inclua na grade de consulta os campos:
1. IDProduto da tblProduto
2. QtEntrada e VlEntrada da qryAgrupaEntrada
3. QtSaida e VlSaida da qryAgrupaSaida
No próximo campo em branco digite:
SaldoQt: Nz([QtEntrada])-Nz([QtSaida])
O uso da expressão Nz garante o cálculo mesmo que não exista algum dos valores para o produto. Salve a consulta com o nome qrySaldoEstoque.
Falando sobre preço médio
Antes de começarmos a calcular o saldo do estoque em valor, é importante falar um pouco sobre as várias formas de efetuar esse cálculo.
Antigamente, quando os controles de estoque eram bem mais simples, o cálculo de preço médio era efetuado apenas em alguns períodos, como balanço. o CMV (custo das mercadorias vendidas) era obtido pelo Estoque Inicial + Compras - Estoque Final.
Com a produção crescente e o aperfeiçoamento dos cálculos de estoque, surgiram novas técnicas, nomeadas em Português como PEPS, UEPS e MPM.
O PEPS (Primeiro que Entra Primeiro que Sai) usa o custo do lote mais antigo até que ele se esgote, então passa-se ao custo do segundo lote e assim sucessivamente. Existem várias desvantagens nessa metodologia, uma delas é que teremos que controlar vários lotes para sabermos sempre o custo do mais antigo. Na prática, muitas vezes, isso pode ser inviável.
Outra desvantagem deste método é que a tendência é de que sempre as primeiras compras possuam um custo mais baixo e, com o decorrer do tempo, o valor das comprar aumente devido a inflação, fazendo com que tenhamos um estoque com valor mais alto, um custo mais baixo e um lucro maior. Em outras palavras, que a empresa pague mais impostos e mais dividendos.
O UEPS (Último que Entra Primeiro que Sai) funciona de forma inversa, ou seja, usa-se o custo do lote mais recente. É proibido pela legislação do Imposto de Renda no Brasil.
O MPM (Média Ponderada Móvel) é a técnica mais usada em todo o mundo, pois é obtida através da divisão do saldo financeiro pelo saldo físico. Essa é a técnica que usaremos aqui.
Calculando o MPM
Vamos voltar à qrySaldoEstoque. Note que já temos a soma dos valores das entradas e a soma dos valores das saída (VlEntrada e VlSaida). Resta, agora, calcular o preço médio. No próximo campo em branco digite:
MPM: Selmed([SaldoQt]=0;0;(Nz([VlEntrada])-Nz([VlSaida))/[SaldoQt])
Definindo os relatórios
Agora que já temos o saldo e o preço médio calculados (ainda que, por enquanto, sem critério de data), podemos começar a pensar nos relatórios a serem criados. Veremos então três tipos:
1. Posição do estoque em data definida: listará os produtos calculando o saldo em quantidade e o MPM na data solicitada.
2. Movimentação de estoque: funcionará como um extrato bancário, listando as movimentações dia-a-dia, fornecendo um saldo atualizado de quantidade e valor.
3. Posição atual do estoque: mostrará a última entrada, ultima saída e saldo atual em quantidade e valor, bem como o MPM atual.
Posição do estoque na data
Para criar esse relatório, basta copiar as consultas qryAgrupaEntrada e qryAgrupaSaida como qryAgrupEntradaData e qryAgrupaSaidaData respectivamente e especificar o critério de data [Digite a data desejada:] em ambas. Para isso, abra a consulta qryAgrupaEntradaData e acrescente, à grade, o campo DataMovimentacao, na linha Total selecione Onde e, na linha de critério, <=[Digite a data desejada:]. Salve as alterações e faça o mesmo com a consulta qryAgrupaSaidaData.
Crie agora uma consulta similar à qrySaldoEstoque, com o nome qrySaldoEstoqueData, usando as consultas recém-criadas.
Basta agora criar um relatório, com a ajuda do assistente, usando a qrySaldoEstoqueData e você tera o saldo do estoque e o MPM de cada produto na data solicitada. Salve-o com o nome rptSaldoEstoqueData.
Podemos editá-lo para exibir o nome do produto ao invés do seu código. Para isso, basta selecionar o campo IDProduto e, no menu formatar, escolha caixa de combinação. Vincule a caixa à tblproduto, usando os campos IDProduto e NomeProduto. Na propriedade Largura das colunas, deixe a primeira com tamanho 0 e a segunda em um tamanho que se adapte ao relatório. É possível, também, acrescentar um campo texto ao cabeçalho do relatório informando a data pesquisada. Clique no botão AB! da barra de ferramentas para desenhar a caixa na posição desejada. Em seguida, digite:
="Posição em " & formato([informe a data desejada:];"data abreviada")
Feche, salvando as alterações.
Para o relatório de movimentação de estoque será necessário mexer com algumas consultas. Em primeiro lugar, precisaremos do saldo anterior ao período examinado. Depois, precisaremos verificar, dia-a-dia, dentro do período especificado, todas as movimentações.
Para o cálculo do saldo anterior podemos usar consultas semelhantes às usadas anteriormente. Para isso, copie as consultas qryAgrupaEntrada e qryAgrupaSaida como qryEntradasAnteriores e qrySaidasAnteriores. Altere, em ambas, o critério <=[Digite a data desejada] para <[Data Inicial:].
Crie agora uma consulta no modo estrutura, incluindo a tblProduto e as duas duas consultas que acabou de criar. Altere o relacionamento entre IDProduto da tabela e os campos correspondentes das consultas para que todos os registros da tabela sejam mostrados, independente de haver relação na consulta.
Arraste para a grade os campos: IDProduto, QtEntrada, VlEntrada,QtSaida e VlSaida. Inclua os dois campos:
1. SaldoQt: Nz([QtEntrada])-Nz([QtSaida])
2. MPM: Selmed([SaldoQt]=0;0;(Nz([VlEntrada])-Nz([VlSaida]))/[SaldoQt])
Salve a consulta como qrySaldoEstoqueAnterior.
De posse do saldo anterior de cada produto, basta criar uma consulta que retorne a movimentação do estoque no período. Para isso, crie uma consulta em modo estrutura usando a tblMovimentacao e a qrySaldoEstoqueAnterior. Ligue o campo IDProduto da consulta ao campo correspondente da tabela, alterando o relacionamento para que todos os registros da consulta sejam exibidos, independente de haver registro na tabela.
Adicione à grade da consulta:
1. Os campos IDProduto, SaldoQt e MPM da qrySaldoEstoqueAnterior
2. O campo DataMovimentacao da tblMovimentacao
Além disso, digite nos próximos campos livres:
1. Entrada: Selmed([TipoMovimentacao]=1;[QuantidadeMovimentacao];0)
2. EntradaValor: Selmed([TipoMovimentacao]=1;[ValorMovimentacao];0)
3. Saida: Selmed([TipoMovimentacao]=2;[QuantidadeMovimentacao];0)
4. SaidaValor: Selmed([TipoMovimentacao]=2;[ValorMovimentacao];0)
Na linha de critério do campo DataMovimentacao digite: Entre [Data inicial:] E [Data final:]. Salve a consulta com o nome qryMovimentacao.
Para criar o relatório, pode-se usar o assistente e, depois, editá-lo. lembre-se, apenas, de agrupar o relatório pelo IDProduto. Salve-o como rptMovimentacao.
Edite o relatório colocando os campos SaldoQt e MPM junto ao cabeçalho IDProduto. Arrume os campos de forma que haja espaço à direita para a colocação de campos de cálculo (saldo e MPM dinâmicos).
Crie uma caixa de texto txtSaldoQuant com a origem do controle =Nz([entrada])-Nz([saida]). Altere a propriedade Soma Parcial para Por Grupo. Assim, esse cálculo será sempre acrescido do saldo anterior, dentro do grupo IDProduto. Ou seja, ao mudar de produto, a soma recomeça. Para que esse cálculo seja somado ao saldo inicial (e, aí sim, termos o saldo correto), crie uma nova caixa de texto (txtSaldoAcum) com a origem do controle: =[txtSaldoQuant]+[SaldoQt].
Para calcular o MPM dinâmico, crie uma terceira caixa de texto (txtSaldoValor) e use na oriegm do controle: = Nz([EntradaValor])-Nz({SaidaValor]). Também para essa caixa, coloque a propriedade Soma Parcial como Por Grupo. Para finalizar, crie uma quarta caixa de texto (txtMPMDin) e, na sua origem: =([txtSaldoValor]+([MPM]*[SaldoQt]))/[txtSaldoAcum].
Claro, se pensarmos em um relatório realmente profissional, o txtSaldoQuant e o txtSaldoValor deveriam estar invisíveis, pois a ninguém interessará acompanhar o processo de cálculo, apenas visualizar o resultado final. Nesse caso, para maior entendimento do exemplo, eles continuam sendo mostrados.
Posição atual do estoque
Para esse último relatório, uma consulta simples de agrupamento unida a uma consulta que retorne os saldos atuais será suficiente.
Para retornar os saldos, basta usar aquelas consultas feitas inicialmente, sem parâmetro de data. Portanto, resta fazer a consulta para retornar os últimos registros de cada produto. Crie uma consulta em modo estrutura, usando a tblMovimentacao e a qrySaldoEstoque. Não esqueça de unir os campos IDProduto de ambas, forçando para que apareçam todos os registros da consulta, independente de haver relação na tabela. Inclua os campos IDProduto, SaldoQt e MPM da consulta e os campos TipoMovimentacao, DataMovimentacao, QuantidadeMovimentacao e ValorMovimentacao da tabela. Clique no símbolo do somatório para agrupar, selecionando na linha Total:
1. IDPorduto - agrupar por
2. SaldoQt - agrupar por
3. MPM - agrupar por
4. TipoMovimentacao - agrupar por
5. DataMovimentacao - agrupar por
6. QuantidadeMovimentacao - último
7. ValorMovimentacao - último
Salve a consulta como qryEstoqueAtual
Crie o relatório com o auxilio do assistente, não deixando de criar um agrupamentp pelo IDProduto e um pelo TipoMovimentacao. Salve com o nome rptEstoqueAtual e modifique a estrutura da seguinte maneira:
1. Altere o campo IDProduto para caixa de combinação, procedendo da mesma forma que fizemos anteriormente para exibir o nome do produto.
2. Leva os campos SaldoQt e MPM para o cabeçalho IDProduto.
3. Altere o campo TipoMOvimentacao para caixa de combinação, alterando o tipo de origem da linha para Lista de Valores.
a. Na propriedade Origem da Linha digite 1;Última Entrada:;2;Última Saída:.
b. Na propriedade Número de colunas digite 2
c. Na propriedade Largura das Colunas digite 0;5
4. Leve os campos ÚltimoDeDataMovimentacao, ÚltimoDeQuantidadeMovimentacao e ÚltimoDeValorMovimentacao para o cabeçalho TipoMovimentacao, posicionando-os ao lado do campo TipoMovimentacao.
5. Clique na barra cinza onde está escrito Datalhe e altere a propridade Visivel para Não.
A partir daqui, muito ainda pode ser feito para um completo controle de estoque. Mas, certamente, os primeiros passos foram dados! Aperfeiçoar os formulários, fazer a ligação com outras entidades (fornecedores, clientes ets.), ampliar as consultas e os modelos de relatórios...Há muito trabalho pela frente.
Marcos Vasconcelos Souza 07/06/2019 17:05:56
Como devo proceder no caso de kits. Por exemplo: ao dar saída em uma pizza de mussarela, os ítens que a compõe serão baixados no estoque.
Desde já gradeço sua orientação.
Avelino Sampaio 27/01/2019 01:15:41
é preciso adquirir uma assinatura do site, para ter acesso irrestrito aos arquivos e ao vídeos do site.
Sebastião 26/01/2019 07:46:46
Excelente explicação. muito bem. Só que eu não consigo baixar o arquivo ZIP. Coloco o email. data de nascimento e número 127. Mesmo assim o arquivo não é baixado. Está com algum problema? Alguém pode me ajudar?
Cláudio Machado 22/12/2018 04:11:25
Como sempre perfeito nas explicações e exibição de conteúdos para salvar a nós reles mortais programadores.