68 lines
2.8 KiB
Ruby
68 lines
2.8 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe Analytics::NotasForaOperacao do
|
|
subject(:fora) { described_class.new(inicio: Date.new(2026, 8, 1), fim: Date.new(2026, 8, 31)) }
|
|
|
|
# Visitas já filtradas pelo SQL (NFs que não estão em nenhuma gade_entregas_*).
|
|
let(:visitas) do
|
|
[
|
|
row(nf: 100, status: 'failed', driver: 'Carlos', checkout: '2026-08-10 09:00:00', title: 'NF 100 - FULANO (Avulsa)'),
|
|
row(nf: 100, status: 'completed', driver: 'Carlos', checkout: '2026-08-12 09:00:00', title: 'NF 100 - FULANO (Avulsa)'),
|
|
row(nf: 101, status: 'completed', driver: 'Pedro', checkout: '2026-08-11 09:00:00', title: 'INCLUSÃO'),
|
|
row(nf: 102, status: 'failed', driver: 'Pedro', checkout: '2026-08-13 09:00:00', title: 'INCLUSÃO', obs: 'ÓBITO'),
|
|
row(nf: 103, status: 'pending', driver: 'Marcos', planned: '2026-08-20', title: nil)
|
|
]
|
|
end
|
|
|
|
before { allow(fora).to receive(:visitas).and_return(visitas) }
|
|
|
|
it 'conta uma linha por NF, pelo status da última visita' do
|
|
expect(fora.total).to eq(4)
|
|
expect(fora.entregues).to eq(2)
|
|
expect(fora.nao_entregues).to eq(1)
|
|
expect(fora.pendentes).to eq(1)
|
|
end
|
|
|
|
it 'agrupa por plano de origem (Avulsa x INCLUSÃO)' do
|
|
expect(fora.por_plano).to contain_exactly(
|
|
{ nome: 'INCLUSÃO', total: 2 },
|
|
{ nome: 'NF 100 - FULANO (Avulsa)', total: 1 },
|
|
{ nome: 'SEM PLANO IDENTIFICADO', total: 1 }
|
|
)
|
|
end
|
|
|
|
it 'ordena a listagem da visita mais recente para a mais antiga' do
|
|
expect(fora.listagem.map { |r| r['reference_id'] }).to eq([102, 100, 101, 103])
|
|
end
|
|
|
|
# NOT IN com NULL na subquery devolve zero linhas — por isso cada SELECT da
|
|
# união precisa filtrar nota_fiscal IS NOT NULL.
|
|
it 'protege o NOT IN contra nota_fiscal NULL' do
|
|
allow(Operacao).to receive(:nomes_validos).and_return(%w[gade_entregas_teste])
|
|
sql = nil
|
|
allow(ActiveRecord::Base.connection).to receive(:select_all) { |consulta| sql = consulta; [] }
|
|
allow(ActiveRecord::Base.connection).to receive(:columns).and_return([])
|
|
|
|
described_class.new(inicio: Date.new(2026, 8, 1), fim: Date.new(2026, 8, 31)).send(:carregar)
|
|
|
|
expect(sql).to include('nota_fiscal IS NOT NULL')
|
|
expect(sql).to include('NOT IN')
|
|
end
|
|
|
|
context 'sem nenhuma nota fora da operação' do
|
|
let(:visitas) { [] }
|
|
|
|
it 'não quebra e informa vazio' do
|
|
expect(fora.total).to eq(0)
|
|
expect(fora.any?).to be(false)
|
|
expect(fora.por_plano).to eq([])
|
|
end
|
|
end
|
|
|
|
def row(nf:, status:, driver:, checkout: nil, planned: nil, title: nil, obs: nil)
|
|
{ 'reference_id' => nf, 'status' => status, 'driver' => driver,
|
|
'checkout' => checkout, 'planned_date' => planned, 'observation' => obs,
|
|
'contact_name' => nil, 'title' => title, 'notes' => nil, 'comments' => nil, 'route_id' => nil }
|
|
end
|
|
end
|