Files
Reem-Notas/spec/services/romaneios/plano_planilha_spec.rb

103 lines
4.2 KiB
Ruby

require 'rails_helper'
require 'caxlsx'
# A planilha do plano é o caminho B do romaneio — e é o que o cliente usa quando o
# plano do dia ainda não está publicado. Os casos aqui são os que o export REAL
# apresenta (medido em Imagens para implantação/SimpliRoute_Plan_ 2026-08-31.xlsx):
# coluna "Motorista" vazia, sem "Aparelho", e a NF numa coluna com typo do próprio
# SimpliRoute ("ID de referêncua").
RSpec.describe Romaneios::PlanoPlanilha do
def planilha(cabecalho, linhas)
pacote = Axlsx::Package.new
pacote.workbook.add_worksheet(name: 'Plan') do |aba|
aba.add_row(cabecalho)
linhas.each { |l| aba.add_row(l) }
end
arquivo = Tempfile.new(['plano', '.xlsx'])
arquivo.binmode
arquivo.write(pacote.to_stream.read)
arquivo.flush
arquivo
end
it 'lê o formato real do export (sem Motorista, sem Aparelho, NF com o typo)' do
arquivo = planilha(
['Motorista', 'Veículo', 'Índice de rota', 'Ordem de entrega', 'Título', 'Endereço',
'ID de referêncua', 'Anotações'],
[[nil, 'GADE_038', 1, 1, 'NF 90507 - Cicera Beserra dos Anjos',
'Rua Amapola, 206, Jardim Vista Linda, São Paulo, SP, CEP: 05159-100',
'90507', 'TEL: (11) 99262-0594']]
)
linha = described_class.new(arquivo).linhas.first
expect(linha[:veiculo]).to eq('GADE_038')
expect(linha[:nota_fiscal]).to eq('90507')
expect(linha[:nome]).to eq('CICERA BESERRA DOS ANJOS')
expect(linha[:endereco]).to eq('RUA AMAPOLA, 206, JARDIM VISTA LINDA, SÃO PAULO, SP, CEP: 05159-100')
expect(linha[:telefones]).to eq('(11) 99262-0594')
expect(linha[:motorista]).to eq('')
end
it 'aceita a grafia corrigida da coluna de referência' do
arquivo = planilha(['Veículo', 'Título', 'Endereço', 'ID de referência'],
[['GADE_001', 'NF 1 - Fulano', 'Rua A, 1', '1']])
expect(described_class.new(arquivo).linhas.first[:nota_fiscal]).to eq('1')
end
it 'aceita título fora do padrão "NF n - NOME" sem perder a parada' do
arquivo = planilha(['Veículo', 'Título', 'Endereço'],
[['GADE_001', 'PONTO DE APOIO', 'Rua A, 1']])
linha = described_class.new(arquivo).linhas.first
expect(linha[:nota_fiscal]).to eq('')
expect(linha[:nome]).to eq('PONTO DE APOIO')
end
it 'tira o sufixo ", Brazil" do endereço e junta vários telefones' do
arquivo = planilha(['Veículo', 'Título', 'Endereço', 'Anotações'],
[['GADE_001', 'NF 1 - Fulano', 'Rua A, 1, Bairro, Brazil',
'TEL: (11) 95440-5780 / (11) 99824-8099']])
linha = described_class.new(arquivo).linhas.first
expect(linha[:endereco]).to eq('RUA A, 1, BAIRRO')
expect(linha[:telefones]).to eq('(11) 95440-5780 / (11) 99824-8099')
end
it 'renumera a ordem de 1..N dentro de cada veículo, na ordem de entrega do plano' do
arquivo = planilha(['Veículo', 'Ordem de entrega', 'Título', 'Endereço'],
[['GADE_001', 3, 'NF 3 - C', 'Rua C'],
['GADE_002', 9, 'NF 9 - I', 'Rua I'],
['GADE_001', 1, 'NF 1 - A', 'Rua A']])
linhas = described_class.new(arquivo).linhas
primeiro = linhas.select { |l| l[:veiculo] == 'GADE_001' }
expect(primeiro.map { |l| [l[:ordem], l[:nota_fiscal]] }).to eq([[1, '1'], [2, '3']])
expect(linhas.find { |l| l[:veiculo] == 'GADE_002' }[:ordem]).to eq(1)
end
it 'pula linha sem veículo (rodapé do próprio export) sem levantar erro' do
arquivo = planilha(['Veículo', 'Título', 'Endereço'],
[['GADE_001', 'NF 1 - A', 'Rua A'], [nil, nil, nil]])
expect(described_class.new(arquivo).linhas.size).to eq(1)
end
it 'recusa arquivo que não é .xlsx com uma mensagem acionável' do
arquivo = Tempfile.new(['plano', '.xlsx'])
arquivo.write('isto não é um zip')
arquivo.flush
expect { described_class.new(arquivo) }
.to raise_error(described_class::Erro, /não é um \.xlsx/)
end
it 'recusa planilha sem a coluna Veículo — não dá para montar folha sem carro' do
arquivo = planilha(['Título', 'Endereço'], [['NF 1 - A', 'Rua A']])
expect { described_class.new(arquivo).linhas }
.to raise_error(described_class::Erro, /Veículo/)
end
end