require 'rails_helper'

RSpec.describe Contabilidade::Pagamento, type: :model do
	cria_configuracao_default

	#it_behaves_like "gera eventos contábeis", "Pagar", Contabilidade::Pagamento, :pagamento_de_pessoal
	#it_behaves_like "vistoriavel concern", "Pagar", Contabilidade::Liquidacao, :pagamento_de_pessoal

	it{ is_expected.to belong_to(:liquidacao).required}
	it{ is_expected.to belong_to(:orcamento)}
	it{ is_expected.to belong_to(:pessoa_conta_bancaria)}

	it { is_expected.to have_one(:estorno_de_pagamento).dependent(:restrict_with_exception) }
	it { is_expected.to have_many(:retencoes).inverse_of(:pagamento) }
	it { is_expected.to have_many(:contas_bancarias_por_pagamento).class_name("Base::ContaBancariaPorPagamento") }
	it { is_expected.to have_many(:taloes_de_receita) }

	it { is_expected.to accept_nested_attributes_for(:retencoes).allow_destroy(true) }
	it { is_expected.to accept_nested_attributes_for(:contas_bancarias_por_pagamento).allow_destroy(true) }

	[:data_da_solicitacao, :valor, :liquidacao_id, :forma_de_pagamento].each { |atributo|
		it{ is_expected.to validate_presence_of atributo }
	}

	# it{ is_expected.to validate_numericality_of(:valor).is_greater_than(0)}

	it{ is_expected.to validate_uniqueness_of( :numero ).allow_blank}

	it { is_expected.to allow_value('01/01/2016').for(:data) }



	it "atualiza saldo da liquidação" do
		liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, valor: 100) )
		Contabilidade::Pagamento.find_or_create_by!( FactoryBot.attributes_for(:pagamento_de_pessoal, valor: 100, liquidacao: liquidacao ) )

		expect(liquidacao.saldo).to eq 0.00
	end

	describe "#data_deve_ser_maior_ou_igual_data_da_liquidacao" do
		context "quando a data da solicitação do pagamento é menor que à data da liquidação correspondente" do
			it "valida que o pagamento vai ter erro na data da solicitação" do
				liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, data_da_liquidacao: "2016-11-12") )
				pagamento = Contabilidade::Pagamento.new( FactoryBot.attributes_for(:pagamento_de_pessoal, liquidacao: liquidacao, data_da_solicitacao: "2016-11-11", valor: liquidacao.valor) )
				pagamento.save

				expect(pagamento.errors[:data_da_solicitacao]).to include "deve ser maior ou igual a data da liquidação #{liquidacao.data_da_liquidacao}"
			end
		end

		context "quando a data da solicitação do pagamento é igual que à data da liquidação correspondente" do
			it "valida que o pagamento vai ter erro na data da solicitação" do
				liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, data_da_liquidacao: "2016-11-12") )
				pagamento = Contabilidade::Pagamento.new( FactoryBot.attributes_for(:pagamento_de_pessoal, liquidacao: liquidacao, data_da_solicitacao: liquidacao.data_da_liquidacao, valor: liquidacao.valor) )
				pagamento.save

				expect(pagamento.errors[:data_da_solicitacao]).to_not include "deve ser maior ou igual a data da liquidação #{liquidacao.data_da_liquidacao}"
			end
		end

		context "quando a data da solicitação do pagamento é maior que à data da liquidação correspondente" do
			it "valida que o pagamento vai ter erro na data da solicitação" do
				liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, data_da_liquidacao: "2016-11-12") )
				pagamento = Contabilidade::Pagamento.new( FactoryBot.attributes_for(:pagamento_de_pessoal, liquidacao: liquidacao, data_da_solicitacao: "2016-11-13", valor: liquidacao.valor) )
				pagamento.save

				expect(pagamento.errors[:data_da_solicitacao]).to_not include "deve ser maior ou igual a data da liquidação #{liquidacao.data_da_liquidacao}"
			end
		end
	end

	describe "#valor_deve_ser_igual_ao_valor_pago_mais_impostos" do
		#pending
	end

	describe '#pagamento_deve_ser_menor_ou_igual_ao_saldo_da_liquidacao' do
		it "valida que um pagamento deve possuir o valor maior ou igual ao saldo da liquidação correspondente" do
			liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, valor: 50) )
			pagamento = Contabilidade::Pagamento.new( FactoryBot.attributes_for(:pagamento_de_pessoal, valor: 60, liquidacao: liquidacao ) )
			pagamento.save

			expect(pagamento.errors[:valor]).to include 'deve ser menor ou igual ao saldo da liquidação '
		end
	end

	describe "#quando_for_uma_diaria_valor_deve_ser_o_mesmo" do
		context "quando pagamento pertence a uma diaria" do
			it "retorna mensagem de erro" do
				pagamento = FactoryBot.build(:pagamento_com_diaria)
				pagamento[:valor] = 5
				pagamento.validate

				expect(pagamento.errors[:valor]).to include("deve ser o mesmo valor da diária")
			end
		end
	end

	describe '#impedir_update_se_pagamento_estornado' do
		it 'retorna mensagem de erro e não atualiza' do
			pagamento = FactoryBot.create :pagamento_de_pessoal, estornado: true
			pagamento.update(valor: 10)

			expect(pagamento.errors[:base]).to include 'não é possível editar um pagamento estornado'
		end
	end

	describe '#porcentagem_da_liquidacao' do
		context 'sem valor estornado' do
			it 'retorna percentual do pagamento na liquidacao' do
				liquidacao = FactoryBot.create :liquidacao_001, valor: 100
				pagamento = FactoryBot.create :pagamento_de_pessoal, valor: 8, liquidacao: liquidacao
				expect(pagamento.porcentagem_da_liquidacao.to_f).to eq 8
			end
		end

		context 'com valor estornado' do
			it 'retorna zero' do
				pagamento = FactoryBot.create :pagamento_de_pessoal, estornado: true
				expect(pagamento.porcentagem_da_liquidacao).to eq 0.0
			end
		end
	end

	describe "#inclui_valor_pago_na_liquidacao" do
		context "atualiza campo valor_pago da liquidacao ao criar pagamento" do
			it "retorna liquidacao com novo valor_pago" do
				liquidacao = Contabilidade::Liquidacao.find_or_create_by!( FactoryBot.attributes_for(:liquidacao_001, valor: 100) )
				pagamento = Contabilidade::Pagamento.find_or_create_by!( FactoryBot.attributes_for(:pagamento_de_pessoal, valor: 100, liquidacao: liquidacao ) )
				expect(pagamento.liquidacao.valor_pago.to_f).to eq 100
			end
		end
	end

	describe '#uniq_nested_attributes' do
		describe 'quando são passados 2 impostos de mesmo tipo' do
			context 'e um deles contém destroy = true' do
				it 'salva' do
					pagamento = FactoryBot.create :pagamento_de_pessoal
					iss = FactoryBot.create(:retencao_iss, pagamento_id: pagamento.id)
					pagamento.reload
					imposto = FactoryBot.create(:servico_para_explorarao_de_rodovia, descricao: "imposto 2", codigo: "27")
					atributos_de_retencoes =  {
						retencoes_attributes: {
							"0" => iss.attributes.merge(_destroy: true),
							"1" => FactoryBot.attributes_for(:retencao_iss, imposto_id:imposto.id)
						}
					}

					pagamento.update(atributos_de_retencoes)

					expect(pagamento).to be_persisted
				end
			end
			context 'e nenhum contém destroy = true' do
				it 'retorna erro' do
					pagamento = FactoryBot.create :pagamento_de_pessoal
					iss = FactoryBot.create(:retencao_iss, pagamento_id: pagamento.id)
					pagamento.reload
					imposto = FactoryBot.create(:servico_para_explorarao_de_rodovia, descricao: "imposto 2", codigo: "27")
					atributos_de_retencoes =  {
						retencoes_attributes: {
							"0" => iss.attributes,
							"1" => FactoryBot.attributes_for(:retencao_iss, imposto_id:imposto.id)
						}
					}

					pagamento.update(atributos_de_retencoes)

					expect(
						pagamento.errors[:"retencoes"]
					).to include( 'imposto deve ser único dentro de pagamento' )
				end
			end
		end
	end

	context 'Data da solicitação do pagamento superior a data de abertura da conta' do
		before(:each) do
			@pagamento = FactoryBot.create(:pagamento_de_pessoal)
			@pagamento.reload
		end
		it 'Quando data da solicitação é superior ou igual a data de abertura da conta' do
			@pagamento.contas_bancarias_por_pagamento.last.conta_bancaria.update_attribute(:data_de_abertura, @pagamento.data_da_solicitacao)
			@pagamento.validate
			expect(@pagamento.errors[:data_da_solicitacao]).to_not include "Inferior a Data de Abertura das Seguintes Contas: #{@pagamento.contas_bancarias_por_pagamento.last.conta_bancaria.to_s}"
		end
		it 'Quando data da solicitação é inferior a data de abertura da conta' do
			@pagamento.contas_bancarias_por_pagamento.last.conta_bancaria.update_attribute(:data_de_abertura, @pagamento.data_da_solicitacao + 1.day)
			@pagamento.validate
			expect(@pagamento.errors[:data_da_solicitacao]).to include "Inferior a Data de Abertura das Seguintes Contas: #{@pagamento.contas_bancarias_por_pagamento.last.conta_bancaria.to_s}"
		end
	end

	describe 'esta_em_um_lote_bancario?' do
		context 'quando não há lote nem contas bancarias por pagamento' do
			it 'return false' do
				pagamento = Contabilidade::Pagamento.new
				expect(pagamento.esta_em_um_lote_bancario?).to eq false
			end
		end

		context 'quando não há lote' do
			it 'return false' do
				pagamento = Contabilidade::Pagamento.new
				pagamento.contas_bancarias_por_pagamento.build
				expect(pagamento.esta_em_um_lote_bancario?).to eq false
			end
		end

		context 'quando há lote' do
			it 'retorna true' do
				lote_bancario = Contabilidade::LoteBancario.new(pagamentos_do_lote_bancario: [FactoryBot.create(:contabilidade_pagamento_do_lote_bancario)])
				pagamento = lote_bancario.pagamentos_do_lote_bancario.first.conta_bancaria_por_pagamento.pagamento
				expect(pagamento.esta_em_um_lote_bancario?).to eq true
			end
		end
	end
end
