class Contabilidade::TalaoDeReceita < ApplicationRecord
	has_paper_trail
	include TradutorConcern
	include AASM
	include IncrementadorDeCodigoConcern
	include GeradorDeEventosContabeis
	include Pcasp::ValidaMovimentacoesConcern

	#gerador_de_eventos_contabeis codigo: 4, atributo_valor: 'valor', atributo_data: 'data_do_talao', atributo_codigo_movimentacao: 'numero_do_talao'

	attr_accessor :lancamento_automatico_retencao
	attr_accessor :item_do_lote_da_receita_id
	attr_accessor :manter_form

	attr_defaults documento_de_credito: '0', tipo_de_documento: :outro_tipo_de_documento_de_credito
	attr_default :talao_de_desconto, false
	attr_default :lancamento_automatico_retencao, false

	belongs_to :orcamento, required: true
	belongs_to :pessoa, class_name: 'Base::Pessoa', required: true
	belongs_to :conta_bancaria_por_unidade_orcamentaria, class_name: 'Base::ContaBancariaPorUnidadeOrcamentaria'
	belongs_to :natureza_da_receita, class_name: 'Base::NaturezaDaReceita'
	belongs_to :operacao_de_credito, class_name: 'Obra::OperacaoDeCredito'
	belongs_to :transferencia, class_name: 'Obra::Transferencia'
	belongs_to :unidade_orcamentaria, class_name: 'Loa::UnidadeOrcamentaria'
	belongs_to :conta_extra_orcamentaria
	belongs_to :pagamento, class_name: 'Contabilidade::Pagamento'
	belongs_to :retencao, class_name: 'Contabilidade::Retencao'
	belongs_to :pagamento_da_retencao, class_name: 'Contabilidade::PagamentoDaRetencao'
	belongs_to :sub_conta_pcasp, class_name: 'Contabilidade::SubContaPcasp'
	belongs_to :fonte_de_recursos, class_name: 'Base::FonteDeRecursos'
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false

	delegate :receita_stn, to: :natureza_da_receita, allow_nil: true

	has_many :anulacoes_dos_taloes_de_receita, dependent: :destroy
	has_many :orcamentos_da_receita, through: :natureza_da_receita, class_name: "Loa::OrcamentoDaReceita"
	has_many :complementos_por_fonte_do_talao_de_receita, class_name: "Contabilidade::ComplementoPorFonteDoTalaoDeReceita", dependent: :destroy
	has_many :lancamentos_do_orcamento_da_receita, as: :modulo, class_name: "Contabilidade::LancamentoDoOrcamentoDaReceita", dependent: :destroy
	has_many :orcamentos_dos_lancamentos_da_receita, through: :lancamentos_do_orcamento_da_receita, source: :orcamento_da_receita, class_name: "Loa::OrcamentoDaReceita"
	has_many :lancamentos_extraorcamentario_receita, as: :modulo

	has_one :conta_bancaria, through: :conta_bancaria_por_unidade_orcamentaria, class_name: 'Base::ContaBancaria'
	has_one :item_do_lote_da_receita, class_name: 'Contabilidade::ItemDoLoteDeReceita'

	accepts_nested_attributes_for :complementos_por_fonte_do_talao_de_receita, reject_if: :all_blank, allow_destroy: true

	validates_associated :lancamentos_do_orcamento_da_receita, if: Proc.new {self.orcamentario?}
	validates_presence_of :data_do_talao, :valor, :historico, :pessoa_id, :documento_de_credito
	validates_presence_of :tipo_de_documento, :origem_do_talao, :unidade_orcamentaria_id

	validates_presence_of :conta_bancaria_por_unidade_orcamentaria_id, unless: Proc.new {self.talao_de_desconto?}
	validates_numericality_of :conta_bancaria_por_unidade_orcamentaria_id, if: Proc.new { self.conta_bancaria_por_unidade_orcamentaria_id.present? && self.talao_de_desconto? }, greater_than: 0
	validates_presence_of :natureza_da_receita_id, if: Proc.new { self.orcamentario? }
	validates_presence_of :conta_extra_orcamentaria_id, if: Proc.new { self.extra_orcamentario? }
	validates_presence_of :transferencia_id, if: Proc.new { self.natureza_da_receita.present? && self.natureza_da_receita.pedir_cadastro_de_convenio? }
	validates_presence_of :operacao_de_credito_id, if: Proc.new { self.natureza_da_receita.present? && self.natureza_da_receita.pedir_cadastro_de_operacao_de_credito? }
	validates_presence_of :sub_conta_pcasp_id, if: Proc.new { self.usa_sub_conta_pcasp? }
	validates_presence_of :fonte_de_recursos_id, if: Proc.new{ self.extra_orcamentario? }, unless: proc { self.lancamento_automatico_retencao == true || self.talao_de_desconto? }

	validates_uniqueness_of :numero_do_talao, scope: :orcamento_id, case_sensitive: false, allow_blank: true

	validates_length_of :documento_de_credito, maximum: 20
	validates_numericality_of :valor, other_than: 0, allow_nil: true

	validate :verifica_saldo_conta_extra_ativo, if: Proc.new {self.conta_extra_orcamentaria.present? && self.conta_extra_orcamentaria.try(:ativo?)}
	validate :verifica_saldo_conta_extra_passivo, on: :update,if: Proc.new {self.conta_extra_orcamentaria.present? && self.conta_extra_orcamentaria.try(:passivo?)}
	validate :verifica_saldo_conta_bancaria, on: :update, if: proc { self.valor_changed? && self.conta_bancaria_por_unidade_orcamentaria.present? }
	validate :verifica_saldo_conta_bancaria_na_criacao_de_deducao, if: proc { self.conta_bancaria_por_unidade_orcamentaria.present? && self.natureza_da_receita.try(:deducao?)}
	validate :valida_mudanca_de_tipo_de_conta_extra, on: :update, if: Proc.new {self.conta_extra_orcamentaria.present? && self.conta_extra_orcamentaria_id_changed? }
	validate :valida_alteracao_da_conta_bancaria, on: :update, if: Proc.new {self.conta_bancaria_por_unidade_orcamentaria.present? && self.conta_bancaria_por_unidade_orcamentaria_id_changed? }
	validate :validar_subconta, if: Proc.new {self.natureza_da_receita_id.present? && self.natureza_da_receita.sub_conta_pcasp_id.present?}
	validate :validar_modalidade_da_operacao_de_credito, if: Proc.new { self.operacao_de_credito.present? }

	before_validation :apaga_complementos_ao_editar_talao, if: Proc.new { self.houve_mudanca_de_unidade_ou_natureza? }
	after_commit :atribui_codigo_disponivel

	before_save :vincula_fontes_na_conta_bancaria, if: :orcamentario?
	before_save :verificar_se_he_receita_de_deducao
	after_save :lancar_na_conta_bancaria
	after_save :lancar_movimento_orcamentario, if: :orcamentario?
	after_save :lancar_movimento_conta_extraorcamentaria, if: :extra_orcamentario?
	after_save :cria_movimentacoes_por_fonte_de_recursos, if: Proc.new{ self.class.name == 'Contabilidade::TalaoDeReceita' && movimentacoes_do_plano_de_contas.any? }
	after_create :atualiza_item_do_lote_da_receita, if: proc { self.item_do_lote_da_receita_id.present? }

	before_destroy :valida_saldo_da_conta_extra_antes_de_excluir, if: Proc.new {self.conta_extra_orcamentaria.present? }
	before_destroy :valida_saldo_da_conta_bancaria_antes_de_excluir, if: Proc.new { self.conta_bancaria_por_unidade_orcamentaria.present? && !self.natureza_da_receita.try(:deducao?)}
	before_save :preenche_dados_do_pagamento, if: Proc.new { self.retencao_id.present? }

	after_destroy :apagar_lancamento_na_conta
	after_destroy :apagar_movimento_orcamentario, if: :orcamentario?
	after_destroy :apagar_movimento_orcamentario_extra, if: :extra_orcamentario?

	validates :data_do_talao, data_nao_pode_estar_no_futuro: true
	validates :data_do_talao, mesmo_exercicio_do_pai: true, unless: proc { self.lancamento_automatico_retencao == true }
	validates :data_do_talao, sabado_ou_domingo_ou_feriado: true
	validates :data_do_talao, date: true
	validates :lancamentos_do_orcamento_da_receita, uniq_nested_attributes: { atributo: :id, mensagem: "lançamento deve ser único dentro de um talão" }
	validate :conta_extra_cancelada, if: :extra_orcamentario?
	validate :soma_dos_valores_por_fonte_nao_pode_diferente_do_valor_do_talao, unless: proc { self.extra_orcamentario? }
	validate :data_do_talao_superior_a_conta_bancaria, if: Proc.new { |talao_de_receita| talao_de_receita.retencao_id.nil? }
	validate :valida_se_ja_houve_envio_do_sim
	validate :valida_pessoa_do_talao, if: :extra_orcamentario?
	validate :valida_retencao, if: :extra_orcamentario?

	enum tipo_do_talao: {
		original: 0,
		estorno: 1
	}

	enum origem_do_talao:{
		orcamentario: 0,
		extra_orcamentario: 1
	}

	enum tipo_de_documento: {
		cheque: 1,
		outro_tipo_de_documento_de_credito: 2,
		caixa: 9
	}

	def soma_dos_valores_por_fonte_nao_pode_diferente_do_valor_do_talao
		unless lancamento_automatico_retencao == true
			soma_dos_valores_das_fonte = complementos_por_fonte_do_talao_de_receita.inject(0){|total, complemento_por_fonte| total + complemento_por_fonte.valor.to_d }
			errors.add(:valor, "A soma dos valores por fonte não pode ser diferente do valor do talão ") if self.valor.to_d != soma_dos_valores_das_fonte.to_d
		end
	end

	def numero_do_talao
		self[:numero_do_talao].to_i.digitos(8) if self[:numero_do_talao].present?
	end
	def existe_anulacao_total?
		anulacoes = self.anulacoes_dos_taloes_de_receita
		anulacoes.where(tipo_de_anulacao: Contabilidade::AnulacaoDoTalaoDeReceita.tipos_de_anulacao["total"]).any?
	end

	def numero_da_anulacao
		num_da_anulacao = ""
		if existe_anulacao_total?
			anulacao = self.anulacoes_dos_taloes_de_receita.find_by(tipo_de_anulacao: Contabilidade::AnulacaoDoTalaoDeReceita.tipos_de_anulacao["total"])
			num_da_anulacao = anulacao.numero_da_anulacao
		end
		return num_da_anulacao
	end

	def verifica_saldo_conta_extra_passivo
		if self.unidade_orcamentaria_id.present? && self.data_do_talao.present?
			saldo_atual = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, Date.today) + (self.valor.to_d - self.valor_was.to_d)
			saldo_do_dia_do_lancamento = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, self.data_do_talao) + (self.valor.to_d - self.valor_was.to_d)

			errors.add(:valor, "Saldo insuficiente na conta extra, saldo disponível na data selecionada #{saldo_do_dia_do_lancamento.to_d.real_contabil}") if saldo_do_dia_do_lancamento < 0
			errors.add(:valor, "Saldo insuficiente na conta extra, saldo atual da conta: #{saldo_atual.to_d.real_contabil}") if saldo_atual < 0			
		end
	end

	def verifica_saldo_conta_extra_ativo
		if self.unidade_orcamentaria_id.present? && self.data_do_talao.present?
			saldo_final = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, Date.today) - (self.valor.to_d - self.valor_was.to_d)
			saldo_atual = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, Date.today) - self.valor_was.to_d
			saldo_final_do_dia_do_lancamento = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, self.data_do_talao) - (self.valor.to_d - self.valor_was.to_d)
			saldo_atual_do_dia_do_lancamento = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, self.data_do_talao) - self.valor_was.to_d

			errors.add(:valor, "Saldo insuficiente na conta extra, saldo disponível na data selecionada #{saldo_atual_do_dia_do_lancamento.to_d.abs.real_contabil}") if saldo_final_do_dia_do_lancamento < 0
			errors.add(:valor, "Saldo insuficiente na conta extra, saldo atual da conta: #{saldo_atual.to_d.abs.real_contabil}") if saldo_final < 0
		end
	end

	def valida_mudanca_de_tipo_de_conta_extra
		conta_extra_anterior = Contabilidade::ContaExtraOrcamentaria.find(self.conta_extra_orcamentaria_id_was)
		conta_extra_atual = Contabilidade::ContaExtraOrcamentaria.find(self.conta_extra_orcamentaria_id)

		errors.add(:conta_extra_orcamentaria_id, "não pode alterar entre os tipos ativo e passivo") if conta_extra_anterior.present? && conta_extra_atual.present? && conta_extra_anterior.classe_pcasp != conta_extra_atual.classe_pcasp
	end

	def valida_alteracao_da_conta_bancaria
		errors.add(:conta_bancaria_por_unidade_orcamentaria_id, "não pode ser alterada") unless self.vem_do_intermodulos?
	end

	def validar_subconta
		errors.add(:sub_conta_pcasp_id, "A Subconta PCASP deve ser a mesma informada na Previsão da Receita") if self.sub_conta_pcasp_id != self.natureza_da_receita.sub_conta_pcasp_id
	end

	def validar_modalidade_da_operacao_de_credito
		natureza_atual = self.natureza_da_receita.codigo

		case self.operacao_de_credito.conta.nome
		when "DÍVIDA MOBILIÁRIA"
			if !(natureza_atual[0..5] == "002111" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2111") && !(natureza_atual[0..5] == "902111")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.1.00.0.1.00.00.00, 009.0.2.1.11.0.0.01.00.00 ou 902.1.1.1.00.0.1.00.00.00")
			end
		when "OUTROS TÍTULOS - EMPRÉSTIMOS INTERNOS"
			if !(natureza_atual[0..5] == "002111" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2111") && !(natureza_atual[0..5] == "902111")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.1.00.0.1.00.00.00, 009.0.2.1.11.0.0.01.00.00 ou 902.1.1.1.00.0.1.00.00.00")
			end
		when "CONTRATOS DE EMPRÉSTIMOS INTERNOS"
			if !(natureza_atual[0..5] == "002112" && natureza_atual[9] == "1") && !(natureza_atual[0..5] == "002113" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2112") && !(natureza_atual[0..5] == "902112") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2113") && !(natureza_atual[0..5] == "902113")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.2.00.0.1.00.00.00, 002.1.1.3.00.0.1.00.00.00, 009.0.2.1.12.0.0.01.00.00, 902.1.1.2.00.0.1.00.00.00, 009.0.2.1.13.0.0.01.00.00 ou 902.1.1.3.00.0.1.00.00.00")
			end
		when "ANTECIPAÇÃO DA RECEITA ORÇAMENTÁRIA"
			if !(natureza_atual[0..5] == "002112" && natureza_atual[9] == "1") && !(natureza_atual[0..5] == "002113" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2112") && !(natureza_atual[0..5] == "902112") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2113") && !(natureza_atual[0..5] == "902113")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.2.00.0.1.00.00.00, 002.1.1.3.00.0.1.00.00.00, 009.0.2.1.12.0.0.01.00.00, 902.1.1.2.00.0.1.00.00.00, 009.0.2.1.13.0.0.01.00.00 ou 902.1.1.3.00.0.1.00.00.00")
			end
		when "OUTROS CONTRATOS - EMPRÉSTIMOS INTERNOS"
			if !(natureza_atual[0..5] == "002112" && natureza_atual[9] == "1") && !(natureza_atual[0..5] == "002113" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2112") && !(natureza_atual[0..5] == "902112") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2113") && !(natureza_atual[0..5] == "902113")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.2.00.0.1.00.00.00, 002.1.1.3.00.0.1.00.00.00, 009.0.2.1.12.0.0.01.00.00, 902.1.1.2.00.0.1.00.00.00, 009.0.2.1.13.0.0.01.00.00 ou 902.1.1.3.00.0.1.00.00.00")
			end
		when "OUTROS EMPRÉSTIMOS A CURTO PRAZO - INTERNO"
			if !(natureza_atual[0..7] == "00211999" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2119") && !(natureza_atual[0..5] == "902119")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.1.9.99.0.1.00.00.00, 009.0.2.1.19.9.9.01.00.00 ou 902.1.1.9.99.0.1.00.00.00")
			end
		when "EMPRÉSTIMOS EXTERNOS - EM TÍTULOS"
			if !(natureza_atual[0..5] == "002121" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2121") && !(natureza_atual[0..5] == "902121")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.2.1.00.0.1.00.00.00, 009.0.2.1.21.0.0.01.00.00 ou 902.1.2.1.00.0.1.00.00.00")
			end
		when "EMPRÉSTIMOS EXTERNOS - EM CONTRATOS"
			if !(natureza_atual[0..5] == "002122" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2122") && !(natureza_atual[0..5] == "902122")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.2.2.00.0.1.00.00.00, 009.0.2.1.22.0.0.01.00.00.00 ou 902.1.2.2.00.0.1.00.00.00")
			end
		when "OUTROS EMPRÉSTIMOS A CURTO PRAZO - EXTERNO"
			if !(natureza_atual[0..5] == "002129" && natureza_atual[9] == "1") && !(natureza_atual[0..2] == "009" && natureza_atual[4..7] == "2129") && !(natureza_atual[0..5] == "902129")
				errors.add(:natureza_da_receita_id, "Para essa operação de crédito a receita deve ser 002.1.2.9.00.0.1.00.00.00, 009.0.2.1.29.0.0.01.00.00 ou 902.1.2.9.00.0.1.00.00.00")
			end
		end
	end

	def valida_pessoa_do_talao
		errors.add(:pessoa_id, "não possue cpf ou cnpj cadastrado") if self.pessoa.present? && self.pessoa.cpf&.empty? && self.pessoa.cnpj&.empty?
	end

	def verifica_saldo_conta_bancaria
		saldo_inicial = self.conta_bancaria_por_unidade_orcamentaria.saldo_por_data(self.data_do_talao)

		if self.natureza_da_receita.try(:deducao?)
			saldo_pos = saldo_inicial - (self.valor.to_d - self.valor_was.to_d.abs)
		else
			saldo_pos = saldo_inicial + (self.valor.to_d - self.valor_was.to_d)
		end

		if saldo_pos < 0
			errors.add(:valor, "Saldo será de #{saldo_pos.real_contabil}, sendo insuficiente na data selecionada")
		else
			conta_bancaria_por_unidade_orcamentaria.soma_das_movimentacoes_futuras_agrupadas_por_dia(self.data_do_talao).each do |movimentacao|
				movimentado_no_dia = movimentacao['valor'].to_d
				saldo_pos = saldo_pos + movimentado_no_dia

				errors.add(:valor, "Saldo será de #{saldo_pos.real_contabil}, sendo insuficiente na data #{I18n.l(Date.parse(movimentacao['data_da_movimentacao']))}") if saldo_pos < 0
			end
		end
	end

	def verifica_saldo_conta_bancaria_na_criacao_de_deducao
		saldo_atual = conta_bancaria_por_unidade_orcamentaria.saldo_atual - (self.valor.to_d - self.valor_was.to_d.abs)
		saldo_do_dia_do_lancamento = conta_bancaria_por_unidade_orcamentaria.saldo_por_data(self.data_do_talao) - (self.valor.to_d - self.valor_was.to_d.abs)

		errors.add(:valor, "Saldo insuficiente, saldo disponível na data selecionada #{saldo_do_dia_do_lancamento.to_d.real_contabil}") if saldo_do_dia_do_lancamento < 0
		errors.add(:valor, "Saldo insuficiente, saldo atual da conta: #{saldo_atual.to_d.real_contabil}") if saldo_atual < 0
	end

	def valida_saldo_da_conta_extra_antes_de_excluir
		if self.conta_extra_orcamentaria.try(:passivo?)
			saldo_atual = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, Date.today) - self.valor.to_d
			saldo_do_dia_do_lancamento = self.conta_extra_orcamentaria.saldo_consolidade_por_data_e_unidade(self.unidade_orcamentaria_id, self.data_do_talao) - self.valor.to_d

			raise "O saldo atual da conta extra não poderá ficar negativo." if saldo_do_dia_do_lancamento < 0
			raise "O saldo da conta extra no dia do lançamento não poderá ficar negativo" if saldo_atual < 0
		end
	end

	def valida_saldo_da_conta_bancaria_antes_de_excluir
		saldo_atual = conta_bancaria_por_unidade_orcamentaria.saldo_atual - self.valor.to_d
		saldo_do_dia_do_lancamento = conta_bancaria_por_unidade_orcamentaria.saldo_por_data(self.data_do_talao) - self.valor.to_d

		raise "O saldo atual da conta bancária não poderá ficar negativo." if saldo_do_dia_do_lancamento < 0
		raise "O saldo da conta bancária no dia do lançamento não poderá ficar negativo" if saldo_atual < 0
	end

	def saldo
		(valor.to_d - valor_anulado.to_d).to_d
	end

	def conta_extra_cancelada
		if self.conta_extra_orcamentaria.try(:saldo).to_f == 0 && self.conta_extra_orcamentaria.present? && self.conta_extra_orcamentaria.anulacoes_da_conta_extra.where(orcamento_id: self.orcamento_id).sum(:valor).to_f > 0
			errors.add(:conta_extra_orcamentaria_id, "A conta está com o saldo cancelado nesse exercicio")
		end
	end

	def saldo_em_porcentagem
		((saldo * 100) / valor.to_f).round(2)
	end

	def porcentagem_anulada
		((self.valor_anulado.to_f * 100) / valor.to_f).round(2)
	end

	def enviado_ao_sim?
		self.mes_bloqueado? || (arquivo_id.present? && arquivo_id > 0 && arquivo.lote.lote_processado_ou_enviado?) || (complementos_por_fonte_do_talao_de_receita.present? && complementos_por_fonte_do_talao_de_receita.joins(:arquivo).where('arquivo_id is not null').select {|i| i.arquivo.lote.lote_processado_ou_enviado? }.compact.any?)
	end

	def anulado?
		self.saldo.to_d == 0
	end

	def parcialmente_anulado?
		valor_anulado.to_d > 0 && anulado? == false ? true : false
	end

	def unidade_gestora
		unidade_orcamentaria.unidade_gestora.codigo_e_nome
	end

	def orgao
		unidade_orcamentaria.orgao.codigo_com_zeros
	end

	def unidade_gestora_codigo
		unidade_orcamentaria.unidade_gestora.codigo
	end

	def atribui_codigo_disponivel
		# se numero vazio ou se a data é diferente da data do talão
		if self.numero_do_talao.nil? || self.numero_do_talao.to_s.empty? || self.data_do_talao.to_s.gsub("/", "")[0..3] != self.numero_do_talao.to_s[0..3]
			gerar_codigo(data_do_talao, :numero_do_talao, :data_do_talao, :orcamento_id, self.orcamento_id)
			self.update_column(:numero_do_talao, self.numero_do_talao)
		end
	end

	def dados_da_movimentacao_bancaria
		historico_da_movimentacao_do_talao = self.orcamentario? ? "Receita orçamentaria #{self.numero_do_talao} - Contribuinte: #{self.pessoa.try(:nome)} - Historico: #{self.historico}" : "Receita extraorçamentaria #{self.numero_do_talao} - #{self.retencao.descricao_imposto if self.try(:retencao).try(:descricao_imposto).present?} - Contribuinte: #{self.pessoa.try(:nome)} - Historico: #{self.historico}" 
		{
			conta_bancaria_por_unidade_orcamentaria_id: conta_bancaria_por_unidade_orcamentaria.id,
			modulo: self,
			data_da_movimentacao: data_do_talao,
			historico: historico_da_movimentacao_do_talao
		}
	end

	def vincula_fontes_na_conta_bancaria
		return false if conta_bancaria_por_unidade_orcamentaria.blank? || orcamentos_da_receita.empty?

		fontes_da_conta = conta_bancaria_por_unidade_orcamentaria.conta_bancaria.fontes_de_recursos_da_conta_bancaria

		orcamentos_da_receita.map(&:fonte_de_recursos).each do |fonte|
			fontes_da_conta.create!(fonte_de_recurso: fonte) unless fontes_da_conta.pluck(:fonte_de_recurso_id).include?(fonte.id)
		end
	end

	def usa_sub_conta_pcasp?
		usa_sub_conta = false

		if self.natureza_da_receita.present?
			usa_sub_conta = true if natureza_da_receita.try(:codigo).to_s == '0012150111000000' || natureza_da_receita.try(:codigo).to_s == '0072150211000000' || natureza_da_receita.try(:codigo).to_s == '0072155111000000' || (!self.natureza_da_receita.try(:deducao?) && self.natureza_da_receita.try(:detalhamento_optativo).to_s == "3" || self.natureza_da_receita.try(:deducao?) && self.natureza_da_receita.try(:nivel_opcional_1).last.to_s == "3")
		end

		return usa_sub_conta
	end

	def deducao?
		self.natureza_da_receita.try(:deducao?)
	end

	def verificar_se_he_receita_de_deducao
		if self.valor.present? && self.valor > 0
			self.valor = self.valor * -1 if self.natureza_da_receita.try(:deducao?)
		end
	end

	def lancar_na_conta_bancaria
		return false if conta_bancaria_por_unidade_orcamentaria.blank? || valor.blank?

		self.apagar_lancamento_na_conta
		movimentacao = Contabilidade::MovimentacaoDaContaBancaria.create!(dados_da_movimentacao_bancaria.merge!(valor: self.valor))
	end

	def apagar_lancamento_na_conta
		movimentacoes_da_conta = Contabilidade::MovimentacaoDaContaBancaria.where(modulo: self).all
		movimentacoes_da_conta.destroy_all
	end

	def lancar_movimento_orcamentario
		ActiveRecord::Base.transaction do
			if self.valor.to_f != 0
				if lancamentos_do_orcamento_da_receita.any?
					lancamentos_do_orcamento_da_receita.each do |lancamento|
						lancamento.update_column(:data_do_lancamento, self.data_do_talao) if self.data_do_talao != lancamento.data_do_lancamento
						complemento_por_fonte = complementos_por_fonte_do_talao_de_receita.find_by(talao_de_receita_id: lancamento.modulo_id)
						apagar_movimento_orcamentario if (complemento_por_fonte.present? && lancamento.try(:valor) != complemento_por_fonte.valor) || (lancamento.orcamento_da_receita_id != complemento_por_fonte.orcamento_da_receita_id)
					end
				end
				if !lancamentos_do_orcamento_da_receita.any?
					cria_lancamentos_do_orcamento
				end
			end
		end
	end

	def lancar_movimento_conta_extraorcamentaria
		ActiveRecord::Base.transaction do
			if self.valor.to_f != 0
				if lancamentos_extraorcamentario_receita.any?
					lancamentos_extraorcamentario_receita.each do |lancamento|
						lancamento.update_column(:conta_extra_orcamentaria_id, self.conta_extra_orcamentaria_id) if lancamento.conta_extra_orcamentaria_id != self.conta_extra_orcamentaria_id
						lancamento.update_column(:data_do_lancamento, self.data_do_talao) if self.data_do_talao != lancamento.data_do_lancamento
						apagar_movimento_orcamentario_extra unless self.enviado_ao_sim?
					end
				end
				
				if !lancamentos_extraorcamentario_receita.any?
					cria_lancamentos_da_conta_extraorcamentaria
				end
			end
		end
	end


	def cria_lancamentos_da_conta_extraorcamentaria
			lancamentos_extraorcamentario_receita.try(:destroy_all)
			movimentacao = Contabilidade::LancamentoExtraorcamentarioReceita.new(
				conta_extra_orcamentaria_id: conta_extra_orcamentaria_id,
				data_do_lancamento: self.data_do_talao,
				valor: self.valor.to_f,
				modulo: self
			)
			movimentacao.save
	end

	def cria_lancamentos_do_orcamento
		orcamentos_da_receita.joins(:unidade_orcamentaria_por_natureza_da_receita).where(loa_unidades_orcamentarias_por_natureza_da_receita: { unidade_orcamentaria_id: unidade_orcamentaria.try(:id) }).each do |orcamento_da_receita|
			complemento_da_fonte = complementos_por_fonte_do_talao_de_receita.find_by(orcamento_da_receita_id: orcamento_da_receita.try(:id))
			if complemento_da_fonte.present?
				valor_receita = complemento_da_fonte.valor.to_f
			else
				valor_receita = self.valor.to_f
			end

			if valor_receita.to_f != 0 && orcamento_da_receita.valor.to_f != valor_receita.to_f
				lancamentos_do_orcamento_da_receita.try(:destroy_all)
				movimentacao = Contabilidade::LancamentoDoOrcamentoDaReceita.new(
					orcamento_da_receita: orcamento_da_receita,
					data_do_lancamento: self.data_do_talao,
					valor: valor_receita,
					modulo: self
				)
				valor_receita = 0
				
				if movimentacao.valid?
					movimentacao.save
				else
					raise Exception.new(movimentacao.errors.full_messages.join(','))
				end
			end
		end
	end

	def apagar_movimento_orcamentario
		lancamentos_do_orcamento_da_receita.try(:destroy_all)
	end

	def apagar_movimento_orcamentario_extra
		lancamentos_extraorcamentario_receita.try(:destroy_all)
	end

	def conta_bancaria_deve_pertencer_a_receita_e_ao_convenio
		#todo - Implementar essa validação p/ quando o convênio estiver selecionado.
	end

	def atualiza_item_do_lote_da_receita
		item_do_lote_da_receita = Contabilidade::ItemDoLoteDeReceita.find(self.item_do_lote_da_receita_id)
		if item_do_lote_da_receita.present?
			item_do_lote_da_receita.update_columns(talao_de_receita_id: self.id, status: :lancado) 
			if item_do_lote_da_receita.lote_de_receita.reload.itens_do_lote_de_receita.pluck(:status).uniq == ["lancado"]
				item_do_lote_da_receita.lote_de_receita.update_column(:status, :aprovado)
			end
		end
	end


	def data_do_talao_superior_a_conta_bancaria
		if ( self.data_do_talao.present? && self.conta_bancaria_por_unidade_orcamentaria.present? && self.conta_bancaria_por_unidade_orcamentaria.conta_bancaria.data_de_abertura.present?) && self.data_do_talao < self.conta_bancaria_por_unidade_orcamentaria.conta_bancaria.data_de_abertura
			errors.add(:data_do_talao, "Deve ser Superior a Data de Abertura da Conta")
		end
	end

	def valida_se_ja_houve_envio_do_sim
		if existe_lote_do_sim?
			errors.add(:sim, 'O SIM do mês já foi enviado')
		elsif self.mes_bloqueado?
			errors.add(:sim, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
		end
	end

	def valida_retencao
		if retencao_id.present?
			errors.add(:retencao_id, 'já possui lançamento de talão de receita') if retencao.taloes_de_receita.any?
			errors.add(:valor, 'deve ser igual ao valor da retenção selecionada') if valor.to_d != retencao.valor_calculado.to_d
			errors.add(:conta_extra_orcamentaria_id, 'deve ser igual a retenção selecionada') if self.conta_extra_orcamentaria_id != retencao.conta_extra_orcamentaria_id
		end
	end

	def existe_lote_do_sim?
		ultima_data = data_do_talao

		if ultima_data.present?
			orcamento_id = Orcamento.find_by_exercicio(ultima_data.year)
			lote_sim = Tcm::Lote.find_by(
				orcamento_id: orcamento_id,
				tipo: [Tcm::Lote.tipos[:todos], Tcm::Lote.tipos[:contabilidade]],
				mes_de_referencia: ultima_data.month,
				situacao: [Tcm::Lote.situacoes[:gerado], Tcm::Lote.situacoes[:finalizado]]
			)

			return lote_sim.present?
		end

		return false
	end

	def movimentacoes_do_plano_de_contas_das_anulacoes
		Contabilidade::MovimentacaoDoPlanoDeContas.where(gerador_id: anulacoes_dos_taloes_de_receita.ids, gerador_type: 'Contabilidade::AnulacaoDoTalaoDeReceita')
	end

	def verifica_se_valor_talao_igual_complemento_por_fonte
		soma_dos_valores_das_fonte = complementos_por_fonte_do_talao_de_receita.inject(0){|total, complemento_por_fonte| total + complemento_por_fonte.valor }
		
		if soma_dos_valores_das_fonte == self.valor
			return true
		else
			return false
		end
	end

	def preenche_dados_do_pagamento
		self.pagamento_id = self.retencao&.pagamento_id
		self.talao_de_desconto = true
	end

	def apaga_complementos_ao_editar_talao
		Contabilidade::ComplementoPorFonteDoTalaoDeReceita.where(talao_de_receita_id: self.id).destroy_all
	end

	def houve_mudanca_de_unidade_ou_natureza?
		return true if self.natureza_da_receita_id_changed? || self.unidade_orcamentaria_id_changed? 
	end

	def vem_do_intermodulos?
		self.item_do_lote_da_receita.present?
	end

	def modalidade_para_ativacao_de_evento_contabeis
		if self.operacao_de_credito.present?
			case self.operacao_de_credito.conta.nome
			when "DÍVIDA MOBILIÁRIA"
				return "divida_mobiliaria"
			when "OUTROS TÍTULOS - EMPRÉSTIMOS INTERNOS"
				return "outros_titulos_emprestimo_internos"
			when "CONTRATOS DE EMPRÉSTIMOS INTERNOS"
				return "contratos_de_emprestimo_internos"
			when "ANTECIPAÇÃO DA RECEITA ORÇAMENTÁRIA"
				return "antecipacao_da_receita_orcamentaria"
			when "OUTROS CONTRATOS - EMPRÉSTIMOS INTERNOS"
				return "outros_contratos_emprestimos_internos"
			when "OUTROS EMPRÉSTIMOS A CURTO PRAZO - INTERNO"
				return "outros_emprestimos_a_curto_prazo_interno"
			when "EMPRÉSTIMOS EXTERNOS - EM TÍTULOS"
				return "emprestimos_externos_em_titulos"
			when "EMPRÉSTIMOS EXTERNOS - EM CONTRATOS"
				return "emprestimos_externos_em_contratos"
			when "OUTROS EMPRÉSTIMOS A CURTO PRAZO - EXTERNO"
				return "outros_emprestimos_a_curto_prazo_externo"
			end
		end
	end
end
