Fala ai Radizeiros e Radizeiras, tudo bem com vocês?
Quantas vezes você precisou ajustar a geração do arquivo SPED do seu software?
A cada mudança do governo é mais um dia de trabalho intenso para realizar os ajustes devidos, e a cada ajuste um novo problema.
Conhecendo bem os padrões de projetos e a programação funcional, essas chamadas serão resolvidos em pouco tempo.
Problemas como esses acontecem em grande escala nas soft-house, saiba que você pode reduzir esses problemas e ainda mais seu tempo, poder focar em melhorar o seu software, e até mesmo ter mais tempo para você e sua família…
Hoje neste post irei mostrar como podemos gerar o arquivo de SPED usando o padrão de projeto Bridge.
Mas o que o Bridge?
Esse padrão é mais um daquele que você olha e diz:
Caramba por que eu nunca pensei nisso antes, isso resolve minha vida.
O padrão Bridge é um padrão estrutural, e ele diz que devemos ter uma classe de abstração, uma de implementação e uma concrete implementor.
Em inglês o Bridge é ponte, e é exatamente o que ele irá fazer, ele vai fazer uma ponte entre métodos dentro dos objetos.
Vamos ao que interessa.
Como sempre vamos criar uma Unit de interfaces.
E para o nosso padrão Bridge iremos precisar de duas interfaces.
type iExport<t> = interface; iSource<t> = interface ['{F2B074B1-F991-4783-BAA5-9304AF00C698}'] function Exportar(Value : iExport<t>) : iSource<t>; end; iExport<t> = interface ['{C193344E-62C5-4DDD-82DA-232B46EF0EB6}'] function GerarRegistros(Value : t) : iExport<t>; end;
A interface iSource<t> tem seu objeto genérico e é ele que irá prover os dados para nós, e o iExport<t> que irá gerar nossos arquivos.
Aqui estaremos simulando a geração do arquivo SPED usando o Bridge, ele nos ajuda a reutilizar códigos para geração de um arquivo de SPED.
Nós iremos ter um Source que irá gerar vendas, pois a nossa classe de vendas irá implementar o Source, porque é ele que está provendo os dados dessa venda para que possamos trabalhar, e ai nós iremos fazer uma ponte com os registros que precisamos gerar, nós queremos o padrão que irá gerar o registro C100 e o C190, os registros C100 e C190 implementam o iExport, são eles que irão exportar os dados, ele pega o resulta do iSource trata e exporta esses registros.
Em nosso exemplo iremos criar um record para simular as informações vindas do banco de dados.
type TVenda = record COO : Integer; Itens : Integer; Total : Currency; end; end;
Agora vamos criar as classes que implementam essas interfaces para criarmos essa ponte.
Type TModelVenda = class(TInterfacedObject, iSource<TVenda>) private FList : TList<TVenda>; procedure AddItens; public constructor Create; destructor Destroy; override; class function New : iSource<TVenda>; function Exportar(Value : iExport<TVenda>) : iSource<TVenda>; end; implementation uses System.SysUtils; { TModelVenda } procedure TModelVenda.AddItens; var Venda : TVenda; begin Venda.COO := 10; Venda.Itens := 2; Venda.Total := 20; FList.Add(Venda); Venda.COO := 20; Venda.Itens := 2; Venda.Total := 20; FList.Add(Venda); Venda.COO := 30; Venda.Itens := 3; Venda.Total := 30; FList.Add(Venda); Venda.COO := 40; Venda.Itens := 4; Venda.Total := 40; FList.Add(Venda); end; constructor TModelVenda.Create; begin FList := TList<TVenda>.Create; AddItens; end; destructor TModelVenda.Destroy; begin FreeAndNil(FList); inherited; end; function TModelVenda.Exportar(Value: iExport<TVenda>): iSource<TVenda>; var I: Integer; begin Result := Self; for I := 0 to Pred(FList.Count) do Value.GerarRegistros(FList.Items[I]); end; class function TModelVenda.New: iSource<TVenda>; begin Result := Self.Create; end;
Essa nossa classe implementa a interface iSource , como eu já tinha dito, é ela que irá prover os dados.
E você pode observar que o nosso iSource é do tipo genérico TVenda.
No método Exportar estamos percorrendo a lista que criamos, cada vez que é passado o item em lista é chamado o método GerarRegistro que é pedido como passagem de parâmetro o TVenda que é nossa lista, feito isso ele já irá gerar o registro.
Mas que registro você está gerando?
Não importa, é ai que fica legal nossa implementação, a minha venda simplesmente exporta para geração de algum registro, ele exporta para geração de qualquer coisa, seja para SPED, SINTEGRA, eSocial, qualquer coisa que eu tenha que gerar, simplesmente eu estou exportando, e tenho um método que faz a exportação das minhas vendas.
O que você irá precisar para gerar o SPED, é simplesmente criar uma classe para especializar um registro do SPED usando esse exportar da minha venda.
Simplesmente crio uma classe que implementa o iExport, desta forma ela já será capais de consumir os registros da venda e fazer essa formatação, e é o que iremos fazer agora, nós iremos criar uma classe que implementa essa interface para que possamos gerar o registro C100 do SPED.
Type TModelSPEDC100 = class(TInterfacedObject, iExport<TVenda>) private FArquivo : TStringList; public constructor Create; destructor Destroy; override; class function New : iExport<TVenda>; function GerarRegistros(Value : TVenda) : iExport<TVenda>; end; implementation uses System.SysUtils; const ARQUIVO = 'SPED.TXT'; { TModelSPEDC100 } constructor TModelSPEDC100.Create; begin FArquivo := TStringList.Create; if FileExists(ARQUIVO) then FArquivo.LoadFromFile(ARQUIVO); FArquivo.Add('|C100|0|1|'); end; destructor TModelSPEDC100.Destroy; begin FArquivo.Free; inherited; end; function TModelSPEDC100.GerarRegistros(Value: TVenda): iExport<TVenda>; begin Result := Self; FArquivo.Add(Format('|C100|%d|%d|%f|', [Value.COO, Value.Itens, Value.Total])); FArquivo.SaveToFile(ARQUIVO); end; class function TModelSPEDC100.New: iExport<TVenda>; begin Result := Self.Create; end;
Como podemos observar que a interface implementa a classe TVenda, desta forma nossa classe já está habilitada a exporta os registros da venda.
Dentro do método GerarRegistro simplesmente nós chamamos o objeto FArquivo e adicionamos os valores vindos da venda, a cada registro ele monta uma linha e salva no arquivo.
Nossa classe para o registro C100 já está pronta, e para os demais registro simplesmente basta pegar uma copia dessa classe e fazer os ajuste devidos.
Type TModelSPEDC190 = class(TInterfacedObject, iExport<TVenda>) private FArquivo : TStringList; public constructor Create; destructor Destroy; override; class function New : iExport<TVenda>; function GerarRegistros(Value : TVenda) : iExport<TVenda>; end; implementation uses System.SysUtils; const ARQUIVO = 'SPED.TXT'; { TModelSPEDC190 } constructor TModelSPEDC190.Create; begin FArquivo := TStringList.Create; if FileExists(ARQUIVO) then FArquivo.LoadFromFile(ARQUIVO); FArquivo.Add('|C190|0|1|'); end; destructor TModelSPEDC190.Destroy; begin FArquivo.Free; inherited; end; function TModelSPEDC190.GerarRegistros(Value: TVenda): iExport<TVenda>; begin Result := Self; FArquivo.Add(Format('|C190|0|0|0|0|%d|%d|%f|0|0|0|', [Value.COO, Value.Itens, Value.Total])); FArquivo.SaveToFile(ARQUIVO); end; class function TModelSPEDC190.New: iExport<TVenda>; begin Result := Self.Create; end;
Viu como é basicamente a mesma coisa?
Simplesmente nós pegamos a classe do C100 e ajustamos para as particularidades para o registro C190.
Em nossa camada de visão a implementação é mais simples ainda.
TModelVenda.New .Exportar( TModelSPEDC100.New ) .Exportar( TModelSPEDC190.New );
Desta forma nosso arquivo já será gerado com os registros que implementamos.
|C100|0|1| |C100|10|2|20,00| |C100|20|2|20,00| |C100|30|3|30,00| |C100|40|4|40,00| |C190|0|1| |C190|0|0|0|0|10|2|20,00|0|0|0| |C190|0|0|0|0|20|2|20,00|0|0|0| |C190|0|0|0|0|30|3|30,00|0|0|0| |C190|0|0|0|0|40|4|40,00|0|0|0| |C100|0|1| |C100|10|2|20,00| |C100|20|2|20,00| |C100|30|3|30,00| |C100|40|4|40,00| |C190|0|1| |C190|0|0|0|0|10|2|20,00|0|0|0| |C190|0|0|0|0|20|2|20,00|0|0|0| |C190|0|0|0|0|30|3|30,00|0|0|0| |C190|0|0|0|0|40|4|40,00|0|0|0|
Viu como é muito simples gerar o arquivo usando o padrão Bridge, esse dentre outros padrões você pode aprender em um dos meus treinamentos Certificação especialista em Delphi.
O QUE VOCÊ IRÁ APRENDER?
A Certificação Especialista em Padrões de Projeto dará a você a oportunidade de melhorar seu software, otimizar o seu tempo e te dar a possibilidade de atender melhor os seus clientes.
Conhecer a fundo esse paradigma e utilizar todos os seus benefícios irá facilitar muito a sua vida quando houver necessidade por parte de um cliente de um update rápido ou resolver um problema.