Skip to content

Commit

Permalink
chore: add tratative to warn line that has an error
Browse files Browse the repository at this point in the history
  • Loading branch information
eulixir committed May 29, 2023
1 parent 997d97f commit 21908c3
Show file tree
Hide file tree
Showing 22 changed files with 146 additions and 77 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.

## Version History

- 1.2.5 (2023-29-05)
- 1.2.5 (2023-18-05)
- 1.2.4 (2023-12-05)
- 1.2.3 (2023-10-05)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In `mix.exs`, add the ExMachina dependency:
```elixir
def deps do
[
{:ex_cnab, "~> 1.2.5"},
{:ex_cnab, "~> 1.3.0"},
]
end
```
Expand Down
2 changes: 1 addition & 1 deletion app/excnab/cnab240/services/build_details.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ defmodule ExCnab.Cnab240.Services.BuildDetails do
}
}

@spec run(Map.t(), Map.t()) :: {:ok, Map.t()}
@spec run(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def run(%{chunks: batches}, _attrs) do
with {:ok, builded_details} <- build_recursive(batches, [], batches, nil),
{:ok, _} <- DetailsValidator.call(builded_details, batches) do
Expand Down
34 changes: 29 additions & 5 deletions app/excnab/cnab240/services/decode.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,57 @@ defmodule ExCnab.Cnab240.Services.Decode do

@spec run(String.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
def run(file, attrs \\ %{}) do
with {:ok, map} <- read_file(file),
list = read_file(file)

with {:ok, map} <- classify_by_type(list),
{:ok, file_header} <- FileHeader.generate(map.file_header, attrs),
{:ok, details} <- BuildDetails.run(map.chunks, attrs),
{:ok, footer} <- FileFooter.generate(map.file_footer, attrs),
{:ok, filename_info} <- GetFileInfo.run(file, file_header, attrs) do
build_response(file_header, details, footer, filename_info, :ok)
else
{:error, error, line_error} ->
line =
list
|> Enum.find_index(&(&1 == line_error))
|> Kernel.+(1)

{:error, error, "Falha na linha #{line}"}

{:error, error} ->
{:error, error}
end
end

@spec run!(String.t(), Map.t()) :: Map.t() | {:error, String.t()}
def run!(file, attrs) do
with {:ok, map} <- read_file(file),
list = read_file(file)

with {:ok, map} <- classify_by_type(list),
{:ok, file_header} <- FileHeader.generate(map.file_header, attrs),
{:ok, details} <- BuildDetails.run(map.chunks, attrs),
{:ok, footer} <- FileFooter.generate(map.file_footer, attrs),
{:ok, filename_info} <- GetFileInfo.run(file, file_header, attrs) do
build_response(file_header, details, footer, filename_info, :no)
else
{:error, error, line_error} ->
line =
list
|> Enum.find_index(&(&1 == line_error))
|> Kernel.+(1)

{:error, error, "Falha na linha #{line}"}

{:error, error} ->
{:error, error}
end
end

defp read_file(file) do
with {:ok, content} <- File.read(file),
{:ok, %{size: size}} <- File.stat(file),
true <- size <= 524_288_000 do
content
|> String.split("\r\n")
|> classify_by_type()
String.split(content, "\r\n")
else
false ->
{:error, "File size is bigger than 500MB"}
Expand Down
2 changes: 1 addition & 1 deletion app/excnab/cnab240/templates/details.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule ExCnab.Cnab240.Templates.Details do
raw_details
|> build_recursive([])
|> case do
{:error, error} -> {:error, error}
{:error, error, raw_content} -> {:error, error, raw_content}
details -> ChunkValidator.call(details, raw_details)
end
end
Expand Down
3 changes: 2 additions & 1 deletion app/excnab/cnab240/templates/file_footer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ defmodule ExCnab.Cnab240.Templates.FileFooter do

alias ExCnab.Cnab240.Validator.FileFooter, as: FileFooterValidator

@spec generate(String.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec generate(String.t(), Map.t()) ::
{:ok, Map.t()} | {:error, String.t(), String.t()}
def generate(raw_string, _attrs) do
info = info_fields(raw_string)
total = total_fields(raw_string)
Expand Down
2 changes: 1 addition & 1 deletion app/excnab/cnab240/templates/file_header.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ defmodule ExCnab.Cnab240.Templates.FileHeader do

alias ExCnab.Cnab240.Validator.FileHeader, as: FileHeaderValidator

@spec generate(String.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec generate(String.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def generate(raw_string, _attrs) do
control_fields = control_fields(raw_string)
company_fields = company_fields(raw_string)
Expand Down
7 changes: 5 additions & 2 deletions app/validators/details.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ defmodule ExCnab.Cnab240.Validator.Details do
An implementation of chain of responsibility to validate the detailsr.
"""

@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def call(builded_batches, batches) do
with :ok <- validate_length(batches) do
{:ok, builded_batches}
else
{:error, reason} ->
{:error, reason, batches}
end
end

Expand All @@ -16,7 +19,7 @@ defmodule ExCnab.Cnab240.Validator.Details do

case batches <= @spec_length do
true -> :ok
false -> {:error, "Invalid details length: #{batches}, expected #{@spec_length}}"}
false -> {:error, "Tamanho dos detalhes inválido: #{batches}, esperado: #{@spec_length}}"}
end
end
end
7 changes: 5 additions & 2 deletions app/validators/details/chunk_footer.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ defmodule ExCnab.Cnab240.Validator.Details.ChunkFooter do
with :ok <- validate_length(raw_footer),
:ok <- validate_record_type(builded_footer.controle.registro) do
{:ok, builded_footer}
else
{:error, reason} ->
{:error, reason, raw_footer}
end
end

Expand All @@ -18,7 +21,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ChunkFooter do
:ok

number ->
{:error, "Invalid file footer length: #{number}, and should be #{@cnab_size}"}
{:error, "Tamanho inválido para o footer: #{number}, deveria ser #{@cnab_size}"}
end
end

Expand All @@ -29,7 +32,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ChunkFooter do
:ok

false ->
{:error, "Invalid record type: #{record_type}, and should be #{@record_type}}"}
{:error, "Tipo de registro incorreto: #{record_type}, deveria ser #{@record_type}}"}
end
end
end
16 changes: 11 additions & 5 deletions app/validators/details/chunk_header.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,42 @@ defmodule ExCnab.Cnab240.Validator.Details.ChunkHeader do
An implementation of chain of responsibility to validate the chunk header.
"""

@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def call(builded_header, raw_header) do
with :ok <- validate_length(raw_header),
:ok <- chunk_layout_version(builded_header.servico.layout_lote),
:ok <- validate_record_type(builded_header.controle.registro) do
{:ok, builded_header}
else
{:error, reason} ->
{:error, reason, raw_header}
end
end

@spec_length 240
defp validate_length(raw_header) do
case String.length(raw_header) do
@spec_length -> :ok
number -> {:error, "Invalid file header length: #{number}, expected #{@spec_length}}"}
@spec_length ->
:ok

number ->
{:error, "Tamanho do header do lote inválido: #{number}, esperado: #{@spec_length}}"}
end
end

@layout_chunk_version "042"
defp chunk_layout_version(layout) do
case layout === @layout_chunk_version do
true -> :ok
_ -> {:error, "Invalid layout version: #{layout}, expected #{@layout_chunk_version}"}
_ -> {:error, "Versão do layout inválida: #{layout}, esperado: #{@layout_chunk_version}"}
end
end

@record_type "1"
defp validate_record_type(record_type) do
case record_type == @record_type do
true -> :ok
false -> {:error, "Invalid record type: #{record_type}, expected #{@record_type}"}
false -> {:error, "Tipo de registro inválido: #{record_type}, esperado: #{@record_type}"}
end
end
end
21 changes: 11 additions & 10 deletions app/validators/details/chunks.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,38 @@ defmodule ExCnab.Cnab240.Validator.Details.Chunk do
An implementation of chain of responsibility to validate the chunks
"""

@spec call(List.t(), List.t()) :: {:ok, Map.t()} | {:error, String.t()}
def call(details, raw_details) do
with :ok <- validate_length(raw_details),
:ok <- validate_details_length(details, raw_details) do
@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def call(details, raw_detail) do
with :ok <- validate_length(raw_detail),
:ok <- validate_details_length(details, raw_detail) do
{:ok, details}
end
end

@spec_length 10_000
defp validate_length(raw_details) do
length = length(raw_details)
defp validate_length(raw_detail) do
length = length(raw_detail)

case length < @spec_length do
true ->
:ok

false ->
{:error, "Invalid file header length: #{length}, the max size is #{@spec_length}}"}
{:error,
"Tamanho total do lote inválido: #{length}, não pode ser maior que #{@spec_length}}"}
end
end

defp validate_details_length(details, raw_details) do
raw_length = length(raw_details)
defp validate_details_length(details, raw_detail) do
raw_length = length(raw_detail)
length = length(details)

case length == raw_length do
true ->
:ok

false ->
{:error, "Invalid details length: #{length}, expected #{raw_length},
{:error, "Tamanho dos detalhes inválido: #{length}, esperado: #{raw_length},
if you have this error, please contact the maintainers and open an issue"}
end
end
Expand Down
13 changes: 8 additions & 5 deletions app/validators/details/model_a.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelA do
An implementation of chain of responsibility to validate the model A.
"""

@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def call(builded_detail, raw_detail) do
with :ok <- validate_length(raw_detail),
:ok <- validate_record_type(builded_detail.controle.registro),
:ok <- validate_model_type(builded_detail.servico.segmento),
:ok <- validate_currency_type(builded_detail.credito.moeda.tipo) do
{:ok, builded_detail}
else
{:error, reason} ->
{:error, reason, raw_detail}
end
end

Expand All @@ -20,7 +23,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelA do
:ok

number ->
{:error, "Invalid file detail length: #{number}, and should be #{@cnab_size}"}
{:error, "Tamanho do segmento inválido: #{number}, deveria ser: #{@cnab_size}"}
end
end

Expand All @@ -31,7 +34,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelA do
:ok

false ->
{:error, "Invalid record type: #{record_type}, and should be #{@record_type}}"}
{:error, "Tipo de registro incorreto: #{record_type}, deveria ser #{@record_type}}"}
end
end

Expand All @@ -42,7 +45,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelA do
:ok

false ->
{:error, "Invalid record type: #{model_type}, and should be #{@model_type}}"}
{:error, "Tipo de segmento incorreto: #{model_type}, esperado: #{@model_type}}"}
end
end

Expand All @@ -53,7 +56,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelA do
:ok

false ->
{:error, "Invalid currency type: #{currency_type}, and should be #{@currency_type}}"}
{:error, "Tipo monetário inválido: #{currency_type}, o esperado é: #{@currency_type}}"}
end
end
end
11 changes: 7 additions & 4 deletions app/validators/details/model_b.validator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelB do
An implementation of chain of responsibility to validate the model B.
"""

@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t()}
@spec call(Map.t(), Map.t()) :: {:ok, Map.t()} | {:error, String.t(), String.t()}
def call(builded_detail, raw_detail) do
with :ok <- validate_length(raw_detail),
:ok <- validate_record_type(builded_detail.controle.registro),
:ok <- validate_model_type(builded_detail.servico.segmento) do
{:ok, builded_detail}
else
{:error, reason} ->
{:error, reason, raw_detail}
end
end

Expand All @@ -19,7 +22,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelB do
:ok

number ->
{:error, "Invalid file detail length: #{number}, and should be #{@cnab_size}"}
{:error, "Tamanho do segmento inválido: #{number}, deveria ser: #{@cnab_size}"}
end
end

Expand All @@ -30,7 +33,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelB do
:ok

false ->
{:error, "Invalid record type: #{record_type}, and should be #{@record_type}}"}
{:error, "Tipo de registro incorreto: #{record_type}, deveria ser #{@record_type}}"}
end
end

Expand All @@ -41,7 +44,7 @@ defmodule ExCnab.Cnab240.Validator.Details.ModelB do
:ok

false ->
{:error, "Invalid record type: #{model_type}, and should be #{@model_type}}"}
{:error, "Tipo de segmento incorreto: #{model_type}, esperado: #{@model_type}}"}
end
end
end

0 comments on commit 21908c3

Please sign in to comment.