Gerar parcelas dias da semana
24/10/2024
0
Minha rotina de gerar parcelas tem 2 opções:
por período(usuário informa o intervalo de dias)
por dia fixo(sempre no dia 15, por exemplo, IncMonth)
Pego o valor total, divido pelo numero de parcelas e uso o intervalo selecionado para gerar as parcelas.
Quando cai no sábado ou domingo, jogo a primeira parcela para a segunda-feira(IncDay), o problema é que a segunda parcela pega a data da primeira como base para calcular o próximo vencimento, mas deveria pegar a data original + prazo
Alguém tem uma rotina que faça isso?
Renan
Post mais votado
27/10/2024
DataOrigPrimParcela = 10/11/2024 NumParcelas = 10 for i:=0 to Pred(NumParcelas) do begin DataParcela:=AddMonths(DataOrigPrimParcela,i); case DayOfWeek(DataParcela) of 1: DataParcela:=DataParcela+1; 7: DataParcela:=DataParcela+2; end; end;
Obviamente, a rotina acima não checa se é feriado, que é muito mais complexa, pois depende de um cadastro de feriados.
Se houver uma função Feriado(Data) que retorna True se for feriado, você pode utilizar uma lógica simplificada, assim:
DataOrigPrimParcela = 10/11/2024 NumParcelas = 10 for i:=0 to Pred(NumParcelas) do begin DataParcela:=AddMonths(DataOrigPrimParcela,i); if ( (DayOfWeek(DataParcela) in [1,7]) or Feriado(DataParcela) ) then DataParcela:=DataParcela+1; end;
Arthur Heinrich
Mais Posts
28/10/2024
Arthur Heinrich
DataOrigPrimParcela = 10/11/2024 NumParcelas = 10 for i:=0 to Pred(NumParcelas) do begin DataParcela:=AddMonths(DataOrigPrimParcela,i); while ( (DayOfWeek(DataParcela) in [1,7]) or Feriado(DataParcela) ) do DataParcela:=DataParcela+1; end;
29/10/2024
Renan
Seria mesmo interessante ter ao menos os feriados nacionais.
Vou criar uma tabela e cadastrar.
Nesse meio tempo vou pesquisar uma função para adaptar ao código que você postou.
29/10/2024
Arthur Heinrich
{ Carregar Feriados } Q:=TQuery.Create; Q.Lines.Add('select data from feriados order by 1'); Q.Open; Feriados:=TStringList.Create; while (not Q.EOF) do begin Feriados.Add( FormatDateTime( Q.FieldByName('data').AsDateTime, 'yyyy-mm-dd') ); Q.Next; end; Feriados.Sorted:=true; Q.Close; Q.Free; { Verificar se uma data é feriado } if ( Feriados.IndexOf( FormatDateTime( DATA, 'yyyy-mm-dd') ) >=0 ) then else {não feriado}; function Feriado( Data : TDateTime ):Boolean; begin Result:=( Feriados.IndexOf( FormatDateTime( Data, 'yyyy-mm-dd') ) >=0 ); end;
30/10/2024
Renan
Logo que eu sobrar um tempo vou adaptar para usar na mesma instrução, a verificação de feriado e sabado e domingo.
abraço
05/11/2024
Renan
aqui recebo um erro de tipos incompativeis String e Integer, na ultima linha, na verificação do feriado
procedure TForm1.Button1Click(Sender: TObject); var Feriados : TStringList; Qry : TIBQuery; begin { Carregar Feriados } Qry := TIBQuery.Create(Self); Qry.SQL.Add('SELECT DATA FROM FERIADOS ORDER BY 1'); Qry.Open; Feriados := TStringList.Create; while not Qry.EOF do begin Feriados.Add(FormatDateTime('dd/mm/yyyy', Qry.FieldByName('DATA').AsDateTime)); Qry.Next; end; Feriados.Sorted:=true; FreeAndNil(Qry); { Verificar se uma data é feriado } if Feriados.IndexOf(FormatDateTime('dd/mm/yyyy', Qry.FieldByName('DATA').AsDateTime) >= 0) then else {não feriado}; end;
Aqui na função, ela não reconhece Feriados e a Qry(devo declarar essas variaveis como globais?)
function TForm1.Feriado(Data: TDateTime): Boolean; begin Result := (Feriados.IndexOf(FormatDateTime('dd/mm/yyyy', Qry.FieldByName('DATA').AsDateTime)) >= 0); end;
05/11/2024
Arthur Heinrich
if Feriados.IndexOf(FormatDateTime('dd/mm/yyyy', Qry.FieldByName('DATA').AsDateTime) >= 0) then
Deveria ser:
if Feriados.IndexOf(FormatDateTime('dd/mm/yyyy', Qry.FieldByName('DATA').AsDateTime)) >= 0 then
Eu declarei a variável Feriados, no exemplo, como uma variável local.
Mas você pode declarar como uma propriedade da classe que contém o método/função Feriados(), para que a função tenha acesso à lista carregada no início.
Ou, pode utilizar uma variável global, em uma unit utilizada para gerenciar os feriados, onde seja colocada a função Feriados().
A escolha tem mais a ver com o seu estilo de organização e o escopo em que a função feriados irá funcionar.
05/11/2024
Renan
if ( (DayOfWeek(DataParcela) in [1,7]) or Feriado(DataParcela) ) then DataParcela:=DataParcela+1;
07/11/2024
Emerson Nascimento
Os boletos que eu recebo (são muitos, hahahaha) têm vencimentos em qualquer dia, seja final de semana ou feriado.
Porque?
Se o vencimento do boleto for no sábado, eu pago na segunda (dia útil) e não há juros nem mora.
Mas se eu pagar na terça-feira serão cobrados juros e 3 dias de mora, porque o vencimento era sábado (cliente - eu - no "prejuízo").
Se esse boleto tivesse a data de vencimento alterada para segunda, ao pagar na terça eu pagaria menos mora (credor recebe menos pelo meu atrazo).
Boletos com vencimento em finais de semana ou feriados são aceitos no primeiro dia útil seguinte sem cobrança de juros ou mora (artigo 1º da Lei 7089/83).
Impostos e taxas são diferentes: caso o vencimento seja no final de semana ou feriado, o pagamento deve ser antecipado.
https://www.bcb.gov.br/meubc/faqs/p/boleto-com-vencimento-em-dia-nao-util-e-boleto-vencido
07/11/2024
Renan
Vou alterar para dias uteis, para fins de relatórios e fluxos de caixa.
08/11/2024
Emerson Nascimento
eu trabalho com 2 campos de vencimento: 1 para o vencimento real (aquele obtido a partir condição de pagamento) e outro para gravar a data útil, aquela que corresponde ao primeiro dia útil seguinte. caso o vencimento real já seja um dia útil, o conteúdo dos campos é o mesmo.
desta forma posso trabalhar com uma data para envio ao banco e outra data para relatórios. inclusive os relatórios são parametrizáveis quanto ao vencimento utilizado no filtro e o vencimento apresentado.
08/11/2024
Emerson Nascimento
eu trabalho com 2 campos de vencimento: 1 para o vencimento real (aquele obtido a partir condição de pagamento) e outro para gravar a data útil, aquela que corresponde ao primeiro dia útil seguinte. caso o vencimento real já seja um dia útil, o conteúdo dos campos é o mesmo.
desta forma posso trabalhar com uma data para envio ao banco e outra data para relatórios. inclusive os relatórios são parametrizáveis quanto ao vencimento utilizado no filtro e o vencimento apresentado.
08/11/2024
Renan
No meu caso não vou gerar remessa, apenas controlar contas a pagar e a receber.
Posso controlar o vencimento ao gerar o relatório, mas ainda acho que vou jogar o registo para o próximo dia útil.
Tenho parte do código pronto, usando dia fixo. Ainda preciso adaptar o intervalo de dias que o usuário pode informar, como por exemplo, parcelas a cada 15 dias.
A questão do feriado, ainda não consegui adaptar a função do Arthur.
15/11/2024
Emerson Nascimento
CREATE TABLE [dbo].[Feriado](
[Data] [date] NOT NULL,
[Descricao] [varchar](50) NOT NULL,
[Tipo] [char](1) NULL,
) ON [PRIMARY]
GO
após obter a data a partir da condição de pagamento você terá dois procedimentos obrigatórios:
- verificar se é fim de semana e
- verificar se é feriado.
deverá ser um loop até encontrar um dia útil.
imagine que pela condição de pagamento, a data de vencimento caiu no dia 30/12/2023. é um sábado. dia 01/01/2024 é feriado, e esta data deve ser incluída na tabela Feriado.
deixe a query que acessa a tabela Feriado sempre aberta - num DM, se possível.
então você precisa ter um loop que seja executado enquanto NÃO for um dia útil:
while not DiaUtil(vencimento) do
vencimento := vencimento + 1;
então, na função/método DiaUtil() você verifica se é fim de semana ou feriado:
function DiaUtil(dia: date): boolean;
begin
result := not( (DayOfWeek(dia) in [1,7]) or qryFeriado.Locate('Data', dia) );
end;
se você usar um DM, coloque a função DiaUtil nele ou em uma unit de funções (lib).
15/11/2024
Emerson Nascimento
CREATE TABLE [dbo].[Feriado]( [Data] [date] NOT NULL, [Descricao] [varchar](50) NOT NULL, [Tipo] [char](1) NULL ) ON [PRIMARY] GO
após obter a data a partir da condição de pagamento você terá dois procedimentos obrigatórios:
- verificar se é fim de semana e
- verificar se é feriado.
deverá ser um loop até encontrar um dia útil.
imagine que pela condição de pagamento, a data de vencimento caiu no dia 30/12/2023. é um sábado. dia 01/01/2024 é feriado, e esta data deve ser incluída na tabela Feriado.
deixe a query que acessa a tabela Feriado sempre aberta - num DM, se possível.
você precisa ter um loop que seja executado enquanto NÃO for um dia útil:
while not DiaUtil(vencimento) do vencimento := vencimento + 1;
na função/método DiaUtil() você verifica se é fim de semana ou feriado:
function DiaUtil(dia: date): boolean; begin result := not( (DayOfWeek(dia) in [1,7]) or qryFeriado.Locate('Data', dia) ); end;
se você usar um DM, coloque a função DiaUtil nele ou em uma unit de funções (lib).
utilizando no código que eu vi um pouco acima:
for i := 0 to Pred(NumParcelas) do begin DataParcela := AddMonths(DataOrigPrimParcela,i); while not DiaUtil(DataParcela) do DataParcela := DataParcela + 1; // Saiu do loop, então faça o que for necessário com a DataParcela // to-do end;
Clique aqui para fazer login e interagir na Comunidade :)