require 'rails_helper'

RSpec.describe Contabilidade::DespesaExtraOrcamentaria, type: :model do
	it { is_expected.to belong_to(:orcamento).required(true) }
	it { is_expected.to belong_to(:conta_bancaria_por_unidade_orcamentaria).class_name('Base::ContaBancariaPorUnidadeOrcamentaria').required(true) }
	it { is_expected.to belong_to(:conta_extra_orcamentaria).required(true) }
	it { is_expected.to belong_to(:pessoa).class_name('Base::Pessoa').required(true) }

	it { is_expected.to have_one :estorno_de_despesa_extra_orcamentaria }

	[:orcamento_id, :data_de_emissao, :conta_extra_orcamentaria_id, :conta_bancaria_por_unidade_orcamentaria_id,
		:credor_id, :tipo_de_documento, :valor_da_despesa].each do |atributo|
		it { is_expected.to validate_presence_of atributo }
	end

	it { is_expected.to validate_numericality_of(:valor_da_deducao).is_greater_than(0) }
	it { is_expected.to validate_numericality_of(:valor_da_despesa).is_greater_than(0) }

	describe "#atribui_codigo_disponivel" do
		context "ao criar uma despesa extraorçamentária sem número de caixa" do
			it "gera número de caixa dinamicamente" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria, numero_de_caixa: '')
				expect( despesa_extra_orcamentaria.numero_de_caixa ).to eq despesa_extra_orcamentaria[:data_de_emissao].strftime("%d%m") + '0001'
			end
		end

		context "ao criar uma despesa extraorçamentária sem número de caixa" do
			it "gera número de caixa fixo" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria, numero_de_caixa: '123123')
				expect( despesa_extra_orcamentaria.numero_de_caixa ).to eq '123123'
			end
		end
	end

	describe "#verifica_saldo" do	#
		context 'caso conta bancaria tenha saldo menor que valor da despesa a despesa' do
			it 'retorna mensagem de erro' do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria, valor_da_despesa: 3000000.00)
				expect(despesa_extra_orcamentaria).to_not be_valid
				expect(despesa_extra_orcamentaria.errors[:conta_bancaria_por_unidade_orcamentaria_id]).to include 'Saldo insuficiente'
			end
		end
	end

	context "#valor_total" do
		it "retorna valor total da despesa" do
			Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
			despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria, valor_da_despesa: 1.5, valor_da_deducao: 2, valor_juros_e_multa: 3)
			expect(despesa_extra_orcamentaria.valor_total).to eq 6.5
		end
	end

	describe "#debita_da_conta_extra_orcamentaria" do
		context "ao criar uma despesa extraorçamentária" do
			it "debitar da conta extraorçamentária" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria)
				despesa_extra_orcamentaria.conta_extra_orcamentaria.reload
				expect(despesa_extra_orcamentaria.conta_extra_orcamentaria.saldo.to_f).to eq 24.97
			end
		end
	end

	describe "#credita_da_conta_extra_orcamentaria" do
		context "ao remover uma despesa extraorçamentária" do
			it "credita da conta extraorçamentária" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria)
				saldo_inicial = despesa_extra_orcamentaria.conta_extra_orcamentaria.saldo_inicial
				despesa_extra_orcamentaria.conta_extra_orcamentaria.reload

				conta_extra_orcamentaria = despesa_extra_orcamentaria.conta_extra_orcamentaria
				despesa_extra_orcamentaria.destroy
				conta_extra_orcamentaria.reload
				expect(conta_extra_orcamentaria.saldo_inicial).to eq saldo_inicial
			end
		end
	end

	describe "#desfaz_movimentacao" do
		context "ao remover uma despesa extraorçamentária" do
			it "desfaz a movimentação na conta_bancaria_por_unidade_orcamentaria" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				despesa_extra_orcamentaria = FactoryBot.create(:despesa_extra_orcamentaria)
				conta_extra_orcamentaria = despesa_extra_orcamentaria.conta_extra_orcamentaria

				expect { despesa_extra_orcamentaria.destroy }.to change(Contabilidade::MovimentacaoDaContaBancaria, :count).by(-1)
			end
		end
	end

	describe "#gera_movimentacao" do
		context "ao criar uma despesa extraorçamentária" do
			it "gera uma movimentacao na conta_bancaria_por_unidade_orcamentaria" do
				Contabilidade::ContaExtraPorUnidadeOrcamentaria.find_or_create_by!(FactoryBot.attributes_for(:conta_extra_por_unidade_orcamentaria))
				expect { FactoryBot.create(:despesa_extra_orcamentaria) }.to change(Contabilidade::MovimentacaoDaContaBancaria, :count).by(4)
			end
		end
	end

	describe "#verifica_saldo_conta_extra" do
		context "Válido" do
			it "Quando não tem data de emissão" do
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria, data_de_emissao: nil)
				despesa_extra_orcamentaria.validate
				expect(despesa_extra_orcamentaria.errors[:conta_extra_orcamentaria_id]).to_not include("Saldo insuficiente, saldo disponível na data selecionada R$ 0,00")
			end
			it "Quando não tem unidade orcamentaria_id" do
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria, unidade_orcamentaria_id: nil)
				despesa_extra_orcamentaria.validate
				expect(despesa_extra_orcamentaria.errors[:conta_extra_orcamentaria_id]).to_not include("Saldo insuficiente, saldo disponível na data selecionada R$ 0,00")
			end
			it "Quando tem data de emissão e unidade_orcamentaria_id e tem saldo disponivel naquele periodo" do
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria)
				saldo_receita = despesa_extra_orcamentaria.conta_extra_orcamentaria.lancamentos_da_receita_por_unidade_entre_periodo(despesa_extra_orcamentaria.unidade_orcamentaria_id, despesa_extra_orcamentaria.data_de_emissao).sum(&:valor)
				despesa_extra_orcamentaria.validate
				expect(despesa_extra_orcamentaria.errors[:conta_extra_orcamentaria_id]).to_not include("Saldo insuficiente, saldo disponível na data selecionada #{saldo_receita.to_d.real_contabil}")
			end
		end
		context "inválido" do
			it "Quando tem data de emissão e unidade_orcamentria_id mas não possui saldo disponivel naquele periodo" do
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria, valor_da_despesa: 1000)
				saldo_receita = despesa_extra_orcamentaria.conta_extra_orcamentaria.lancamentos_da_receita_por_unidade_entre_periodo(despesa_extra_orcamentaria.unidade_orcamentaria_id, despesa_extra_orcamentaria.data_de_emissao).sum(&:valor)
				despesa_extra_orcamentaria.validate
				expect(despesa_extra_orcamentaria.errors[:conta_extra_orcamentaria_id]).to include("Saldo insuficiente, saldo disponível na data selecionada #{saldo_receita.to_d.real_contabil}")
			end
			it "Quando tem data de emissão e unidaed_orcamentaria_id mas não possui nenhuma movimentação" do
				despesa_extra_orcamentaria = FactoryBot.build(:despesa_extra_orcamentaria)
				despesa_extra_orcamentaria.conta_extra_orcamentaria.lancamentos_extraorcamentario_receita.last.destroy
				despesa_extra_orcamentaria.validate
				expect(despesa_extra_orcamentaria.errors[:conta_extra_orcamentaria_id]).to include("Saldo insuficiente, saldo disponível na data selecionada #{0.real_contabil}")
			end
		end
	end
end
