CREATE OR REPLACE FUNCTION public.calculacmc(integer, integer, integer, timestamp without time zone, numeric, numeric, character varying, integer, boolean) RETURNS void LANGUAGE plpgsql AS $function$ declare filial alias for $1; codigolancto alias for $2; codigomaterial alias for $3; datalancto alias for $4; quantidade alias for $5; valorunitario alias for $6; tipolancto alias for $7; arredondamento alias for $8; cancelado alias for $9; tipo_lancto_entrada character varying := upper('e'); tipo_lancto_saida character varying := upper('s'); casas_arredondamento integer := 4; aux tipovalorestoque; valorunitaux numeric(15,4); qtdeaux numeric(15,4); valortotalaux numeric(15,4); somavaloraux numeric(15,4); somaqtdeaux numeric(15,4); novounitarioaux numeric(15,4); codigoproximaentradaaux integer := null; dataproximaentradaaux date := null; primeirocalculoaux boolean := false; auxcursor refcursor; auxrecord record; begin if (cancelado) then --se o lancamento foi cancelado --busca a primeira entrada apos o lancamento select lce.lce_codigo ,lce.lce_datahora into codigoproximaentradaaux ,dataproximaentradaaux from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and upper(lce.lce_tipo) = tipo_lancto_entrada and date_trunc('day', lce.lce_datahora) >= date_trunc('day', datalancto) and lce.lce_codigo > codigolancto order by lce.lce_datahora ,lce.lce_codigo limit 1; if (codigoproximaentradaaux is null or dataproximaentradaaux is null) then codigoproximaentradaaux := codigolancto; dataproximaentradaaux := datalancto; end if; --busca a quantidade total e o ultimo valor unitario ate o lancamento imediatamente anterior ao proximo lancamento de entrada select sum(case when upper(lce.lce_tipo) = tipo_lancto_entrada then coalesce(cmc.cmc_quantidade, 0) else coalesce(cmc.cmc_quantidade, 0) * (-1) end) into aux.quantidade from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and date_trunc('day', lce.lce_datahora) <= date_trunc('day', dataproximaentradaaux) and lce.lce_codigo < codigoproximaentradaaux; select coalesce(cmc.cmc_valorunitario, 0) into aux.valor from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and upper(lce.lce_tipo) = tipo_lancto_entrada and date_trunc('day', lce.lce_datahora) <= date_trunc('day', datalancto) and lce.lce_codigo < codigoproximaentradaaux order by lce.lce_datahora desc ,lce.lce_codigo desc limit 1; --verifica se os valores foram encontrados, e, caso não tenham sido: ainda não foi feito nenhum lançamento de entrada para o material --deve-se então utilizar os valores de última compra do material if (aux.valor is null or aux.quantidade is null) then select mat_valorultcompra ,mat_qtdeultcompra into aux.valor ,aux.quantidade from material where fil_codigo = filial and mat_codigo = codigomaterial; end if; aux.quantidade = coalesce(aux.quantidade, 0); aux.valor = coalesce(aux.valor, 0); novounitarioaux := round(aux.valor, casas_arredondamento, arredondamento); --busca os cmcs dos lancamentos subsequentes open auxcursor for select * from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null --and upper(lce.lce_tipo) = tipo_lancto_entrada and date_trunc('day', lce.lce_datahora) >= date_trunc('day', datalancto) and lce.lce_codigo > codigolancto order by lce.lce_datahora ,lce.lce_codigo; elsif (upper(tipolancto) = tipo_lancto_saida) then --se o lancamento for de saida --busca o valor atual do cmc select cmc.cmc_valorunitario ,cmc.cmc_quantidade into aux from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and upper(lce.lce_tipo) = tipo_lancto_entrada order by lce.lce_datahora desc ,lce.lce_codigo desc limit 1; --verifica se os valores foram encontrados, e, caso não tenham sido: ainda não foi feito nenhum lançamento de entrada para o material --deve-se então utilizar os valores de última compra do material if (aux.valor is null or aux.quantidade is null) then select mat_valorultcompra ,mat_qtdeultcompra into aux.valor ,aux.quantidade from material where fil_codigo = filial and mat_codigo = codigomaterial; end if; valorunitaux := round(aux.valor, casas_arredondamento, arredondamento); qtdeaux := round(quantidade, casas_arredondamento, arredondamento); valortotalaux := round(valorunitaux * qtdeaux, casas_arredondamento, arredondamento); --insere na tabela de cmc insert into lanctoestoquecmc (fil_codigo ,cmc_codigo ,lce_codigo ,cmc_valorunitario ,cmc_quantidade ,cmc_valor ,cmc_valorunitarioentrada) values (filial ,nextval('lanctoestoquecmc_' || filial || '_sequence') ,codigolancto ,valorunitaux ,qtdeaux ,valortotalaux ,null); elsif (upper(tipolancto) = tipo_lancto_entrada) then --se o lancamento for de entrada --busca o saldo total ate a data select sum(coalesce(case when upper(lce.lce_tipo) = tipo_lancto_entrada then cmc.cmc_quantidade else cmc.cmc_quantidade * (-1) end, 0)) into aux.quantidade from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and date_trunc('day', lce.lce_datahora) <= date_trunc('day', datalancto); --busca o ultimo valor unitario ate a data select coalesce(cmc.cmc_valorunitario, 0) into aux.valor from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and upper(lce.lce_tipo) = tipo_lancto_entrada and date_trunc('day', lce.lce_datahora) <= date_trunc('day', datalancto) order by lce.lce_datahora desc ,lce.lce_codigo desc limit 1; --verifica se os valores foram encontrados, e, caso não tenham sido: ainda não foi feito nenhum lançamento de entrada para o material --deve-se então utilizar os valores de última compra do material if (aux.valor is null or aux.quantidade is null) then select mat_valorultcompra ,mat_qtdeultcompra into aux.valor ,aux.quantidade from material where fil_codigo = filial and mat_codigo = codigomaterial; end if; aux.quantidade = coalesce(aux.quantidade, 0); aux.valor = coalesce(aux.valor, 0); --calcula os novos valores aux.quantidade := round(aux.quantidade, casas_arredondamento, arredondamento); aux.valor := round(aux.valor * aux.quantidade, casas_arredondamento, arredondamento) + round(valorunitario * quantidade, casas_arredondamento, arredondamento); aux.quantidade := round(aux.quantidade, casas_arredondamento, arredondamento) + round(quantidade, casas_arredondamento, arredondamento); novounitarioaux := case when aux.quantidade = 0 or aux.valor = 0 then 0 else aux.valor / aux.quantidade end; novounitarioaux := round(novounitarioaux, casas_arredondamento, arredondamento); --insere na tabela de cmc insert into lanctoestoquecmc (fil_codigo ,cmc_codigo ,lce_codigo ,cmc_valorunitario ,cmc_quantidade ,cmc_valor ,cmc_valorunitarioentrada) values (filial ,nextval('lanctoestoquecmc_' || filial || '_sequence') ,codigolancto ,novounitarioaux ,quantidade ,round(novounitarioaux * quantidade, casas_arredondamento, arredondamento) ,valorunitario); --busca os cmcs dos lancamentos subsequentes open auxcursor for select * from lanctoestoque lce join lanctoestoquecmc cmc on lce.fil_codigo = cmc.fil_codigo and lce.lce_codigo = cmc.lce_codigo where lce.fil_codigo = filial and lce.mat_codigo = codigomaterial and lce.lce_datahoracancelamento is null and upper(lce.lce_tipo) = tipo_lancto_entrada and date_trunc('day', lce.lce_datahora) > date_trunc('day', datalancto) order by lce.lce_datahora ,lce.lce_codigo; end if; --caso o lancamento tenha sido cancelado ou seja de entrada, deve-se fazer o reprocessamento dos lancamentos subsequentes if (cancelado or upper(tipolancto) = tipo_lancto_entrada) then loop fetch auxcursor into auxrecord; if (auxrecord is null) then close auxcursor; exit; end if; if (upper(auxrecord.lce_tipo) = tipo_lancto_saida) then if (primeirocalculoaux) then aux.quantidade := round(aux.quantidade, casas_arredondamento, arredondamento) - round(auxrecord.cmc_quantidade, casas_arredondamento, arredondamento); end if; continue; end if; --calcula os novos valores aux.valor := round(aux.valor * aux.quantidade, casas_arredondamento, arredondamento) + round(auxrecord.cmc_valorunitarioentrada * auxrecord.cmc_quantidade, casas_arredondamento, arredondamento); aux.quantidade := round(aux.quantidade, casas_arredondamento, arredondamento) + round(auxrecord.cmc_quantidade, casas_arredondamento, arredondamento); novounitarioaux := case when aux.valor = 0 or aux.quantidade = 0 then 0 else aux.valor / aux.quantidade end; novounitarioaux := round(novounitarioaux, casas_arredondamento, arredondamento); aux.valor = novounitarioaux; --atualiza os cmcs update lanctoestoquecmc set cmc_valorunitario = novounitarioaux ,cmc_valor = round(novounitarioaux * auxrecord.cmc_quantidade, casas_arredondamento, arredondamento) where fil_codigo = filial and cmc_codigo = auxrecord.cmc_codigo; primeirocalculoaux := true; end loop; end if; end; $function$ ; --[lode] CREATE OR REPLACE FUNCTION public.calculasaldoestoque(integer, integer, integer, integer, timestamp without time zone, timestamp without time zone, character varying, numeric, numeric, character varying, character varying, boolean) RETURNS void LANGUAGE plpgsql AS $function$ declare filial alias for $1; codigolancto alias for $2; codigomaterial alias FOR $3; codigocelula alias FOR $4; datalancto alias FOR $5; dataconciliacao alias for $6; tipolancto alias FOR $7; quantidade alias FOR $8; valorunitario alias FOR $9; tipooperacaolancto alias FOR $10; situacaolancto alias FOR $11; cancelado alias FOR $12; TIPO_OPERACAO_TRANSFERENCIA CHARACTER VARYING := 'T'; dataaux DATE; vsaldoestoque tiposaldoestoque; operacao NUMERIC(15,4); gerarfinanceiro boolean; arredondamento integer; begin if (filial is null) then raise exception 'A filial nao foi informada.'; end if; if (codigolancto is null) then raise exception 'O codigo do lancamento nao foi informado.'; end if; if (codigomaterial is null) then raise exception 'O codigo do material nao foi informado.'; end if; if (codigocelula is null) then raise exception 'O codigo da celula nao foi informado.'; end if; if (tipolancto is null) then raise exception 'O tipo do lancamento nao foi informado.'; end if; IF (upper(situacaolancto) = 'A' AND datalancto IS NULL) THEN RAISE EXCEPTION 'A data do lancamento nao foi informada.'; END IF; IF (upper(situacaolancto) = 'O' AND dataconciliacao IS NULL) THEN RAISE EXCEPTION 'A data de conciliacao do lancamento nao foi informada.'; END IF; --caso seja cancelamento de lancamento de entrada, deve-se verificar se o estoque nao ficara negativo if (tipolancto = 'E' AND cancelado) then if (verificapodecancelarlanctoestoque(filial, codigomaterial, codigocelula, datalancto, quantidade) = FALSE) then RAISE EXCEPTION 'Nao e possivel fazer o cancelamento da entrada, pois, o estoque ficaria negativo.'; end if; end if; --data a ser usada dataaux := COALESCE(dataconciliacao, datalancto); --operacao de estoque operacao := CASE WHEN upper(tipolancto) = 'E' THEN quantidade ELSE quantidade * (-1) END; operacao := CASE WHEN cancelado then operacao * (-1) else operacao end; --busca o saldo de estoque da data vsaldoestoque := saldoestoquematerial(filial, codigomaterial, dataaux); --se nao ha saldo anterior a data e a operacao e de subtracao (e nao esta cancelada), deve-se lancar uma excecao if (tipolancto = 'S' AND not cancelado AND (vsaldoestoque is null OR vsaldoestoque.saldo < quantidade)) THEN raise exception 'Nao ha saldo em estoque suficiente para realizar o lancamento de saida.'; end if; --caso haja saldo na data if (vsaldoestoque is not null and vsaldoestoque.data = dataaux) then --atualiza o saldo da data e das datas subsequentes UPDATE saldoestoque SET sde_saldo = sde_saldo + operacao WHERE fil_codigo = filial AND mat_codigo = codigomaterial and sde_data >= dataaux; else --insere o saldo na data INSERT INTO saldoestoque (fil_codigo ,mat_codigo ,sde_data ,sde_saldo ,sde_totalpeps ,sde_totalueps ,sde_totalcmc) values (filial ,codigomaterial ,dataaux ,COALESCE(vsaldoestoque.saldo, 0) + operacao ,0 ,0 ,0); --atualiza os saldos subsequentes UPDATE saldoestoque SET sde_saldo = sde_saldo + operacao WHERE fil_codigo = filial AND mat_codigo = codigomaterial and sde_data > dataaux; end if; --caso o lancamento esteja conciliado, deve-se movimentar o estoque das celulas if (upper(situacaolancto) = 'O') then execute calculasaldoestoquecelula(filial, codigolancto, codigomaterial, codigocelula, dataconciliacao, tipolancto, quantidade, cancelado); end if; --verifica se o parametro para gerar financeiro esta ativado select CASE WHEN COALESCE(par_perguntarvalorestoque, 'N') = 'N' THEN false else true end into gerarfinanceiro from parametros; if (gerarfinanceiro) then --busca o arredondamento configurado nos parametros gerais select par_tipoarredondamentopreco into arredondamento from parametros; if (tipooperacaolancto <> TIPO_OPERACAO_TRANSFERENCIA) then --invoca o calculo do CMC execute calculacmc(filial, codigolancto, codigomaterial, datalancto, quantidade, valorunitario, tipolancto, arredondamento, cancelado); --invoca o calculo do PEPS execute calculapeps(filial, codigolancto, codigomaterial, datalancto, quantidade, valorunitario, tipolancto, arredondamento, cancelado); --invoca o calculo do UEPS execute calculaueps(filial, codigolancto, codigomaterial, datalancto, quantidade, valorunitario, tipolancto, arredondamento, cancelado); end if; --invoca o calculo do saldo de estoque geral (da data do lancamento em diante) execute atualizavalorsaldo(filial, codigomaterial, datalancto, arredondamento); --invoca o calculo do saldo de estoque da celula (da data do lancamento em diante) --execute atualizavalorsaldocelula(filial, codigomaterial, datalancto, arredondamento); execute atualizavalorsaldoestoquecelula(filial, codigomaterial, datalancto, arredondamento); end if; end; $function$ ; --[lode] insert into atualizacoes(atu_nome) values ('v24000001_080124.sql'); --[lode] alter table senhagerada alter gui_id drop not null; alter table totensenha add tot_som varchar(2000); insert into atualizacoes(atu_nome) values ('v24000002_090124.sql'); --[lode]