require 'rails_helper'

RSpec.describe GestaoDeEstoque::Estoque, type: :model do
  it { is_expected.to belong_to(:item).class_name("Base::Item") }
  it { is_expected.to belong_to(:unidade_de_medida).class_name("UnidadeDeMedida") }
  it { is_expected.to belong_to(:almoxarifado).class_name("GestaoDeEstoque::Almoxarifado") }
  it { is_expected.to belong_to(:unidade_orcamentaria).class_name("Loa::UnidadeOrcamentaria") }
  it { is_expected.to belong_to(:sub_elemento_de_despesa) }
  it { is_expected.to have_many(:movimentacoes_do_estoque).class_name('GestaoDeEstoque::MovimentacaoDoEstoque').dependent(:destroy) }
  it { is_expected.to have_many(:sub_estoques_por_validade) }

  context "Retorna unidade de medida baseada na conversão" do
    it "Quando não tem conversão de medida" do
      item = FactoryBot.create(:caderno)
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: item.id, unidade_de_medida_id: item.unidade_de_medida_id)
      expect(estoque.unidade_de_medida_descricao).to eq item.unidade_de_medida.descricao
    end
    it "Quando tem conversão de medida" do
      item = FactoryBot.create(:caderno)
      unidade = FactoryBot.create(:unidade_de_medida, descricao: "Medida de Teste")
      estoque = FactoryBot.build(:gestao_de_estoque_estoque, item_id: item.id, unidade_de_medida_id: unidade.id)
      expect(estoque.unidade_de_medida_descricao).to eq unidade.descricao
    end
  end

  context "Calculo das Movimentações do Estoque" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque)
    end
    it "Calcula as Entradas" do
      segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_entrada: 10)
      @estoque.reload
      expect(@estoque.entrada_por_item_e_unidade_de_medida).to eq 160.0
    end
    it "Calcula as Saídas" do
      movimentacao_saida = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 15)
      @estoque.reload
      expect(@estoque.saida_por_item_e_unidade_de_medida).to eq 15.0
    end
    it "Calcula o Saldo Depois de Entradas e Saída" do
      segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_entrada: 10)
      movimentacao_saida = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 15)
      @estoque.reload
      expect(@estoque.saldo_por_item_e_unidade_de_medida).to eq 145.0
    end
  end

  context "Calculo das Movimentações Agrupadas Por Item e Unidade" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque)
      @segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque)
    end
    it "Calcula as Entradas" do
      segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_entrada: 10)
      @estoque.reload
      expect(@estoque.entrada_por_item_e_unidade_de_medida).to eq 160.0
    end
    it "Calcula as Saídas" do
      movimentacao_saida = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 15)
      @estoque.reload
      expect(@estoque.saida_por_item_e_unidade_de_medida).to eq 15.0
    end
    it "Calcula o Saldo Depois de Entradas e Saída" do
      segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_entrada: 10)
      movimentacao_saida = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque: @estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 15)
      @estoque.reload
      expect(@estoque.saldo_por_item_e_unidade_de_medida).to eq 145.0
    end
  end

  context "Calcula Valor Unitário Médio" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque)
    end
    it 'quando cria um recebimento' do
      @estoque.movimentacoes_do_estoque.create(FactoryBot.attributes_for(:gestao_de_estoque_movimentacao_do_estoque, :entrada, valor_unitario: 15, quantidade_entrada: 50, valor_total: 750))
      @estoque.reload
      expect(@estoque.valor_unitario_medio.to_f).to eq 12.90
    end
    it 'quando cria uma requisicao' do
      @estoque.movimentacoes_do_estoque.create(FactoryBot.attributes_for(:gestao_de_estoque_movimentacao_do_estoque, :saida, valor_unitario: 12.2, quantidade_saida: 50, valor_total: 610))
      @estoque.reload
      expect(@estoque.valor_unitario_medio.to_f).to eq 12.2
    end
  end

  describe "#entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: "consumo")
      @sub_elemento_de_despesa = FactoryBot.create(:sub_elemento_de_despesa_outros_materiais_de_consumo)
      @estoque.update_attribute(:sub_elemento_de_despesa_id, @sub_elemento_de_despesa.id)
    end
    context "Quando é valido" do
      it "Quando só existe o proprio estoque com mesmo almoxarifado e Unidade orcamentaria e sub elemento, retorna a soma das proprias entradas" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)
        FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_entrada: 10)

        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 20
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria e mesmo tipo de material e mesmo sub elemento de despesa, retorna a soma das entradas de ambos" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)
        FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_entrada: 10)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: @sub_elemento_de_despesa.id, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)
        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 30
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria tipo de material igual mas sub elemento de despesa diferente, retorna a soma das entradas do estoque referenciado" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)
        FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_entrada: 10)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: nil, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)
        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 20
      end

      it "Retorna 0 quando não possui nenhuma entrada" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.destroy

        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 0
      end
    end

    context "Quando é invalido" do
      it "retorna 0 quando não tem tipo de material" do
        @estoque.update_attribute(:tipo_de_material, nil)
        expect(@estoque.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas(Date.today, Date.today)).to eq 0
      end
      it "retorna 0 qunto tem parametros inválidos" do
        expect(@estoque.entradas_dos_estoques_com_mesmo_sub_elemento_entre_datas("invalido", "invalido")).to eq 0
      end
    end
  end

  describe "#saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: "consumo")
      @sub_elemento_de_despesa = FactoryBot.create(:sub_elemento_de_despesa_outros_materiais_de_consumo)
      @estoque.update_attribute(:sub_elemento_de_despesa_id, @sub_elemento_de_despesa.id)
    end
    context "Quando é valido" do
      it "Quando só existe o proprio estoque com mesmo almoxarifado e Unidade orcamentaria e sub_elemento_de_despesa, retorna a soma das proprias saidas" do
        movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_saida: 10)

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 10
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria e mesmo tipo de material e sub_elemento_de_despesa, retorna a soma das saidas de ambos" do
        movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_saida: 10)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: @sub_elemento_de_despesa.id, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: segundo_estoque.id, quantidade_saida: 10)

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 20
      end

      it "Quando existe outro estoque com mesmo almoxarifado, Unidade orcamentaria e tipo de material, porem sub elemento diferente , retorna a soma das saidas do estoque referenciado" do
        movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_saida: 10)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: nil, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: segundo_estoque.id, quantidade_saida: 10)

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 10
      end

      it "Retorna 0 quando não possui nenhuma saida" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.destroy

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 0
      end
    end

    context "Quando é invalido" do
      it "retorna 0 quando não tem tipo de material" do
        @estoque.update_attribute(:tipo_de_material, nil)
        expect(@estoque.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas(Date.today, Date.today)).to eq 0
      end
      it "retorna 0 qunto tem parametros inválidos" do
        expect(@estoque.saidas_dos_estoques_com_mesmo_sub_elemento_entre_datas("invalido", "invalido")).to eq 0
      end
    end
  end

  describe "#saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: "consumo")
    end
    context "Quando é valido" do
      it "Quando só existe o proprio estoque com mesmo almoxarifado e Unidade orcamentaria, retorna a soma das proprias saidas" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(origem_type: "Administrativo::RequisicaoDeMaterial", quantidade_saida: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_saida: 10)
        segunda_movimentacao.update_attribute(:data_da_movimentacao, movimentacao.data_da_movimentacao)

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 20
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria e mesmo tipo de material, retorna a soma das saidas de ambos" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(origem_type: "Administrativo::RequisicaoDeMaterial", quantidade_saida: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(origem_type: "Administrativo::RequisicaoDeMaterial", quantidade_saida: 30, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 40
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria tipo de material diferente, retorna a soma das saidas do estoque referenciado" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(origem_type: "Administrativo::RequisicaoDeMaterial", quantidade_saida: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "permanente", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(origem_type: "Administrativo::RequisicaoDeMaterial", quantidade_saida: 30, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)
        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 10
      end

      it "Retorna 0 quando não possui nenhuma saida" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.destroy

        expect(@estoque.reload.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 0
      end
    end

    context "Quando é invalido" do
      it "retorna 0 quando não tem tipo de material" do
        @estoque.update_attribute(:tipo_de_material, nil)
        expect(@estoque.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas(Date.today, Date.today)).to eq 0
      end
      it "retorna 0 qunto tem parametros inválidos" do
        expect(@estoque.saidas_dos_estoques_com_mesmo_almoxarifado_entre_datas("invalido", "invalido")).to eq 0
      end
    end
  end

  describe "#sub_estoque_mais_proximo_a_vencer" do
    context "Quando tem mais de um sub estoque" do
      it "retorna o mais proximo a vencer" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque, :estoque_com_sub_estoque)
        estoque.sub_estoques_por_validade.last.update_attribute(:validade, Date.today)
        sub_estoque_mais_proximo_a_vencer = FactoryBot.create(:gestao_de_estoque_sub_estoque_por_validade, estoque_id: estoque.id, validade: Date.today - 1.day )

        expect(estoque.reload.sub_estoque_mais_proximo_a_vencer).to eq sub_estoque_mais_proximo_a_vencer
      end
    end
    context "Quando não tem sub estoque" do
      it "retorna nil" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque)

        expect(estoque.sub_estoque_mais_proximo_a_vencer).to eq nil
      end
    end
  end

  describe "#entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: "consumo")
    end
    context "Quando é valido" do
      it "Quando só existe o proprio estoque com mesmo almoxarifado e Unidade orcamentaria, retorna a soma das proprias entradas" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :entrada, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, almoxarifado_id: @estoque.almoxarifado_id ,estoque_id: @estoque.id, quantidade_entrada: 10)
        segunda_movimentacao.update_attribute(:data_da_movimentacao, movimentacao.data_da_movimentacao)
        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 20
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria e mesmo tipo de material, retorna a soma das entradas de ambos" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(data_da_movimentacao: movimentacao.data_da_movimentacao,quantidade_entrada: 20, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)

        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 30
      end

      it "Quando existe outro estoque com mesmo almoxarifado e Unidade orcamentaria tipo de material diferente, retorna a soma das entradas do estoque referenciado" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "permanente", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(data_da_movimentacao: movimentacao.data_da_movimentacao,quantidade_entrada: 20, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)
        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 10
      end

      it "Retorna 0 quando não possui nenhuma entrada" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.destroy

        expect(@estoque.reload.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 0
      end
    end

    context "Quando é invalido" do
      it "retorna 0 quando não tem tipo de material" do
        @estoque.update_attribute(:tipo_de_material, nil)
        expect(@estoque.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas(Date.today, Date.today)).to eq 0
      end
      it "retorna 0 qunto tem parametros inválidos" do
        expect(@estoque.entradas_dos_estoques_com_mesmo_almoxarifado_entre_datas("invalido", "invalido")).to eq 0
      end
    end
  end

  describe "#sub_estoque_mais_longe_a_vencer" do
    context "Quando tem mais de um sub estoque" do
      it "retorna o mais longe a vencer" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque, :estoque_com_sub_estoque)
        estoque.sub_estoques_por_validade.last.update_attribute(:validade, Date.today - 1.day)
        sub_estoque_mais_longe_a_vencer = FactoryBot.create(:gestao_de_estoque_sub_estoque_por_validade, estoque_id: estoque.id, validade: Date.today)

        expect(estoque.reload.sub_estoque_mais_longe_a_vencer).to eq sub_estoque_mais_longe_a_vencer
      end
    end
    context "Quando não tem sub estoque" do
      it "retorna nil" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque)

        expect(estoque.sub_estoque_mais_proximo_a_vencer).to eq nil
      end
    end
  end

  describe "#total_dos_estoques_com_mesmo_sub_elemento" do
    before(:each) do
      @estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: "consumo")
      @sub_elemento_de_despesa = FactoryBot.create(:sub_elemento_de_despesa_outros_materiais_de_consumo)
      @estoque.update_attribute(:sub_elemento_de_despesa_id, @sub_elemento_de_despesa.id)
    end
    context "Quando é válido" do
      it "Quando é o único estoque com o almoxarifado, unidade orcamentaria e elemento de despesa, retorna (entradas - saidas) proprias do estoque" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        segunda_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque_id: @estoque.id, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 5)
        segunda_movimentacao.update_attribute(:data_da_movimentacao, movimentacao.data_da_movimentacao)
        expect(@estoque.reload.total_dos_estoques_com_mesmo_sub_elemento(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 5
      end
      it "Quando existe mais de um estoque com almoxarifado, unidade orcamentaria e elemento de despesa iguais, retorna (entradas - saidas) de todos os estoques" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: @sub_elemento_de_despesa.id ,almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(data_da_movimentacao: movimentacao.data_da_movimentacao,quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)

        terceira_movimentacao = FactoryBot.create(:gestao_de_estoque_movimentacao_do_estoque, :saida, estoque_id: @estoque.id, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, quantidade_saida: 5)
        terceira_movimentacao.update_attribute(:data_da_movimentacao, movimentacao.data_da_movimentacao)
        expect(@estoque.reload.total_dos_estoques_com_mesmo_sub_elemento(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 15
      end
      it "Quando existe estoques com almoxarifado e unidades orcamentarias iguais e elementos de despesa diferente, retorna (entradas - saidas) do estoque de referencia" do
        movimentacao = @estoque.movimentacoes_do_estoque.last
        movimentacao.update_attributes(quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        movimentacao.save(validate: false)

        item_base_papel = FactoryBot.create(:papel)
        segundo_estoque = FactoryBot.create(:gestao_de_estoque_estoque, sub_elemento_de_despesa_id: nil ,almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id, tipo_de_material: "consumo", item_id: item_base_papel)
        segunda_movimentacao = segundo_estoque.movimentacoes_do_estoque.last
        segunda_movimentacao.update_attributes(data_da_movimentacao: movimentacao.data_da_movimentacao,quantidade_entrada: 10, almoxarifado_id: @estoque.almoxarifado_id, unidade_orcamentaria_id: @estoque.unidade_orcamentaria_id)
        segunda_movimentacao.save(validate: false)

        expect(@estoque.reload.total_dos_estoques_com_mesmo_sub_elemento(movimentacao.data_da_movimentacao, movimentacao.data_da_movimentacao)).to eq 10
      end
    end
    context "Quando é invalido" do
      it "retorna 0 quando não tem tipo de material" do
        @estoque.update_attribute(:tipo_de_material, nil)
        expect(@estoque.total_dos_estoques_com_mesmo_sub_elemento(Date.today, Date.today)).to eq 0
      end
      it "retorna 0 qunto tem parametros inválidos" do
        expect(@estoque.total_dos_estoques_com_mesmo_sub_elemento("invalido", "invalido")).to eq 0
      end
    end
  end

  describe "#titulo_do_tipo_de_material" do
    context "Quando possui tipo de material" do
      ["consumo", "permanente", "consumo_distribuicao_gratuita"].each do |tipo_de_material|
        it "Retorna titulo com i18n" do
          estoque = FactoryBot.create(:gestao_de_estoque_estoque, tipo_de_material: tipo_de_material)
          expect(estoque.titulo_do_tipo_de_material).to eq "Bens #{estoque.tipo_de_material_i18n}"
        end
      end
    end
    context "Quando não possui tipo de material" do
      it "retorna string vazia" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque)
        expect(estoque.titulo_do_tipo_de_material).to eq ""
      end
    end
  end

  describe "quantidade_mais_proxima_a_vencer" do
    context "Quando tem mais de um sub estoque" do
      it "retorna a quantidade do mais proximo a vencer" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque, :estoque_com_sub_estoque)
        estoque.sub_estoques_por_validade.last.update_attribute(:validade, Date.today)
        estoque.sub_estoques_por_validade.last.update_attribute(:quantidade, 5)
        FactoryBot.create(:gestao_de_estoque_sub_estoque_por_validade, estoque_id: estoque.id, validade: Date.today - 1.day, quantidade: 10 )

        expect(estoque.reload.quantidade_mais_proxima_a_vencer).to eq 10
      end
    end
    context "Quando não tem sub estoque" do
      it "retorna nil" do
        estoque = FactoryBot.create(:gestao_de_estoque_estoque)

        expect(estoque.quantidade_mais_proxima_a_vencer).to eq 0
      end
    end
  end
end
