Python/Django REST Framework positional flat file reader API
python-edi-parser
é um projeto feito em Python, utilizando framework Django, que expõe uma API REST para verificação de um arquivo EDI (arquivo texto posicional).
A API funciona recebendo um parâmetro de tipo de layout (explicado abaixo) e também um arquivo texto de upload.
O sistema de verificação do arquivo EDI é baseado em um mapeamento de layout que pode ser configurado para outros layouts de arquivos posicionais.
A aplicação foi desenvolvida utilizando o design pattern Abstract Factory para implementar as funções de custom_validation
e também de custom_actions
.
https://developercielo.github.io/tutorial/edi
- Campo 26 do registro de detalhe é do tipo numérico, mas nos comentários diz para preencher com brancos
No arquivo settings.py
temos uma configuração especial que é uma constante chamada EDI_LAYOUTS
, onde temos os layouts implementados para validar arquivos posicionais.
A vantagem dessa abordagem é que podemos adicionar novas configurações no array de layout e aumentar o leque de arquivos que podem ser verificados pelo programa, sem precisar alterá-lo.
Obs: Exceto novas custom_validations
e custom_actions
que precisam ser implementadas a partir das suas classes abstratas.
Instalar o virtual environment:
> pip install virtualenv
Crie um virtual environment:
> virtualenv env
Ative o environment Windows
:
> .\env\Scripts\activate
Ative o environment Linux/MAC
:
> source ./env/bin/activate
Instale os requisitos básicos:
(env) > pip install -r requirements.txt
Rode os comandos abaixo para finalizar a configuração do Django:
(env) > python ./manage.py makemigrations
(env) > python ./manage.py migrate
(env) > python ./manage.py collectstatic
Finalmente rode o servidor do Django:
(env) > python manage.py runserver
Na raiz do projeto existe um arquivo chamado test_file.txt
que pode ser usado para testar o programa.
No arquivo settings.py
existe uma constante chamada EDI_LAYOUTS
que possui os layouts utilizados pela aplicação.
Os parâmetros esperados pela API são:
- id: Que é o id do layout (por enquanto temos apenas o id 1, então basta passar 1 nesse parâmetro)
- file: Arquivo texto que será feito upload e validado pela aplicação.
O retorno da API é um JSON no seguinte formato:
{
"response": "OK/FAIL",
"valid": false/true,
"messages": [
"Array de mensagens de log",
"..."
]
}
Onde:
response
: retornaOK
ouFAIL
dependendo se o arquivo processou corretamente ou não.valid
:true
se o arquivo é válido efalse
se não é.messages
: um array de mensagens para ajudar a identificar onde o arquivo deu problema, trazendo todas as mensagens de log geradas durante cada etapa da validação.
Observações:
- O array de mensagens é bastante verboso quando a constante
DEBUG
do arquivosettings.py
está ligada, ou seja configurada com o valorTrue
, quando está com valorFalse
, apenas retorna mensagens de erro.
curl -X POST \
http://localhost:8000/api/parser \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F id=1 \
-F file=@/C:/Users/RenatoAloi/python-edi-parser/test_file.txt
Obs: substitua o caminho do arquivo test_file.txt
pelo correspondente no seu computador.
Outra forma de usar a API é chamando pelo Postman. Utilize a URL abaixo e importe no Postman, clicando no botão Import
e selecionando a aba Import From Link
:
https://www.getpostman.com/collections/86aa206e3a7b181d746a
Depois clique na aba Body
e selecione o arquivo clicando no botão Select Files
do parâmetro file
.
Para enviar a requisição clique no botão Send
.
O programa já tem configurado com o layout do Arquivo para Remessa e/ou Retorno de Vendas
, do portal da Cielo, conforme esse link.
Mas pode ser configurado para aceitar outros layouts de arquivos, conforme o exemplo abaixo:
EDI_LAYOUTS = [
{
'id': '99',
'type': 'Titulo do tipo de layout',
'layout': [
{
'registro': 'header',
'regex': r'^00\d{8}\d{7}$',
'positions': ( (1, 2), (3, 8), (11, 7), ),
'formato': ( 'N', 'N', 'N', ),
'obrigatorio': ( False, True, True, ),
'custom_validation': ( None, 'Date', None, ),
'custom_action': ( None, None, 'SaveField', )
},
{
'registro': 'detalhe',
'regex': r'^01\d{7}\d{19}.{6}$',
'positions': ( (1, 2), (3, 7), (10, 19), (29, 6), ),
'formato': ( 'N','N','N','X', ),
'obrigatorio': ( False, True, True, False, ),
'custom_validation': ( None, 'Unique', None, None, ),
'custom_action': ( None, None, None, None, )
},
{
'registro': 'trailler',
'regex': r'^99\d{7}\d{15}$',
'positions': ( (1, 2), (3, 7), (10, 15), ),
'formato': ( 'N', 'N', 'N', ),
'obrigatorio': ( False, True, True, ),
'custom_validation': ( None, None, None, ),
'custom_action': ( None, None, None, )
}
]
}
]
Onde:
- id: Um identificador único do layout, que pode ser qualquer número, desde que seja único.
- type: Um identificador de texto, que pode ser qualquer texto.
- layout: Um array de configurações, conforme segue:
registro
: Tipo do registro, pode serheader
,detalhe
etrailler
.regex
: Expressão regular que valida o layout do registro. Essa é a primeira validação que é feita no arquivo.positions
: Tuplas de posições, que determinam o intervalo fechado de cada campo posicional do registro.formato
: 'N' para numérico e 'X' para texto em geral.obrigatorio
: Determina se o campo é opcional (False) ou obrigatório (True). Essa é a segunda validação que é feita no arquivo.custom_validation
: Custom validations são funções específicas de validação avançada. Precisam ser configuradas nocustom_rules
do arquivohelpers.py
, e implementadas no arquivofactory\validation.py
. Essa é a terceira e última validação que é feita no arquivo.custom_action
: Custom actions são funções específicas de ações avançadas, como por exemplo, somar o valor de um campo na tabela. Precisam ser configuradas nocustom_actions
do arquivohelpers.py
, e implementadas no arquivofactory\action.py
.
- O código começa no arquivo
views.py
onde tem aAPIView
que executa o script macro principal. Esse script recebe o parametroid
e carrega o layout correspondente. Também recebe o parâmetrofile
e efetua o upload deste. Depois o script começa as validações, primeiro chama a função que faz o match do regex. Na sequência valida os campos obrigatórios, e finalmente executa ascustom_actions
e ascustom_validations
. - A função que salva o upload
save_upload
está no arquivofs.py
, junto com a função que efetua a leitura do arquivo textoread_file
. A função que lê o arquivo texto utiliza o retorno de cada linha através deyield
que evita ter que carregar o arquivo todo na memória, caso ele tenha milhares de linhas, ou seja, para poder trabalhar com arquivos grandes. - Já as funções que efetuam as validações, como a
regex_match
,mandatory_check
,custom_actions
, ecustom_rules
estão no arquivohelpers.py
. - E as funções do arquivo
helpers.py
chamam as funções custom validators do arquivofactory\validation.py
e as funções custom actions do arquivofactory\action.py
, que implementam o design pattern Abstract Factory. - Por fim temos o ORM implementado no arquivo
models.py
e os testes unitários no arquivotests.py
.
Para rodar os testes unitários, execute o comando abaixo:
(env) > python .\manage.py test
Para verificar a cobertura de testes do código, execute a linha abaixo:
(env) > coverage run --source='flatparser' .\manage.py test flatparser
Para exibir o relatório de cobertura de testes, execute o comando:
(env) > coverage report
ou:
(env) > coverage html