class Base::NaturezaDaReceita < ApplicationRecord
	include ReceitaConcern

	attr_accessor :valor_disponivel
	attr_accessor :valor_temporario
	attr_accessor :tipo_de_alteracao

	attr_default :valor_previsto, 0.00
	attr_default :valor_alteracao_da_previsao, 0.00
	attr_default :de_convenio, false
	attr_default :pedir_cadastro_de_convenio, false
	attr_default :pedir_cadastro_de_operacao_de_credito, false
	attr_default :evento_contabil_obrigatorio, false
	attr_default :tipo_de_receita, "primaria"
	attr_default :exibir, true
	attr_default :novo_tipo, true
	attr_default :forma_de_adicao, :original

	belongs_to :modulo, polymorphic: true
	belongs_to :tipo_de_orcamento, class_name: 'Base::TipoDeOrcamento', required: true
	belongs_to :tipo_de_deducao, class_name: 'Loa::TipoDeDeducao'
	belongs_to :receita_stn
	belongs_to :sub_conta_pcasp, class_name: 'Contabilidade::SubContaPcasp', required: false

	has_one :percentuais_mensais, class_name: 'Base::Rcl', as: :modulo, dependent: :destroy

	has_many :unidades_orcamentarias_por_natureza_da_receita, class_name: 'Loa::UnidadeOrcamentariaPorNaturezaDaReceita', dependent: :destroy
	has_many :taloes_de_receita, class_name: 'Contabilidade::TalaoDeReceita'
	has_many :anulacoes_dos_taloes_de_receita, through: :taloes_de_receita, class_name: 'Contabilidade::AnulacaoDoTalaoDeReceita'
	has_many :orcamentos_da_receita, through: :unidades_orcamentarias_por_natureza_da_receita, class_name: 'Loa::OrcamentoDaReceita'
	has_many :movimentacoes_do_plano_de_contas, through: :orcamentos_da_receita, class_name: 'Contabilidade::MovimentacaoDoPlanoDeContas'
	has_many :convenios, -> (receita) {
		unscope(:where).where("receita_corrente_id = :id OR receita_de_capital_id = :id ", id: receita.id)
	}, class_name: "Contabilidade::Convenio"
	has_many :fonte_de_recursos, -> { group("codigo,descricao").select("codigo, descricao", "SUM(valor) AS valor") }, through: :orcamentos_da_receita, class_name: 'Base::FonteDeRecursos'
	has_many :ocorrencias_da_alteracao_da_receita, class_name: 'Base::OcorrenciaDaAlteracaoDaReceita'

	after_create :cria_naturezas_optativas_para_deducao_e_intra_correspondentes, if: Proc.new { receita_opcional? && receita_orcamentaria? }
	after_create :cria_receita_da_projecao
	after_create :replica_naturezas_optativas_existentes, if: Proc.new { padrao? && !receita_orcamentaria? }
	after_update :atualiza_projecao_de_receita

	after_update :atualiza_configuracao_filhos, if: Proc.new { pode_ser_configurada? && filhos.any? }
	after_create :oculta_despesas_de_deducao_exceto_fundeb

	before_destroy :impede_delecao_para_receita_orcada, if: :novo_tipo?

	scope :podem_ter_filhos, -> { select(&:pode_ter_filho?) }

	after_destroy :apaga_naturezas_optativas_para_deducao_e_intra, if: Proc.new { receita_opcional? && receita_orcamentaria? }
	after_destroy :apaga_receita_da_projecao
	after_destroy :apaga_pais_sem_valor_e_filhos

	accepts_nested_attributes_for :unidades_orcamentarias_por_natureza_da_receita, allow_destroy: true
	accepts_nested_attributes_for :percentuais_mensais, allow_destroy: true

	validates_presence_of :modulo_id, :modulo_type, :tipo_de_orcamento_id, :valor_previsto

	validates_presence_of :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :tipo_de_deducao_id, if: :novo_tipo
	validates_absence_of :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :tipo_de_deducao_id, unless: :novo_tipo

	validates_presence_of :receita_stn_id, if: :padrao
	validates_absence_of :receita_stn_id, unless: :padrao

	validates_uniqueness_of :codigo,                scope: [:modulo_type, :modulo_id], case_sensitive: false, if: Proc.new { self.codigo_changed? }
	validates_uniqueness_of :categoria_economica,   scope: [:origem, :especie, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false , if: Proc.new { self.categoria_economica_changed? }
	validates_uniqueness_of :origem,                scope: [:categoria_economica, :especie, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false , if: Proc.new { self.origem_changed? }
	validates_uniqueness_of :especie,               scope: [:categoria_economica, :origem, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.especie_changed? }
	validates_uniqueness_of :rubrica,               scope: [:categoria_economica, :origem, :especie, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.rubrica_changed? }
	validates_uniqueness_of :alinea,                scope: [:categoria_economica, :origem, :especie, :rubrica, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.alinea_changed? }
	validates_uniqueness_of :subalinea,             scope: [:categoria_economica, :origem, :especie, :rubrica, :alinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.subalinea_changed? }
	validates_uniqueness_of :detalhamento_optativo, scope: [:categoria_economica, :origem, :especie, :rubrica, :alinea, :subalinea, :nivel_opcional_1, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.detalhamento_optativo_changed? }
	validates_uniqueness_of :nivel_opcional_1,      scope: [:categoria_economica, :origem, :especie, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_2, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.nivel_opcional_1_changed? }
	validates_uniqueness_of :nivel_opcional_2,      scope: [:categoria_economica, :origem, :especie, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_3, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.nivel_opcional_2_changed? }
	validates_uniqueness_of :nivel_opcional_3,      scope: [:categoria_economica, :origem, :especie, :rubrica, :alinea, :subalinea, :detalhamento_optativo, :nivel_opcional_1, :nivel_opcional_2, :modulo_id, :modulo_type], case_sensitive: false, if: Proc.new { self.nivel_opcional_3_changed? }
	validates_uniqueness_of :receita_stn_id,        scope: [:modulo_type, :modulo_id], allow_nil: true

	validates_numericality_of :valor_previsto, greater_than_or_equal_to: 0, if: Proc.new { !self.deducao? }
	validates_numericality_of :valor_previsto, less_than_or_equal_to: 0, if: Proc.new { self.deducao? }, message: "deve ser menor que 0 para receitas de dedução"
	# validates_numericality_of :valor_alteracao_da_previsao, greater_than: 0, if: Proc.new { self.valor_alteracao_da_previsao.present? } # kilmer revisar
	validates_numericality_of :percentual_de_aplicacao_na_educacao, greater_than_or_equal_to: 25, allow_nil: true
	validates_numericality_of :percentual_de_aplicacao_na_saude, greater_than_or_equal_to: 15, allow_nil: true
	validates_numericality_of :percentual_para_legislativo, greater_than_or_equal_to: 0, allow_nil: true

	validates :modulo_id, immutable: true
	validates :modulo_type, immutable: true
	validates :unidades_orcamentarias_por_natureza_da_receita, uniq_nested_attributes: { atributo: :unidade_orcamentaria_id, mensagem: "unidade orçamentária deve ser única dentro de uma natureza da receita" }

	# Foi solicitado a remoção da regra pelo Isaac 21/10/2022
	# validates :valor_previsto, valor_inserido_equals_valor_orcado: { associacao: :unidades_orcamentarias_por_natureza_da_receita, orcamento: :orcamentos_da_receita, mensagem: 'valor previsto não corresponde ao total da receita' }

	validates :valor_alteracao_da_previsao, valor_atual_equals_valor_orcado: { associacao: :unidades_orcamentarias_por_natureza_da_receita, orcamento_da_receita: :orcamentos_da_receita }, if: Proc.new { self.valor_alteracao_da_previsao.present? }
	validate :soma_dos_percentuais_nao_pode_exceder_cem
	validate :pai_deve_estar_sem_orcamento
	validate :receita_so_pode_ser_orcada_se_tipo_for_diferente_de_zero, if: :novo_tipo?
	validate :soma_dos_valores_destinados_igual_ao_previsto

	alias_method :descricao_para_detalhe_do_pagamento, :codigo_formatado_e_descricao

	before_save :lancar_ocorrencia, if: Proc.new { self.tipo_de_alteracao.present? }

	scope :de_convenio, -> { where(de_convenio: true)}

	after_save :torna_valor_da_deducao_negativa

	enum forma_de_adicao: { original: 1, revisado: 2	}

	def self.codigo_com_quatro_digitos codigo
		unidade = Loa::UnidadeOrcamentaria.find_by(codigo: codigo)
		unidade.codigo_completo
	end

	def self.codigo_com_tres_digitos codigo
		fonte = Base::FonteDeRecursos.find_by(codigo: codigo)
		fonte.try(:codigo_completo)
	end

	def torna_valor_da_deducao_negativa
		if self.categoria_economica.to_i >= 900 && self.total_previsto_agregado.to_f > 0
				self.valor_previsto = self.valor_previsto.to_f * (-1)
				self.save(validate: false)
		end
	end

	def oculta_despesas_de_deducao_exceto_fundeb
		tipo_de_deducao_do_fundeb = Loa::TipoDeDeducao.where("descricao like '%FUNDEB%'").first
		if self.categoria_economica.to_i >= 900 && self.tipo_de_deducao.codigo != tipo_de_deducao_do_fundeb.codigo
			self.exibir = false
			self.save(validate: false)
		end
	end

	def valor_total
		self.try(:orcamentos_da_receita).sum(:valor).to_f
	end

	def total_previsto_agregado(unidade_orcamentaria_id = nil, tipo_de_orcamento = nil)
		if tipo_de_orcamento == :fiscal
			tipo_de_orcamento = self.modulo.tipos_de_orcamento.find_by(codigo: 'F').id
		elsif tipo_de_orcamento == :social
			tipo_de_orcamento = self.modulo.tipos_de_orcamento.find_by(codigo: 'S').id
		else
			tipo_de_orcamento = self.modulo.tipos_de_orcamento.pluck(:id)
		end

		if de_convenio
			self.convenios.inject(0){|total, convenio| total + convenio.valores_do_convenio.sum(:valor) }
		elsif unidade_orcamentaria_id.to_i > 0
			Loa::OrcamentoDaReceita.joins(unidade_orcamentaria_por_natureza_da_receita: [:unidade_orcamentaria, :natureza_da_receita])
				.where(loa_unidades_orcamentarias: {id: unidade_orcamentaria_id}, base_naturezas_da_receita: classificacao_com_niveis_utilizados.merge({modulo_id: self.modulo_id, modulo_type: self.modulo_type, tipo_de_orcamento_id: tipo_de_orcamento}))
				.sum(:valor)
		else
			Base::NaturezaDaReceita.where(classificacao_com_niveis_utilizados.merge({modulo_id: self.modulo_id, modulo_type: self.modulo_type, tipo_de_orcamento_id: tipo_de_orcamento})).sum(:valor_previsto)
		end
	end

	def total_previsto_agregado_por_tipo_de_arrecadacao tipo_de_arrecadacao
		receitas = Base::NaturezaDaReceita.where(classificacao_com_niveis_utilizados.merge({modulo_id: self.modulo_id, modulo_type: self.modulo_type})).pluck(:id)
		fontes_ids = Base::FonteDeRecursos.where(tipo_de_arrecadacao: tipo_de_arrecadacao).pluck(:id)
		Loa::OrcamentoDaReceita.joins(:unidade_orcamentaria_por_natureza_da_receita).where(loa_unidades_orcamentarias_por_natureza_da_receita: {natureza_da_receita_id: receitas}, fonte_de_recursos_id: fontes_ids).sum(:valor).to_f
	end

	def valor_alteracao_igual_a_soma_de_valor_atual
		if self.valor_alteracao_da_previsao.to_f > 0
			self.valor_alteracao_da_previsao.to_f.contabil
		else
			self.valor_previsto.to_f.contabil
		end
	end

	def valor_total_realizado_da_receita
		self.try(:orcamentos_da_receita).sum(:valor_arrecadado).to_f
	end

	def valor_total_realizado_da_receita_por_data(data_inicial, data_final, unidades_orcamentarias = nil)
		if unidades_orcamentarias.nil?
			self.orcamentos_da_receita.flat_map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::TalaoDeReceita' ", data_inicial, data_final).to_a}.sum{|f| f.valor.to_d}
		else
			if unidades_orcamentarias.is_a?(Loa::UnidadeOrcamentaria)
				self.orcamentos_da_receita.joins(:unidade_orcamentaria_por_natureza_da_receita).where("loa_unidades_orcamentarias_por_natureza_da_receita.unidade_orcamentaria_id in (?)", unidades_orcamentarias.id).flat_map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::TalaoDeReceita' ", data_inicial, data_final).to_a}.sum{|f| f.valor.to_d} rescue 0
			else
				self.orcamentos_da_receita.joins(:unidade_orcamentaria_por_natureza_da_receita).where("loa_unidades_orcamentarias_por_natureza_da_receita.unidade_orcamentaria_id in (?)", unidades_orcamentarias.pluck(:id)).map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::TalaoDeReceita' ", data_inicial, data_final).to_a}.flatten.sum{|f| f.valor.to_d} rescue 0
			end
		end
	end

	def valor_total_anulado_da_receita_por_data(data_inicial, data_final, unidades_orcamentarias = nil)
		if unidades_orcamentarias.nil?
			self.orcamentos_da_receita.map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::AnulacaoDoTalaoDeReceita' ", data_inicial, data_final).to_a}.flatten.sum{|f| f.valor.to_d}
		else
			if unidades_orcamentarias.is_a?(Loa::UnidadeOrcamentaria)
				self.orcamentos_da_receita.joins(:unidade_orcamentaria_por_natureza_da_receita).where("loa_unidades_orcamentarias_por_natureza_da_receita.unidade_orcamentaria_id in (?)", unidades_orcamentarias.id).flat_map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::AnulacaoDoTalaoDeReceita' ", data_inicial, data_final).to_a}.sum{|f| f.valor.to_d} rescue 0
			else
				self.orcamentos_da_receita.joins(:unidade_orcamentaria_por_natureza_da_receita).where("loa_unidades_orcamentarias_por_natureza_da_receita.unidade_orcamentaria_id in (?)", unidades_orcamentarias.pluck(:id)).map{|f| f.lancamentos_do_orcamento_da_receita.where("data_do_lancamento >= ? AND data_do_lancamento <= ? AND modulo_type = 'Contabilidade::AnulacaoDoTalaoDeReceita' ", data_inicial, data_final).to_a}.flatten.sum{|f| f.valor.to_d} rescue 0
			end
		end
	end

	def deducao?
		if novo_tipo?
			categoria_economica.present? && categoria_economica[0] == "9" || (receita_stn.present? && receita_stn.codigo[0] == "9")
		else
			categoria_economica.to_i.eql?(9) && origem.to_i.eql?(5)
		end
	end

	def intra_orcamentaria?
		if novo_tipo?
			codigo[2] == "7" || codigo[2] == "8"
		else
			categoria_economica.to_i.eql?(7) || categoria_economica.to_i.eql?(8)
		end
	end

	def receita_antiga
		Base::NaturezaDaReceita.find_by(codigo_referencia: codigo, novo_tipo: false, modulo_id: self.modulo_id, modulo_type: self.modulo_type)
	end

	def pode_ser_excluida?
		filhos.blank? && valor_previsto == 0 && orcamentos_da_receita.map{|orc| orc.lancamentos_do_orcamento_da_receita}.flatten.blank?
	end

	def atualizar_valor_de_convenio
		tipo_de_receita = categoria_economica.to_i
		periodo = self.modulo.exercicio + 2

		(modulo.exercicio..periodo).each do |ano|
			valores_convenios = total_valores_do_convenio tipo_de_receita, ano
			calculo = self.modulo.projecao_de_receita.busca_projecoes_de_receita_por_orcamento codigo, ano

			if calculo
				calculo.total = valores_convenios
				return false unless calculo.save
			else
				receita = self.modulo.projecao_de_receita.receitas.find_by(codigo: self.codigo)
				Projecao::CalculoPorExercicio.transaction do
					if receita
						receita.calculo_por_exercicios.create!( exercicio: ano, tipo: 'convenio', receita_id: receita.id, total: valores_convenios, importado: false )
					else
						raise ActiveRecord::Rollback
					end
				end
			end

		end
	end

	def total_valores_do_convenio tipo_de_despesa, ano
		convenios.inject(0) {|total, convenio|
			total + convenio.valores_do_convenio.select{|valor_do_convenio|	valor_do_convenio.tipo_de_despesa.codigo == tipo_de_despesa && valor_do_convenio.exercicio == ano}.first.valor
		}
	end

	def gerar_codigo_para_filho codigo
		if pode_ter_filho? && codigo
			codigo_funcional = classificacao_com_niveis_utilizados_e_obrigatorios_em_string.delete! '.'
			codigo_funcional << codigo.rjust(2, '0')
			self.class.completar_codigo_com_zeros(codigo_funcional, self.novo_tipo?)
		else
			nil
		end
	end

	def valor_previsao_da_receita_atual
		if self.valor_previsto.to_f != self.valor_alteracao_da_previsao.to_f && self.valor_alteracao_da_previsao.to_f == 0
			self.valor_alteracao_da_previsao = self.valor_previsto.to_f
		else
			self.valor_alteracao_da_previsao.to_f
		end
	end

	def pode_ter_filho?
		persisted? && detalhamento_optativo != '0' && valor_previsto == 0 && nivel_opcional_3 == '00'
	end

	def cria_deducoes_correspondentes(*deducoes)
		deducoes.flatten.map { |deducao|
			receita_nova = self.dup
			receita_nova.codigo[0..1] = deducao.to_s
			receita_nova.tipo_de_deducao_id = self.modulo.tipos_de_deducao.find_by_codigo(deducao).try(:id)
			if receita_nova.save
				receita_nova
			else
				nil
			end
		}
	end

	def cria_receita_intra
		receita_nova = self.dup
		if categoria_economica == "001"
			receita_nova.codigo[0..2] = "007"
		elsif categoria_economica == "002"
			receita_nova.codigo[0..2] = "008"
		else
			return nil
		end
		receita_nova.tipo_de_deducao_id = Loa::TipoDeDeducao.find_by(codigo: '00').id
		receita_nova.save ? receita_nova : nil
	end

	def self.pesquisa_receita_nova_usando_receita_antiga codigo_antigo, orcamento_id
		orcamento = Orcamento.find(orcamento_id)
		if orcamento.present? && codigo_antigo
			codigo = orcamento.receitas_stn.hash_com_codigos_antigos_e_novos.find{|receita| receita["codigo_antigo"] == codigo_antigo}
			if codigo
				receita_stn = orcamento.receita_stn.find_by(codigo: codigo["codigo_novo"])
				return receita_stn.naturezas_da_receita.find_by(modulo_id: orcamento_id, modulo_type: "Orcamento", categoria_economica: "00#{receita_stn.codigo[0]}")
			end
		end
	end

	def previsao_da_receita_por_unidade_orcamentaria_e_fonte(unidade_orcamentaria_id, fonte_id)
		unidades_orcamentarias_por_natureza_da_receita.where(unidade_orcamentaria_id: unidade_orcamentaria_id).sum{|i| i.valor_total_por_fonte(fonte_id)} rescue 0
	end
	
	def previsao_da_receita_por_unidade_orcamentaria(unidade_orcamentaria_id)
		unidades_orcamentarias_por_natureza_da_receita.where(unidade_orcamentaria_id: unidade_orcamentaria_id).sum { |natureza| natureza.valor_total }
	end

	def soma_dos_valores_destinados_igual_ao_previsto
		valor_total = 0
		self.unidades_orcamentarias_por_natureza_da_receita.reject(&:marked_for_destruction?).collect.each do |unidade|
			if valor_alteracao_da_previsao.to_f > 0
				valores = unidade.orcamentos_da_receita.map(&:valor_atual)
			else
				valores = unidade.orcamentos_da_receita.map(&:valor)
			end
			valor_total += valores.sum
		end
		if valor_alteracao_da_previsao.to_f > 0
			errors.add(:base, "Os valores destinados não estão de acordo com o valor da previsão.") if valor_total != self.valor_alteracao_da_previsao
		else
			errors.add(:base, "Os valores destinados não estão de acordo com o valor da previsão.") if valor_total != self.valor_previsto
		end
	end

	def busca_receita_stn
		if self.codigo[0..2] == '009'
			self.modulo.receitas_stn.find_by(codigo: self.codigo[2..11]).id rescue nil
		elsif self.codigo[0..2] == '007'
			self.modulo.receitas_stn.find_by(codigo: "1#{self.codigo[3..9]}").id rescue nil
		else
			self.modulo.receitas_stn.find_by(codigo: self.codigo[2..9]).id rescue nil
		end
	end

	private
	def pai_deve_estar_sem_orcamento
		natureza_da_receita_pai = nivel_pai
		if natureza_da_receita_pai.present? && natureza_da_receita_pai.unidades_orcamentarias_por_natureza_da_receita.any?
			errors.add(:base, "não é possivel criar uma natureza de receita que tenha um nivel superior com valor orçado")
		end
	end

	def receita_so_pode_ser_orcada_se_tipo_for_diferente_de_zero
		if codigo.present? && codigo[9] == '0' && valor_previsto > 0
			errors.add(:codigo, "não é possivel orçar uma receita que tenha seu tipo de orçamento igual a zero")
		end
	end

	def atualiza_projecao_de_receita
		projecao_de_receita = self.modulo.projecao_de_receita if self.modulo
		if projecao_de_receita && projecao_de_receita.receitas.any?
			receita_da_projecao = projecao_de_receita.receitas.find_by(codigo: codigo)

			if receita_da_projecao.present? && valor_previsto_changed?
				receita_da_projecao.calculo_por_exercicios.find_by(exercicio: self.modulo.exercicio).update(total: valor_previsto)
				receita_da_projecao.receitas_dos_calculos_de_projecao.each { |receita_do_calculo| receita_do_calculo.atualiza_total_do_calculo_por_exercicio }
			end
		end
	end

	def soma_dos_percentuais_nao_pode_exceder_cem
		if (self.percentual_de_aplicacao_na_educacao.to_f +	self.percentual_de_aplicacao_na_saude.to_f + self.percentual_para_legislativo.to_f) > 100
			errors.add(:percentual_para_legislativo, "a soma dos percentuais não pode exceder 100%")
		end
	end

	def impede_delecao_para_receita_orcada
		if valor_previsto != 0
			raise Exception.new('não é possível remover natureza da receita orçada')
		end
	end

	def receita_padrao
		codigo_receita_padrao = self.codigo.dup
		codigo_receita_padrao[10..15] = '000000'
		self.modulo.naturezas_da_receita.find_by_codigo(codigo_receita_padrao)
	end

	def cria_naturezas_optativas_para_deducao_e_intra_correspondentes
		unless receita_padrao.nil? || receita_padrao.receita_stn.nil?
			receita_padrao.receita_stn.naturezas_da_receita.where(params_modulo).where.not(id: receita_padrao.id).each { |natureza|
				receita_nova = self.dup
				receita_nova.codigo[0..2] = natureza.codigo[0..2]
				receita_nova.tipo_de_deducao_id = natureza.tipo_de_deducao_id
				receita_nova.receita_stn_id = nil
				receita_nova.save
			}
		end
	end

	def replica_naturezas_optativas_existentes
		if receita_stn.present?
			receita_stn.naturezas_da_receita.order(:codigo).first.filhos.where(padrao: false).each { |natureza|
				receita_nova = natureza.dup
				receita_nova.codigo[0..2] = self.codigo[0..2]
				receita_nova.tipo_de_deducao_id = self.tipo_de_deducao_id
				receita_nova.save
			}
		end
	end

	def apaga_naturezas_optativas_para_deducao_e_intra
		if receita_padrao
			receita_padrao.receita_stn.naturezas_da_receita.where(params_modulo).where.not(id: receita_padrao.id).each { |natureza|
				opcionais = natureza.filhos.where(nivel_opcional_1: nivel_opcional_1, nivel_opcional_2: nivel_opcional_2, nivel_opcional_3: nivel_opcional_3)
				opcionais.destroy_all
			}
		end
	end

	def apaga_receita_da_projecao
		orcamento = self.modulo
		receita = orcamento.projecao_de_receita.receitas.find_by(codigo: codigo)
		receita.destroy if receita
	end

	def apaga_pais_sem_valor_e_filhos
		receita = self.nivel_pai
		while !receita.nil?
			if receita.pode_ser_excluida?
				receita.delete
			end
			receita = receita.nivel_pai
		end
	end

	def atualiza_configuracao_filhos
		novos_atributos = changes.merge(changes) {|chave,valores| valores[1]}.except(:updated_at, :descricao, :codigo, :analitica)
		if novos_atributos.any?
			self.filhos.each do |receita|
				raise ActiveRecord::Rollback unless receita.update(novos_atributos)
			end
		end
	end

	def cria_receita_da_projecao
		if codigo.present? && modulo.projecao_de_receita.present? && tipo_de_orcamento.present?
			if tipo_de_orcamento.codigo == 'F'
				tipo_de_orcamento_da_receita_de_projecao = 0
			else
				tipo_de_orcamento_da_receita_de_projecao = 1
			end

			params_receita_de_projecao = self.attributes.slice("codigo", "descricao", "novo_tipo",
				"sigla", "padrao", "tipo_de_receita", "tipo_de_deducao_id", "de_convenio")

			params_receita_de_projecao.merge!({projecao_de_receita_id: modulo.projecao_de_receita.try(:id), tipo_de_orcamento: tipo_de_orcamento_da_receita_de_projecao})

			unless modulo.projecao_de_receita.receitas.find_by(codigo: codigo)
				receita_projetada = modulo.projecao_de_receita.receitas.new(params_receita_de_projecao)

				if receita_projetada.save
					if receita_projetada.pode_ser_orcada?
						receita_projetada.criar_calculos_por_exercicios(:orcamento)
						receita_projetada.atualizar_calculos_por_exercicios_para_nova_receita_em_exercicios_base_e_corrente
					end
				else
					errors.add(:base, "Receita tem valor projetado")
					raise ActiveRecord::Rollback
				end
			end
		end
	end

	def lancar_ocorrencia
		if self.tipo_de_alteracao.present?
			Base::OcorrenciaDaAlteracaoDaReceita.create(
				natureza_da_receita_id: self.id,
				ocorrencia: self.tipo_de_alteracao
			).save(validate: false)
		end
	end

	def codigo_para_ic
		if self.codigo[0..2] == '009' && self.codigo[2..9] != '99900000'
			self.codigo[4..11] rescue nil
		else
			self.codigo[2..9] rescue nil
		end
	end
end
