Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Michael.Dev

Problemas com While em Procedure

Recommended Posts

Olá galera, boa tarde.

 

Bom estou com alguns probleminhas aqui e gostaria de saber a opiniões de vocês.

Estou fazendo o controle de saída de produtos do estoque, porém tenho tbm que controlar Lotes.

 

Exemplo: Na entrada de materiais/produtos, tenho Lotes por Produtos, e na hora de realizar a saída dos mesmos,

preciso abater do lote mais antigo e se faltar produtos para abater tenho que selecionar o segundo LOTE mais

antigo e abater a quantidade dele.

 

Estou desenvolvendo a procedure, porém estou com dificuldades na hora de verificar se falta quantidade para ser abatia, e se houver pegar o segundo lote mais antigo e abater-lhe a quantidade.

 

Aqui esta a procedure:

 

ALTER PROCEDURE [dbo].[sPAbaterLote]
(
   @IDPRODUTO INT,
   @QTD DECIMAL(15,2)
)
AS
BEGIN


   DECLARE @DATA INT;
   DECLARE @QUANTIDADE DECIMAL(15,2);
   DECLARE @DATAPROX DATETIME;
   DECLARE @VALORTOTAL DECIMAL(15,2);


       --exec @DATAPROX = SPObterProxDataLotes;

       SET @DATA = (SELECT TOP 1 tbE.ID_ENTRADA
				    FROM tb_Entradas as tbE
						 WHERE tbE.DATA_ENTRADA = (SELECT MIN(tbE2.DATA_ENTRADA) FROM tb_Entradas as tbE2));

       SET @QUANTIDADE = (SELECT
							QUANTIDADE
							FROM tb_Items_Entrada
							WHERE ID_ENTRADA = @DATA);


      SET @QUANTIDADE  = @QUANTIDADE - @QTD;

      IF(@QUANTIDADE != 0)
      BEGIN
	  SELECT
			QUANTIDADE
			FROM tb_Items_Entrada
			WHERE ID_ENTRADA = @DATA
      END

 

 

ATUALIZEI A PROCEDURE..

 

ALTER PROCEDURE [dbo].[sPAbaterLote]
(
   @IDPRODUTO INT,
   @QTD DECIMAL(15,2)
)
AS
BEGIN


   DECLARE @ID_ENTRADA INT;
   DECLARE @QUANTIDADE DECIMAL(15,2);
   DECLARE @DATAPROX DATETIME;
   DECLARE @VALORTOTAL DECIMAL(15,2);
   DECLARE @ID_LOTE INT;


       --exec @DATAPROX = SPObterProxDataLotes;

       SET @ID_ENTRADA = (SELECT TOP 1 tbE.ID_ENTRADA
				         FROM tb_Entradas as tbE
						 WHERE tbE.DATA_ENTRADA = (SELECT MIN(tbE2.DATA_ENTRADA) FROM tb_Entradas as tbE2));

       SET @QUANTIDADE = (SELECT
							QUANTIDADE
							FROM tb_Items_Entrada
							WHERE ID_ENTRADA = @ID_ENTRADA);

	SET @ID_LOTE = (SELECT
							ID_LOTE
							FROM tb_Items_Entrada
							WHERE ID_ENTRADA = @ID_ENTRADA);


      IF(@QUANTIDADE > @QTD)
      BEGIN

         SET @QUANTIDADE = @QUANTIDADE - @QTD;

      	 IF(@QUANTIDADE != 0)
      	 BEGIN
      	       UPDATE
      	           tb_Items_Entrada
		       SET
		          QUANTIDADE = @QUANTIDADE
		       WHERE
		         ID_ENTRADA = @ID_ENTRADA
		         AND ID_ITEM = @IDPRODUTO
		         AND ID_LOTE = @ID_LOTE
     END

Compartilhar este post


Link para o post
Compartilhar em outros sites

A lógica (grosso modo) creio deverá fazer um laço de repetição.

 

Recebe a quantidade a ser abatida.

 

Enquanto houver quantidade a ser abatida faça
 Localiza Lote mais antigo com saldo
   Abate do Saldo do lote a Quantidade
Fim enquanto

Se ainda resta quantidade a ser abatida
 Tratar esta exceção.

Compartilhar este post


Link para o post
Compartilhar em outros sites

GALERA, DESENVOLVI ESTA PROCEDURE COM A SEGUINTE FUNÇÃO:

 

OBS: estou desenvolvendo um modulo de Entrada e Saída de produtos/materiais do estoque,

só que, quando dou entrada de produtos cada um possui um lote, que contem sua data de validade.

 

consegui fazer com que a procedure abate o lote mais antigo, e se faltar quantidade para abater, seleciona o

segundo lote mais antigo e abate sua quantidade.

 

Minha dificuldade agora é fazer com que, enquanto faltar quantidade para abater, ele vem percorrendo

o segundo, terceiro, quarto até zerar a quantidade para abater os lotes.

 

Seguem abaixo, a procedure:

 

ALTER PROCEDURE [dbo].[sPAbaterLote]
(
   @IDPRODUTO INT,
   @QTD DECIMAL(15,2)
)
AS
BEGIN


   DECLARE @ID_ENTRADA INT;
   DECLARE @QUANTIDADE DECIMAL(15,2);
   DECLARE @DATAPROX DATETIME;
   DECLARE @VALORTOTAL DECIMAL(15,2);
   DECLARE @ID_LOTE INT;


        SET @ID_ENTRADA = (SELECT TOP 1 tbE.ID_ENTRADA
				         FROM tb_Entradas as tbE
						 WHERE tbE.DATA_ENTRADA = (SELECT MIN(tbE2.DATA_ENTRADA) FROM tb_Entradas as tbE2));

     SET @ID_LOTE = (SELECT ID_LOTE
							FROM tb_Items_Entrada
							WHERE ID_ENTRADA = @ID_ENTRADA
							AND ID_ITEM = @IDPRODUTO);

        SET @QUANTIDADE = (SELECT
							QUANTIDADE
							FROM tb_Items_Entrada
							WHERE ID_ENTRADA = @ID_ENTRADA
							AND ID_ITEM = @IDPRODUTO
							AND ID_LOTE = @ID_LOTE);




        IF(@QUANTIDADE >= @QTD)
        BEGIN

          SET @QUANTIDADE = @QUANTIDADE - @QTD;

      	   UPDATE
  	           tb_Items_Entrada
	       SET
	          QUANTIDADE = @QUANTIDADE
	       WHERE
	         ID_ENTRADA = @ID_ENTRADA
	         AND ID_ITEM = @IDPRODUTO
	         AND ID_LOTE = @ID_LOTE
     END
     ELSE
     BEGIN


          SET @QUANTIDADE = @QTD - @QUANTIDADE;

      	   IF(@QUANTIDADE != 0)
      	   BEGIN
      		   UPDATE
  				   tb_Items_Entrada
			   SET
				  QUANTIDADE = 0
			   WHERE
				 ID_ENTRADA = @ID_ENTRADA
				 AND ID_ITEM = @IDPRODUTO
				 AND ID_LOTE = @ID_LOTE



				   SET @ID_ENTRADA = (SELECT tbE1.ID_ENTRADA 
										  	 FROM tb_Entradas as tbE1 
											 WHERE tbE1.DATA_ENTRADA > (SELECT MIN(tbE3.DATA_ENTRADA) 
																		       FROM tb_Entradas as tbE3));

				   SET @ID_LOTE = (SELECT
											 ID_LOTE
											 FROM tb_Items_Entrada
											 WHERE ID_ENTRADA = @ID_ENTRADA
											 AND ID_ITEM = @IDPRODUTO);

				   SET @QUANTIDADE = (SELECT
								 			 QUANTIDADE
											 FROM tb_Items_Entrada
											 WHERE ID_ENTRADA = @ID_ENTRADA
											 AND ID_ITEM = @IDPRODUTO
											 AND ID_LOTE = @ID_LOTE);




					 SET @QUANTIDADE = @QUANTIDADE - @QTD;

		   			 IF(@QUANTIDADE != 0)
		   			 BEGIN
		   				   UPDATE
		   					   tb_Items_Entrada
							   SET
								  QUANTIDADE = @QUANTIDADE
							   WHERE
								 ID_ENTRADA = @ID_ENTRADA
								 AND ID_ITEM = @IDPRODUTO
								 AND ID_LOTE = @ID_LOTE


			 END

	    END

        END

END

Compartilhar este post


Link para o post
Compartilhar em outros sites

GALERA, QUANDO EXECUTO ESTA PROCEDURE

 

-- Por exemplo, tenho 3 Lotes com as seguintes Quantidades

 

LOTE 1 - 400

LOTE 2 - 50

LOTE 3 - 50

 

QUANDO EXECUTO A PROC, passo por paramentro o id do produto e a quantidade.

 

EXEC SPAbaterLote 13, 500;

 

QUANDO EXECUTASSE ESTA PROCEDURE, DEVERIA SUBTRAIR, 500 - 400 = 100

E ZERAR O LOTE, DEPOIS NO PROXIMO LOTE 100 - 50 = 50, E ZERAR O LOTE,

LOGO DEPOIS 50 - 50 = 0 E ZERAR O 3 LOTE.

 

MAS A PROC SO ESTA SUBTRAINDO O 400 E ZERANDO E O 50 E ZERANDO, E NÃO SUBTRAI O PROXIMO LOTE.

 

 

 

 

 

 

ALTER PROCEDURE [dbo].[sPAbaterLote]
(
   @IDPRODUTO INT,
   @QTD DECIMAL(15,2)
)
AS
BEGIN


	 DECLARE @ID_ENTRADA INT;
	 DECLARE @QUANTIDADE DECIMAL(15,2);
	 DECLARE @DATAPROX DATETIME;
         DECLARE @VALORTOTAL DECIMAL(15,2);
 	 DECLARE @ID_LOTE INT;


        -- Seleciono o id da entrada do lote mais antigo
        SET @ID_ENTRADA = (SELECT TOP 1 tbE.ID_ENTRADA
		           FROM tb_Entradas as tbE
			   WHERE tbE.DATA_ENTRADA = (SELECT MIN(tbE2.DATA_ENTRADA)
						              FROM tb_Entradas as tbE2));

  	 -- Seleciono o id do lote
     SET @ID_LOTE = (SELECT ID_LOTE
			    FROM tb_Items_Entrada
			    WHERE ID_ENTRADA = @ID_ENTRADA
			    AND ID_ITEM = @IDPRODUTO);
        -- Seleciono a quantidade
        SET @QUANTIDADE = (SELECT
			  QUANTIDADE
			  FROM tb_Items_Entrada
			  WHERE ID_ENTRADA = @ID_ENTRADA
			  AND ID_ITEM = @IDPRODUTO
			  AND ID_LOTE = @ID_LOTE);



        -- Se a Quantidade do lote for > que a quantidade passada por parâmetro
        IF(@QUANTIDADE >= @QTD)
        BEGIN

          -- Faz a subtração
          SET @QUANTIDADE = @QUANTIDADE - @QTD;

      	   -- Atualiza a quantidade do Lote
      	   UPDATE
  	           tb_Items_Entrada
	       SET
	          QUANTIDADE = @QUANTIDADE
	       WHERE
	         ID_ENTRADA = @ID_ENTRADA
	         AND ID_ITEM = @IDPRODUTO
	         AND ID_LOTE = @ID_LOTE
     END
     -- Senão, se a quantidade que for passada por parametro for maior
     ELSE
     BEGIN
           -- Enquanto a quantidade for maior que zero
      	    WHILE(@QUANTIDADE > 0)
      	    BEGIN

      	        -- Irá subtrair a quantidade
      			SET @QUANTIDADE =  @QTD - @QUANTIDADE;

			-- Zera a quantidade do lote mais antigo 
      	   	    UPDATE
  	                  tb_Items_Entrada
		  SET
		     QUANTIDADE = 0
	          WHERE
			ID_ENTRADA = @ID_ENTRADA
			AND ID_ITEM = @IDPRODUTO
			AND ID_LOTE = @ID_LOTE


			       --Pega o ID da entrada do segundo lote mais antigo
SET @ID_ENTRADA = (SELECT TOP 1 tbE1.ID_ENTRADA 
	   FROM tb_Entradas as tbE1 
	   WHERE tbE1.DATA_ENTRADA > (SELECT MIN(tbE3.DATA_ENTRADA) 
																		       FROM tb_Entradas as tbE3));

				   -- Pego o ID deste Lote				       
SET @ID_LOTE  = (SELECT ID_LOTE
                  FROM tb_Items_Entrada
                  WHERE ID_ENTRADA = @ID_ENTRADA
                  AND ID_ITEM = @IDPRODUTO);

				   -- Pego a Quantidade deste Lote
SET @QTD = (SELECT QUANTIDADE
           FROM tb_Items_Entrada
           WHERE ID_ENTRADA = @ID_ENTRADA
           AND ID_ITEM = @IDPRODUTO
           AND ID_LOTE = @ID_LOTE);



	       	         -- Se a quantidade for  >= a Zero
   IF(@QUANTIDADE >= 0)
    BEGIN

	--Subtraio a quantidade deste Lote
     SET @QUANTIDADE = @QUANTIDADE - @QTD;

        -- Atualizo a Quantidade do Lote
	UPDATE
                    tb_Items_Entrada
	     SET
                      QUANTIDADE = @QUANTIDADE 
             WHERE
                      ID_ENTRADA = @ID_ENTRADA
                      ID_ITEM = @IDPRODUTO
                      AND ID_LOTE = @ID_LOTE
      END
END

   END

END

Compartilhar este post


Link para o post
Compartilhar em outros sites

A parte de localizar o lote mais antigo deveria estar na estrutura do laço.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não conheço a síntaxe de SqlServer mas a lógica é mais ou menos como eu disse no post #2

 

ou seja a estrutura deve sempre localizar o Lote mais antigo em aberto (quantidade > 0), assim o laço os Lotes até que acabem o Saldo e/ou os Lotes.

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.