app/excnab/cnab240/services/build_details.ex

defmodule ExCnab.Cnab240.Services.BuildDetails do
  @moduledoc """
  Service to generate a details
  """

  alias ExCnab.Cnab240.Templates.{ChunkFooter, ChunkHeader, Details}

  alias ExCnab.Cnab240.Validator.Details, as: DetailsValidator

  @payment_mapper %{
    "03": %{
      code: :boleto_eletronico,
      descricao: "Boleto Eletrônico",
      "30": %{
        code: :liquidacao_titulos_banco,
        descricao: "Liquidação de Títulos do Próprio Banco"
      },
      "31": %{
        code: :liquidacao_titulos_outros_banco,
        descricao: "Pagamento de Títulos de Outros Bancos"
      }
    },
    "20": %{
      code: :pagamento_fornecedor,
      descricao: "Pagamento Fornecedor",
      "01": %{
        code: :credito_conta,
        descricao: "Crédito em Conta-Corrente"
      },
      "03": %{
        code: :doc,
        descricao: "DOC"
      },
      "10": %{
        code: :op,
        descricao: "Ordem de Pagamento - OP"
      },
      "41": %{
        code: :ted,
        descricao: "TED - Transferência entre Clientes"
      },
      "45": %{
        code: :pix,
        descricao: "PIX - Transferência"
      }
    },
    "22": %{
      code: :pagamento_de_contas,
      descricao: "Pagamento de Contas, Tributos e Impostos",
      "11": %{
        code: :pagamento_de_contas_codigo_barras,
        descricao: "Pagamento de Contas e Tributos com Código de Barras"
      },
      "16": %{
        code: :tributo_darf_normal,
        descricao: "Tributo DARF Normal"
      },
      "17": %{
        code: :tributo_gps,
        descricao: "Tributo GPS (Guia da Previdência Social)"
      },
      "18": %{
        code: :tributo_darf_simples,
        descricao: "Tributo DARF Simples"
      }
    },
    "30": %{
      code: :pagamento_salario,
      descricao: "Pagamento Salários/Folha de Pagamento",
      "01": %{
        code: :credito_conta,
        descricao: "Crédito em Conta-Corrente"
      }
    }
  }

  @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
      {:ok, builded_details}
    end
  end

  defp build_recursive([], acc, _, nil), do: {:ok, acc}

  defp build_recursive([hd | tail], acc, original_batches, nil) do
    with index <- Enum.find_index(original_batches, &(&1 == hd)) + 1,
         detail_key_id <- :"chunk_register_#{index}",
         %{header: header, detail: details, footer: footer} <- hd[detail_key_id],
         {:ok, builded_header} <- ChunkHeader.generate(header),
         {:ok, builded_details} <- Details.generate(details),
         {:ok, builded_footer} <- ChunkFooter.generate(footer, builded_details),
         amount <- get_chunk_infos(builded_header, builded_footer) do
      details = [
        %{
          header_lote: builded_header,
          lotes: builded_details,
          trailer_lote: builded_footer,
          valor: amount
        }
      ]

      build_recursive(tail, acc ++ details, original_batches, nil)
    end
  end

  defp get_chunk_infos(header, %{total: %{valor: amount}}) do
    %{service_type: service_type} = get_payment_method(header)

    %{tipo: service_type, quantidade: amount}
  end

  defp get_payment_method(%{servico: payment_details}) do
    payment_input = @payment_mapper[:"#{payment_details.tipo_servico}"]

    service_type = payment_input[:"#{payment_details.forma_lancamento}"]

    %{payment_input: payment_input.code, service_type: service_type.code}
  end
end