saldos_e_movimentacoes

Relatório de Saldos e Movimentação

O objetivo desse manual é documentar tudo o que envolve o processo do cálculo mas de uma forma mais técnica, para facilitar os testes do suporte ou futuras correções de bugs pelo desenvolvimento.

A forma como é calculado os Saldos e Movimentações dos produtos foi alterada. Anteriormente o relatório calculava toda a movimentação no momento da impressão, o que gerava lentidão quando o cliente possuía uma base de dados muito grande.

A partir de agora os saldos serão calculados diariamente, evitando que o relatório tenha uma gama de dados grande para processar.

Os saldos e movimentações serão armazenados na tabela SaldosEstoque que contém num único registro todas as movimentações do produto no dia, como: saldo anterior, entradas, saídas, ajustes e vendas.

Por exemplo:

SELECT * FROM SaldosEstoque

Resultado:

idSaldosEstoque    salEmpresa    salProduto    salDataMovimento    salSaldoAnterior    
     38705             1            1059         27/12/2016           0,00    
salEntradas    salSaidas    salAjusteMais    salAjusteMenos    salVendas
   300,00           0,00         0,00             0,00           0,00    

A rotina que calcula os saldos e armazena na tabela SaldosEstoque é a sp dbo.spc_mov_processa_saldos_estoque.sql.

Quem executa a sp é o AutomatizeGO, através do plugin SaldoEstoque.dll.

O processamento é feito a cada 1 hora e filtrará somente movimentos que foram alterados a mais de meia hora, isso para evitar rodar a rotina com o cliente ainda digitando um movimento.

O resultado da execução do AutomatizeGO pode ser verificada no log do mesmo em: C:\Arquivos de Programas\Automatize\log\AutomatizeGO\.

Exemplo:

Caso o processamento ocorra com sucesso:

28/11 14:39:13,807 [30] INFO AutomatizeGo.ServiceGo - Info plugin AutomatizeGo.Plugins.SaldoEstoque, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null:
EXEC SALDO ESTOQUE

Abaixo um exemplo caso ocorra um problema:

28/11 14:04:26,034 [6] INFO AutomatizeGo.ServiceGo - Info plugin AutomatizeGo.Plugins.SaldoEstoque, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null:
NÃO ENCONTRADO TABELA E SP DE PROCESSAMENTO DO SALDO

Note que o erro foi “NÃO ENCONTRADO TABELA E…”. Para esse erro ocorrer, uma das seguintes situações deve ter ocorrido:

  • A tabela SaldosEstoque não existir no banco;
  • A sp dbo.spc_mov_processa_saldos_estoque.sql não exista;
  • O campo MovimentoProdutoItem.mpiSaldoProcessado não exista (abaixo esse campo é explicado);
  • O campo MovimentoProdutoItemComposicao.mpcSaldoProcessado não exista (abaixo esse campo é explicado).

Na primeira execução, caso a tabela SaldosEstoque esteja vazia, a sp irá recalcular toda a movimentação de todos os produtos e armazenar nela. Sendo assim, para fins de teste, caso haja a necessidade de se recalcular tudo novamente, basta apagar a tabela da seguinte forma:

TRUNCATE TABLE SaldosEstoque

O procedimento pode demorar um pouco (em alguns testes com bases grandes, menos de 3 minutos) dependendo da quantidade de movimentos do cliente, então é necessário verificar o log do AutomatizeGO se a mensagem “EXEC SALDO ESTOQUE” foi apresentada ou algum outro erro.

O saldo é calculado nas seguintes situações:

  • logo na primeira execução do plugin do AutomatizeGO ao ver que a tabela SaldosEstoque está vazia
  • Ao alterar a situação do movimento
  • Ao excluir um movimento
  • Ao incluir um produto no movimento
  • Ao alterar a quantidade de um produto dentro de um movimento
  • Ao excluir um produto do movimento

Para permitir esses monitoramentos foram criados os seguintes gatilhos (triggers):

  • dbo.tu_MovimentoProduto.sql
    • é disparado quando houver alteração na situação do movimento.
      • um registro será criado na tabela temporária TmpSaldosEstoque para que o AutomatizeGO processe essa alteração.
  • dbo.td_MovimentoProduto.sql
    • é disparado quando houver exclusão do movimento
      • da mesma foram um registro será criado na tabela temporária TmpSaldosEstoque para que o AutomatizeGO processe essa exclusão.
  • dbo.tu_MovimentoProdutoItem.sq
    • é disparado ao alterar a quantidade de um produto dentro do movimento.
      • os campos MovimentoProdutoItem.mpiSaldoProcessado e MovimentoProdutoItemComposicao.mpcSaldoProcessado serão setados para 0 (zero), para que o AutomatizeGO processe a alteração
  • dbo.td_MovimentoProdutoItem.sql
    • é disparado excluir um produto do movimento.
      • um registro será criado na tabela temporária TmpSaldosEstoque para cada produto e cada composição, para que o AutomatizeGO processe essa alteração.

A rotina de cálculo irá rodar nas filiais e, na central caso essa esteja indicada no campo Node.NodeDest (abaixo).

Após rodar a sp na filial os registros da tabela SaldosEstoque são enviados para a central para permitir visualizar nela o relatório de Saldos e Movimentação da filial.

Nunca os dados serão enviados da central para as filiais ou de uma filial para outra.

Não é possível visualizar o relatório de uma filial estando na outra. Por exemplo, a filial 1 não conseguirá ver da 2 e vice-versa. Na central será possível ver das duas filiais.

Para isso teremos que verificar a tabela Node na central.

Exemplo de central que irá rodar:

SELECT * FROM node

Resultado:

KEY = corp       nodeDest = 4 

Exemplo de central que não irá rodar:

SELECT * FROM node

Resultado:

KEY = corp       nodeDest = NULL

Sim, como o AutomatizeGO irá rodar o cálculo dos saldos a cada 1 hora, talvez seja conveniente utilizar o script abaixo.

Não esqueça de trocar a filial no início do script, caso necessário:

SET NOCOUNT ON
 
DECLARE @idEmpresa	INT
 
SET @idempresa = 1  -- << TROQUE A FILIAL AQUI >>
 
 
-- se não tem registro na tabela então ja recalcula tudo pela primeira vez
IF NOT EXISTS(SELECT top 1 1 FROM SaldosEstoque)
BEGIN
    print 'Primeiro recalculo'
	EXEC spc_mov_processa_saldos_estoque @idempresa=@idEmpresa, @dataInicial='01/01/2000'
 
	UPDATE MovimentoProdutoItem SET
        mpiSaldoProcessado = 1
 
	UPDATE MovimentoProdutoItemComposicao SET
        mpcSaldoProcessado = 1	
	RETURN
END
 
-- exclui os temporarios processados
DELETE FROM TmpSaldosEstoque WHERE saeProcessado = 1
 
 
-- PROCURA pelos registros não processados do movimento para executar a spc_mov_processa_saldos_estoque
DECLARE @curEmpresa INT, @curProduto INT, @curDt smalldatetime
        , @curIdMpi INT, @curIdMpc INT, @curProcessado bit, @curidTmpSaldos INT
        , @msgerro VARCHAR(2000)
 
DECLARE @TBPROC TABLE  (
    idEmpresa INT,
    prod INT,
    dt datetime,
    idMpi INT,
    idMpc INT,
	sysInc datetime,
    processado bit,
	idTmpSaldos INT
)
 
INSERT INTO @TBPROC (idEmpresa, prod, dt, idMpi, idMpc, sysInc, processado, idTmpSaldos)
    SELECT DISTINCT 
            idEmpresa = mvpEmpresa
        , prod = MPI.mpiProduto
        , Dt = CAST(FLOOR(CAST(MVP.mvpData AS FLOAT)) AS DATETIME) --retira a hora da data
        , IDMPI = idMovimentoProdutoItem
        , NULL 
		, isnull(mpi.sysRegistro, mpi.sysInc)
        , 0
		, NULL
	FROM MovimentoProdutoItem MPI
		INNER JOIN MovimentoProduto MVP ON MVP.idMovimentoProduto	= MPI.mpiMovimentoProduto 
	WHERE MVP.mvpEmpresa = @idEmpresa
        AND isnull(MPI.mpiSaldoProcessado,0) = 0
        AND (IsNull(MVP.mvpSituacao, 0) IN (0,9))
 
    UNION ALL
 
    -- composição
    SELECT DISTINCT 
            idEmpresa = mvpEmpresa
        , MPC.mpcProduto
        , Dt = CAST(FLOOR(CAST(MVP.mvpData AS FLOAT)) AS DATETIME) 
        , NULL
        , idMovimentoProdutoItemComposicao
        , isnull(mpi.sysRegistro, mpi.sysInc)
        , 0
		, NULL
	FROM MovimentoProdutoItemComposicao MPC
		INNER JOIN MovimentoProdutoItem MPI ON MPI.idMovimentoProdutoItem	= MPC.mpcMovimentoProdutoItem
		INNER JOIN MovimentoProduto		MVP ON MVP.idMovimentoProduto		= MPI.mpiMovimentoProduto 
 
	WHERE MVP.mvpEmpresa = @idEmpresa
        AND isnull(MPC.mpcSaldoProcessado,0) = 0
	    AND (IsNull(MVP.mvpSituacao, 0) IN (0,9))
 
 
	UNION ALL 
 
	SELECT DISTINCT
		  saeEmpresa
		, saeProduto
		, CAST(FLOOR(CAST(saeData AS FLOAT)) AS DATETIME)
		, NULL
		, NULL
		, sysInc
		, 0
		, idTmpSaldosEstoque
	FROM TmpSaldosEstoque
	WHERE saeProcessado = 0
	  AND saeEmpresa = @idEmpresa
 
 
    ORDER BY idEmpresa, prod, dt
 
 
SELECT * FROM @TBPROC
 
 
 -- DEFINE UM CURSOR DINAMICO PORQUE VOU ALTERAR OS DADOS DA COLUNA
 -- PROCESSADO E QUERO QUE REFLITA NOS PROCESSAMENTOS SEGUINTES
DECLARE curMov CURSOR LOCAL DYNAMIC 
    FOR SELECT 
            idEmpresa ,
            prod ,
            dt ,
            processado 
        FROM @TBPROC
		--WHERE (sysInc is null or sysInc < dateadd(minute, -30, current_timestamp)) -- pega somente o que foi modificado a mais de 30min
 
--
-- ABRE O CURSOR E PERCORRE OS MOVIMENTOS
--    
OPEN curMov
FETCH NEXT FROM curMov INTO @curEmpresa, @curProduto, @curDt, @curProcessado
 
WHILE @@FETCH_STATUS = 0
BEGIN
    --print 'Processa?: ' + cast( @curProduto as varchar) + ' | ' + convert(varchar(12), @curDt, 103) + ' > ' + CAST(@curProcessado as varchar)
 
    IF @curProcessado = 0
    BEGIN 
        --print 'Calculando...'
        BEGIN try
            EXEC dbo.spc_mov_processa_saldos_estoque 
                  @idEmpresa	= @curEmpresa
	            , @DataInicial  = @curDt
                , @DataFinal    = NULL
	            , @idProduto    = @curProduto
        END try
        BEGIN catch
            SET @MSGErro = 'Erro processando salods: ' +
					        ERROR_MESSAGE()+' /L:' + CAST(error_line() AS VARCHAR)
		    RAISERROR(@MSGErro, 16, 1)
			GOTO SAIR
        END catch
 
        -- a spc_mov_processa_saldos_estoque processa todos os movimentos
        -- do produto a partir de uma data, então se existe mais algum 
        -- registro do produto com uma data superior a @curDt, vou marcar como processado
 
        UPDATE MovimentoProdutoItem SET
            mpiSaldoProcessado = 1
        WHERE IDMovimentoProdutoItem IN (
            SELECT idMpi
            FROM @TBProc
            WHERE idEmpresa = @curEmpresa
              AND prod = @curProduto
              AND dt >= @curDt
        )
 
        --composição
        UPDATE MovimentoProdutoItemComposicao SET
            mpcSaldoProcessado = 1
        WHERE idMovimentoProdutoItemComposicao IN (
            SELECT idMpc
            FROM @TBProc
            WHERE idEmpresa = @curEmpresa
              AND prod = @curProduto
              AND dt >= @curDt
        )     
 
		-- temporaria com os excluidos
		UPDATE TmpSaldosEstoque SET
			saeProcessado = 1
		WHERE idTmpSaldosEstoque IN (
            SELECT idTmpSaldos
            FROM @TBProc
            WHERE idEmpresa = @curEmpresa
              AND prod = @curProduto
              AND dt >= @curDt
        )     
 
 
        UPDATE @TBPROC SET
            processado = 1
        WHERE idEmpresa = @curEmpresa
            AND prod = @curProduto
            AND dt >= @curDt
    END
 
    FETCH NEXT FROM curMov INTO @curEmpresa, @curProduto, @curDt, @curProcessado
END
 
SAIR:
CLOSE curMov
DEALLOCATE curMov

Qual versão do AutomatizeGO que possui o plugin SaldoEstoque.dll?

A partir da 5.0.6.

  • saldos_e_movimentacoes.txt
  • Última modificação: 2017/12/01 18:07
  • por cassol