Fala ai Radizeiros e Radizeiras, tudo bem com vocês?

A cada postagem aqui no nosso blog estamos evoluindo a implementação das boas práticas para geração de arquivos fiscais.

Como já tenho falado que aplicar as boas práticas ajuda e reduzir a sua dor de cabeça a cada alteração do governo ou novas implementações dentro das suas rotinas fiscais, e para que você venha ter maior flexibilidade e legibilidade em seus códigos é de extrema importância aplicar essas técnicas em seus software.

Quem me conhece sabe que bato sempre nessa tecla, porque não quero que você sofra com as alterações que tem que fazer, que ao invés de ser uma dor mexer no seu código seja um prazer a sua programação.

Por este motivo estamos seguindo essa série onde te mostro como é simples e menos doloroso a implementação das rotinas fiscais quando se aplica as boas prática usando o ACBr, mas com tudo que você tem aprendido poderá alterar por outro componente tranquilamente.

Neste post estarei mostrando como aplicar o padrão de projeto Command nas rotinas para NF-e, e você verá como mantendo as boas práticas usando os Padrões de Projetos você aumenta o ganho nos seus códigos, lembrando que todos esses conteúdos aplicados aqui na nossa série é conteúdo exclusivo de um dos meus treinamentos, o de Boas Práticas para Geração de Arquivos Fiscais com ACBr.

Então vamos lá?

Dando continuidade com o post anterior, nós possuímos essa seguinte estrutura em nosso projeto.

Observe que temos o Componente e a estrutura Mãe, vamos dizer assim, da nota fiscal.

Agora em nossa Unit de interfaces, iremos implementar nosso Padrão de Projeto, que é chamado o padrão Command.

Mas o que esse padrão faz e no que ele irá nos auxiliar?

O padrão Command pode ser utilizado todas as vezes que você estiver rodando rotinas que vão precisar, vamos dizer assim, para uma rotina completa, um exemplo da própria nota fiscal para isso, para você gerar uma nota fiscal, você não tem apenas uma rotina, você tem várias coisas que acontecem antes de você enviar a nota, você tem vários processos para acontecer ali dentro.

Toda as vezes que você estiver uma cadeia de processos para executar uma ação específica, enviar a nota é uma delas, processar um relatório financeiro analítico ou sintético, onde você precisa buscar várias informações de vários lugares para gerar esse relatório, então também você irá fazer várias ações para gerar esse relatório, você irá sintetizar isso tudo num padrão Command, porque várias coisas acontecem ali dentro para que seja executado um processo específico.

O padrão Command, vamos dizer assim, é usado para encadear comandos diversos em uma única função, pegamos vários comandos e transformamos em um único comando, só que sem colocar tudo num bloco só, como por exemplo, colocar  tudo dentro de um método, e quando tivermos que reutilizar isso, como iremos fazer? Fica muito complicado.

O padrão Commando está ai para isso, e ele por natureza tem apenas duas interfaces, ele é um padrão relativamente simples.

...
    iCommand = interface
        ['{CC1B132C-F5B6-4499-8B8F-385A56DF4890}']
        function Execute : iCommand;
    end;

    iInvoker = interface
        ['{78237CF1-6953-404A-8255-10F42176E392}']
        function Add(Value : iCommand) : iInvoker;
        function Execute : iInvoker;
     end;
...

Observe no código acima que temos duas interfaces, onde um é o comando e a outra é que irá invocar os comandos, o padrão Command é somente isso, relativamente simples.

Mas por que temos duas interfaces?

Porque graças a essas interfaces, por exemplo, a interface de comando, todo comando precisa ser executado, então para que o nosso iInvoker, o cara que irá invocar os comandos, saiba o que invocar, ele irá precisar ter essa interface iCommand padronizada , por exemplo, eu sei que todo o comando que vai ter no meu software vai ter o método execute, que retorna o próprio iCommand, então tudo que for uma comando, por exemplo, enviar e-mail, ele irá implementar a função iCommando e irá ter o método execute, ele que irá fazer o procedimento de enviar o e-mail, quando meu Invoker for chamando a cadeia de comandos que ele está enviando chegar no enviar e-mail, ele irá chamar o execute de enviar e-mail e irá enviar o e-mail.

Observe que a nossa interface iInvoker tem o método Add que irá receber um comando, só por este método você já percebe que o meu invoker tem uma lista de comandos, eu vou adicionar vários comandos nele e depois mando executar esse comandos lá dentro, e o método execute.

Vamos criar a classe que implementa a interface iInvoker.

type
TModelFiscalNFeInvoker = class (TInterfacedObject, iInvoker)
private
    FLista : TList<iCommand>;
public
    constructor Create;
    destructor Destroy; override;
    class function New : iInvoker;
    function Add(Value : iCommand) : iInvoker;
    function Execute : iInvoker;
end;

implementation

{ TModelFiscalNFeInvoker }

function TModelFiscalNFeInvoker.Add(Value: iCommand): iInvoker;
begin
    Result := Self;
    FLista.Add(Value);
end;

constructor TModelFiscalNFeInvoker.Create;
begin
    FLista := TList<iCommand>.Create;
end;

destructor TModelFiscalNFeInvoker.Destroy;
begin
    FLista.DisposeOf;
    inherited;
end;

function TModelFiscalNFeInvoker.Execute: iInvoker;
var
    FCommand : iCommand;
begin
    Result := Self;
    for FCommand in FLista do
        FCommand.Execute;
end;

class function TModelFiscalNFeInvoker.New: iInvoker;
begin
    Result := Self.Create
end;

Isso que estamos fazendo aqui você pode aplicar em inúmeras coisas dentro do seu software.

Essa classe que acabamos de criar é a responsável por invocar os comandos para nós.

Observe nessa nossa classe que foi criado o objeto chamado FLista que é uma lista que implementa o iCommand, isso é porque estamos adicionando vários comandos para serem executados.

No método Execute de nossa classe eu percorro toda a lista, e a cada interação dessa lista ele irá jogar a interface para dentro da variável FCommand e chamo o Execute.

Então eu posso ter agora várias classes que implementam iCommand, cada uma com seu comando diferente e encadear as execuções delas, agora está pronto o meu Command.

Agora iremos criar nosso primeiro Command mais simples, a primeira coisa que a nota fiscal faz no ACBr é a configuração, que você pode ver no código abaixo do demo do ACBr.

...
ACBrNFe1.Configuracoes.Geral.ModeloDF := moNFe;
ACBrNFe1.Configuracoes.Geral.VersaoDF :=  TpcnVersaoDF(cbVersaoDF.ItemIndex);
GerarNFe(vAux);
...

A ideia aqui é que você possa entender essa utilização dos padrões de projetos, de como isso facilita, e de como nosso código fica mais suscetível a mudanças.

Viu o código do ACBr da aba geral?

 Iremos criar um comando para essa configuração geral.

type
    TModelFiscalNFeCommandGeral = class (TInterfacedObject, iCommand)
    private
        FParent : iModelFiscalNFe;
    public
        constructor Create(Parent : iModelFiscalNFe);
        destructor Destroy; override;
        class function New(Parent : iModelFiscalNFe) : iCommand;
        function Execute : iCommand;
    end;

implementation

uses
    pcnConversaoNFe;

{ TModelFiscalNFeCommandsGeral }

constructor TModelFiscalNFeCommandGeral.Create(Parent : iModelFiscalNFe);
begin
    FParent := Parent;
end;

destructor TModelFiscalNFeCommandGeral.Destroy;
begin
    inherited;
end;

function TModelFiscalNFeCommandGeral.Execute: iCommand;
begin
    Result := Self;
    FParent.Component._This.Configuracoes.Geral.ModeloDF := moNFe;
    FParent.Component._This.Configuracoes.Geral.VersaoDF :=  ve400;
end;

class function TModelFiscalNFeCommandGeral.New(Parent : iModelFiscalNFe) : iCommand;
begin
    Result := Self.Create(Parent);
end;

Observe que criamos uma classe que implementa a interface iCommand  e  precisou receber por injeção de dependência a interface classe mãe, mas você deve estar se perguntando, por que ele está usando injeção de dependência? Porque ele precisava conhecer os métodos do ACBr para poder fazer essa configuração, e como a classe mãe que possui o componente do ACBr foi passado por injeção de dependência a interface da classe mãe, fazendo assim, toda vez que alguém chamar essa nossa classe terá que passar uma instância da classe mãe.

Em nossa classe no método Execute passamos toda a configuração do ACBr para que possa ser executado, observe que possuímos a versão da NF-e, amanhã o governo muda a estrutura da nota fiscal, e para todo o meu software que emite nota fiscal, onde irei mudar é somente nessa classe, lembra que sempre falo que as funções tem que ser curtas e fazerem apenas o que elas tem que ser feitas, agora a nossa classe de configuração está aí curtinha e fazendo aquilo que ela tem que fazer.

Isso tudo facilita mais ainda quando for implementado as regras para implementar as regras fiscais.

Agora temos a comando e a classe Invoker pronta, agora como iremos fazer isso na classe mãe, a classe que gera a nota?

Dentro da classe mãe temos o método chamado Gerar, tudo tem que acontecer dentro desse método.

...
function TModelFiscalNFe.Gerar: iModelFiscalNFe;
begin
    Result := Self;

    TModelFiscalNFeInvoker.New
        .Add(TModelFiscalNFeCommandGeral.New(Self))
    .Execute;

    FComponente._This.NotasFiscais.GerarNFe;
end;
...

Observe que chamamos a classe Invoker, logo em seguida adicionamos os comando que irão ser executados, ao passarmos a nossa classe geral no método Add, estamos adicionando este comando na lista, e logo que ele está adicionado na lista mandamos executar, agora todos os comandos da nota fiscal que eu quiser executar vamos adicionando dentro dessa lista.

Viu como vai ficando simples a geração da NF-e usando as boas práticas, desta forma irá reduzir significativamente os erros em manutenções e ajustes com mudanças do governo.

Viu como vamos melhorando todo nosso código para implementação do ACBrNFe, esse é apenas o primeiro post da nossa série de Boas práticas para geração de arquivos fiscais com ACBr, este post foi extraído de um dos meus treinamentos que ensino todas as técnicas de boas práticas com clean code para geração de arquivos fiscais.

Com as técnicas aplicadas nesse treinamento, alem de aprender a aplicar na criação e emissão da NF-e, você pode também aplicar facilmente para o SPED e o SINTEGRA, ou seja, o que é problema para você hoje, depois desse treinamento você irá enxergar como oportunidade.

CLIQUE AQUI PARA SABER MAIS SOBRE O TREINAMENTO BOAS PRÁTICAS PARA GERAÇÃO DE ARQUIVOS DISCAIS COM ACBr