class Contabilidade::Liquidacao < ApplicationRecord
	has_paper_trail
	include GeradorDeEventosContabeis
	include TradutorConcern
	include VistoriavelLiquidacoesConcern
	include SimConcern

	#gerador_de_eventos_contabeis codigo: 2 , atributo_data: 'data_da_liquidacao', atributo_codigo_movimentacao: 'numero'

	attribute :restos_a_pagar, :boolean, default: false

	attr_accessor :unidade_orcamentaria_id, :orcamento_do_empenho_id,:subempenho
	attr_accessor :itens_da_nota_fiscal_hidden
	attr_accessor :ncms_dos_itens_da_nota_fiscal_hidden
	attr_accessor :logado_na_contabilidade
	attr_accessor :semiautomatico
	attr_accessor :filtrando_liquidacao_sem_item_do_empenho
	attr_accessor :adicionar_todos_itens
	attr_accessor :precisa_resgatar_valores_da_mae
	attr_accessor :modulo_atual
	attr_accessor :nao_faz_duplicada_de_rp
	attr_accessor :valor_pago_simplificado
	attr_accessor :acao_atual

	attr_default :nao_faz_duplicada_de_rp, false
	attr_default :valor_pago, 0.00
	attr_default :estornada, false
	attr_default :simplificado, false
	attr_default :descrimina_itens_processo_ou_empenho, lambda { self.descriminar_itens_processo_ou_empenho? }
	attr_default :nota_fiscal_tipo, :sem_nota

	belongs_to :empenho, class_name: 'Contabilidade::Empenho', inverse_of: :liquidacoes
	belongs_to :medicao_da_obra
	belongs_to :orcamento
	belongs_to :controle_de_pagamento
	belongs_to :liquidacao_mae, class_name: 'Contabilidade::Liquidacao', foreign_key: 'liquidacao_mae_id'
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false
	belongs_to :liquidacao_sim, class_name: 'Contabilidade::Liquidacao', foreign_key: 'liquidacao_sim_id', required: false

	delegate :unidade_orcamentaria, :pessoa, :contas_unidade_por_empenho, :pessoa_conta_bancaria, :fonte_de_recursos_codigo_e_descricao, :elemento_de_despesa, :sub_elemento_de_despesa, :fonte_de_recursos, to: :empenho, :allow_nil => true
	delegate :retencoes, to: :nota_fiscal, allow_nil: true

	has_one :nota_fiscal, dependent: :destroy
	has_one :estorno_de_liquidacao, dependent: :restrict_with_exception
	has_one :contrato, through: :empenho
	has_one :linha, as: :modulo, class_name: "Tcm::Linha", dependent: :destroy

	#A pedido da Eduarda, agora não as liquidações podem ser excluidas, mesmo possuindo itens
	#has_many :itens_da_nota_fiscal, dependent: :restrict_with_exception
	has_many :itens_da_nota_fiscal, dependent: :destroy
	has_many :pagamentos, dependent: :restrict_with_exception
	has_many :documentos_da_liquidacao, class_name: 'Contabilidade::DocumentoDaLiquidacao', dependent: :destroy
	has_many :retencoes_folha, class_name: 'Contabilidade::Retencao', dependent: :destroy
	has_many :detalhamentos_por_subelementos, class_name: 'Contabilidade::DetalhamentoPorSubelemento', dependent: :destroy
	has_many :liquidacoes_do_controle_de_pagamento, dependent: :restrict_with_exception
	# has_many :metas_fisicas_da_liquidacao, dependent: :restrict_with_exception
	has_many :ocorrencias_da_liquidacao
	has_many :liquidacoes_filhas, class_name: 'Contabilidade::Liquidacao', dependent: :destroy, foreign_key: 'liquidacao_mae_id'
	has_many :tokens, class_name: 'Token', foreign_key: 'modulo_id'
	has_many :conjuntos_de_contas_do_grupo_de_retencao
	has_many :itens, through: :itens_da_nota_fiscal
	has_many :liquidacoes_dos_rps_cancelados, class_name: 'Contabilidade::LiquidacaoDoRpCancelado'

	accepts_nested_attributes_for :itens_da_nota_fiscal, allow_destroy: true
	accepts_nested_attributes_for :retencoes_folha, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :detalhamentos_por_subelementos, allow_destroy: true, reject_if: :all_blank
	accepts_nested_attributes_for :liquidacoes_filhas, allow_destroy: true, reject_if: proc { |atributo| atributo['valor'].blank? && atributo['nota_fiscal_numero'].blank? }

	validates :retencoes_folha, uniq_nested_attributes: { atributo: :conta_extra_orcamentaria_id, mensagem: "Imposto deve ser único dentro da Liquidação" }

	validates_presence_of :empenho_id, :valor
	validates_presence_of :medicao_da_obra_id, if: :obriga_medicao_da_obra?, unless: proc { self.simplificado? }
	validates_presence_of :data_de_solicitacao, if: :solicitado?, unless: proc { self.simplificado? }
	validates_presence_of :data_da_liquidacao, if: Proc.new{ (status_was == 'confirmado' && self.confirmado?) || self.simplificado? }
	validates_presence_of :mes_de_competencia, if: Proc.new{ !self.ano_de_competencia.blank? && !tem_folha_de_pagamento? }, unless: proc { self.simplificado? }
	validates_presence_of :ano_de_competencia, if: Proc.new{ !self.mes_de_competencia.blank? && !tem_folha_de_pagamento? }, unless: proc { self.simplificado? }
	validates_presence_of :data_de_emissao_da_folha, :ano_da_folha, :mes_da_folha, :tipo_da_folha, if: Proc.new{ tem_folha_de_pagamento? && logado_na_contabilidade && !empenho.encargos_sociais}, unless: proc { self.simplificado? }
	validates_presence_of :nota_fiscal_numero, if: Proc.new{ obriga_nota_fiscal? }, unless: proc { self.simplificado? }
	validates_presence_of :numero_da_fatura, if: Proc.new{ fatura? && (de_multiplas_notas_fiscais? == false || de_multiplas_notas_fiscais.nil?) }, unless: proc { self.simplificado? }
	validates_presence_of :nota_fiscal_tipo, if: Proc.new{ nota_fiscal_numero.present? }, unless: proc { self.simplificado? }

	validates_presence_of :nota_fiscal_numero, if: Proc.new { self.liquidacao_mae_id.present? }, unless: proc { self.simplificado? }

	# Retirei essa validação, pois ela verifica se os campos estão vazios, na linha 67, ele verifica se esses campos estão presentes. É uma redundância que quebra a tela.
	# validates_absence_of :data_de_emissao_da_folha, :ano_da_folha, :mes_da_folha, :tipo_da_folha, unless: :pode_ter_folha_de_pagamento?
	validates_absence_of :nota_fiscal_numero, if: Proc.new{ sem_nota? || fatura? || aluguel? || (empenho.present? && !empenho.encargos_sociais) && confirmado? && logado_na_contabilidade && sem_nota? || fatura? || aluguel? }, unless: proc { self.simplificado? }
	validates_absence_of :de_multiplas_notas_fiscais, if: Proc.new { sem_nota? || aluguel? }, unless: proc { self.simplificado? }

	validates_uniqueness_of :numero, scope: :empenho_id, case_sensitive: false

	validates_numericality_of :valor, greater_than: 0

	validates :data_da_liquidacao, data_nao_pode_estar_no_futuro: true, if: :confirmado?
	validates :data_da_liquidacao, sabado_ou_domingo_ou_feriado: { flexivel: false }, if: :confirmado?
	validates :data_da_liquidacao, date: true, if: :confirmado?
	validates :data_de_emissao_da_folha, date: { allow_blank: true }, if: :confirmado?, unless: proc { self.simplificado? }

	# validação de unicidade do item da nota fiscal. Situação: no empenho é possível adicionar itens repetidos e na liquidação não salva o item do empenho
	# e sim o item (pois pode existir empenho sem item e liquidacção com itens), nesse caso não teria como saber qual item do empenho corresponde ao item da nota fiscal caso pudesse repetir o item na liquidação tambem.
	validates :itens_da_nota_fiscal, uniq_nested_attributes: { atributo: :item_id, mensagem: "item deve ser único dentro de uma liquidação" }, unless: proc { self.simplificado? }

	#por enquanto foi pedido para não obrigar medição quando for de empenho de obra
	validate :valor_nao_deve_ser_maior_que_valor_da_medicao, if: Proc.new { self.medicao_da_obra.present? }
	validate :valor_nao_deve_ser_maior_que_saldo_do_empenho, if: Proc.new { empenho.present? && valor_changed? && liquidacao_mae_id.nil? }
	validate :data_nao_pode_ser_anterior_a_data_do_empenho, if: Proc.new { data_de_solicitacao || data_da_liquidacao }
	validate :valor_dos_itens_bate_com_valor_liquidacao
	validate :descrimina_itens_processo_ou_empenho_apenas_se_empenho_tem_itens, if: Proc.new { empenho.present?}, unless: proc { self.simplificado? }
	validate :valida_total_folha_de_pagamento,  if: :tem_folha_de_pagamento?
	validate :valor_nao_deve_ser_igual_do_valor_da_medicao, if: Proc.new { self.detalhamentos_por_subelementos.any? && !self.empenho.rgps?}
	validate :valida_data_com_exercicio, if: Proc.new { self.data_de_solicitacao_changed? || self.data_da_liquidacao_changed?}
	validate :data_da_liquidacao_superior_a_data_de_solicitacao, if: Proc.new { self.data_de_solicitacao.present? && self.data_da_liquidacao.present? }, unless: proc { self.simplificado? }
	validate :data_da_Liquidacao_superior_a_nota_fiscal, if: Proc.new { self.nota_fiscal.present? && self.nota_fiscal.data_de_emissao.present? && self.data_da_liquidacao.present? }, unless: proc { self.simplificado? }
	validate :empenho_esta_em_status_de_alteracao, if: Proc.new { self.empenho.present? }
	# comentado por hora. Caso não for utilizar mais, por favor, remover validação.
	# validate :valida_numero_da_nota_fiscal, if: Proc.new { self.nota_fiscal_numero.present? && !aluguel? && !fatura?}, unless: proc { self.simplificado? }
	validate :valida_se_ja_houve_envio_do_sim
	validate :valida_valor_das_liquidacoes_filhas, if: Proc.new { mae? }
	validate :valida_liquidacao_com_data_futura, if: Proc.new { self.status_changed? }
	validate :ano_de_competencia, if: -> { ano_de_competencia.present? && empenho&.data_do_empenho.present? && tem_folha_de_pagamento? && self.empenho.envia_detalhamento_folha_ao_sim.present?} do; errors.add(:ano_de_competencia, "deve ser igual ao ano do empenho: #{empenho.data_do_empenho.year}") if ano_de_competencia.to_i != empenho.data_do_empenho.year.to_i; end

	validate :valida_se_mes_de_competencia_da_liquidacao_esta_no_periodo_da_data_da_liquidacao, if: Proc.new { tem_folha_de_pagamento? && self.empenho.envia_detalhamento_folha_ao_sim.present? && self.mes_de_competencia.present? && self.data_da_liquidacao.present? }
	validate :valida_se_mes_da_folha_igual_mes_da_data_da_liquidacao, if: Proc.new { self.mes_da_folha.present? && self.data_da_liquidacao.present?}
	validate :valida_se_data_de_emissao_da_folha_igual_mes_da_folha, if: Proc.new { self.mes_da_folha.present? && self.data_de_emissao_da_folha.present?}

	validate :valida_data_da_liquidacao_simplificada, on: :create, if: Proc.new { self.simplificado? }
	validate :valida_valor_pago_simplificado, on: :create, if: Proc.new { self.simplificado? }

	after_commit :atribui_proximo_codigo_disponivel

	before_validation :apaga_nota_fiscal
	before_save :atualiza_numero_e_tipo_da_nota_fiscal, on: :update, if: Proc.new {self.nota_fiscal_numero_changed? || self.nota_fiscal_tipo_changed?}
	before_save :preenche_liquidacao_simplificada, on: :create, if: proc { self.simplificado? }

	after_save :gera_nota_fiscal, if: :deve_possuir_nota_fiscal?
	after_save :gera_linha_para_arquivo_do_sim , if: Proc.new {(confirmado? || enviado_para_o_financeiro? || recebido_pelo_financeiro? || autorizado?) && Configuracao.last.faz_envio_do_sim? && self.simplificado == false && self.orcamento.exercicio > Date.today.year - 1} 
	after_save :gera_pagamento_simplificado, on: :create, if: proc { self.simplificado? }

	before_save :lancar_ocorrencia
	before_validation :atribui_valores_da_liquidacao_mae, if: Proc.new { new_record? }

	after_save :gerar_nota_fiscal_fake_para_aluguel, if: proc { self.aluguel? }

	before_create :cria_liquidacao_no_restos_a_pagar, if: Proc.new { self.empenho.empenho_de_restos_a_pagar.present? }
	before_save :lanca_as_mudancas_no_restos_a_pagar_se_tiver, if: Proc.new { self.empenho.empenho_de_restos_a_pagar.present? }
	after_destroy :apaga_no_restos_a_pagar, if: Proc.new { self.empenho.empenho_de_restos_a_pagar.present? }

	after_save :deleta_o_restos_a_pagar_se_totalmente_pago_no_orcamento, if: Proc.new { self.totalmente_pago? && self.restos_a_pagar == false }

	after_destroy :gera_linha_para_arquivo_do_sim , if: Proc.new {(confirmado? || enviado_para_o_financeiro? || recebido_pelo_financeiro? || autorizado?) && Configuracao.last.faz_envio_do_sim? && self.simplificado == false && self.orcamento.exercicio > Date.today.year - 1}

	alias_method :credor, :pessoa

	TIPO_DA_FOLHA = {"title"=>"AN - Ativo Normal", "id"=>"AN"}, {"title"=>"AC - Ativo Complementar", "id"=>"AC"}, {"title"=>"AD - Ativo 13º Salário", "id"=>"AD"}, {"title"=>"IN - Inativo Normal", "id"=>"IN"}, {"title"=>"IC - Inativo Complementar", "id"=>"IC"}, {"title"=>"ID - Inativo 13º Salário", "id"=>"ID"}, {"title"=>"PN - Pensionista Normal", "id"=>"PN"}, {"title"=>"PC - Pensionista Complementar", "id"=>"PC"}, {"title"=>"PD - Pensionista 13º Salário", "id"=>"PD"}

	enum mes_da_folha: {
		janeiro: 0,
		fevereiro: 1,
		marco: 2,
		abril: 3,
		maio: 4,
		junho: 5,
		julho: 6,
		agosto: 7,
		setembro: 8,
		outubro: 9,
		novembro: 10,
		dezembro: 11
	}

	enum mes_de_competencia: {
		janeiro_competencia: 1,
		fevereiro_competencia: 2,
		marco_competencia: 3,
		abril_competencia: 4,
		maio_competencia: 5,
		junho_competencia: 6,
		julho_competencia: 7,
		agosto_competencia: 8,
		setembro_competencia: 9,
		outubro_competencia: 10,
		novembro_competencia: 11,
		dezembro_competencia: 12
	}

	enum status: {
		solicitado: 0,
		enviado_para_controladoria: 1,
		confirmado: 2,
		enviado_para_contabilidade: 3,
		recebido: 4,
		enviado_para_o_financeiro: 5,
		recebido_pelo_financeiro: 6,
		enviado_para_administrativo: 7,
		autorizado: 8,
		retornado_pela_contabilidade: 9,
		retornado_pela_controladoria: 10,
		aguardando_notas_fiscais: 11,
		enviado_ao_email: 12,
		
	}

	enum status_restos_a_pagar: {
		processado: 1,
		nao_processado: 2
	}

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

	enum nota_fiscal_tipo: {
		sem_nota: 0,
		servico: 1, # 'S'
		mercadoria: 2, # 'M'
		mercadoria_avulsa: 3, # 'A'
		mercadoria_produtor: 4, # 'P'
		mercadoria_e_servico: 5, # 'X'
		servico_avulsa: 6, # 'V'
		fatura: 7,
		aluguel: 8
	}

	enum tipo_de_reconhecimento_do_passivo: {
		reconhecido_na_liquidacao_da_despesa: 0,  #Não é mais usado agora é utilizado no Empenho
		reconhecimento_pelo_controle_de_consumo: 1,  #Não é mais usado agora é utilizado no Empenho
		reconhecido_antes_da_liquidacao_nesse_exercicio: 2,
		reconhecido_antes_da_liquidacao_exercicio_anterior: 3,
		reconhecimento_programado: 4,  #Não é mais usado agora é utilizado no Empenho
		reconhecimento_eventual: 5  #Não é mais usado agora é utilizado no Empenho
	}

	scope :confirmadas, -> { where(status: :confirmado) }
	scope :confirmadas_ate_autorizadas, -> { where(status: [:confirmado, :enviado_para_o_financeiro, :recebido_pelo_financeiro, :autorizado])}
	scope :nao_confirmadas, -> { where(status: [:solicitado, :enviado_para_controladoria, :enviado_para_contabilidade, :recebido, :retornado_pela_contabilidade, :retornado_pela_controladoria, :aguardando_notas_fiscais, :enviado_ao_email])}
	scope :de_restos_a_pagar, -> { where('contabilidade_liquidacoes.restos_a_pagar is true') }
	scope :do_orcamento, -> { where('contabilidade_liquidacoes.restos_a_pagar is false') }
	scope :recebidos_pelo_financeiro, -> { where(status: :recebido_pelo_financeiro) }
	scope :nao_estornada, -> { where(estornada: false) }
	scope :sem_controle_de_pagamento, -> {left_joins(:liquidacoes_do_controle_de_pagamento).merge( Contabilidade::LiquidacaoDoControleDePagamento.where(id: nil) )}
	scope :mae, -> { where(de_multiplas_notas_fiscais: true, liquidacao_mae_id: nil) }
	scope :filha, -> { where(de_multiplas_notas_fiscais: true).where.not(liquidacao_mae_id: nil) }
	scope :valida, -> { where('(de_multiplas_notas_fiscais = ? AND liquidacao_mae_id IS NOT NULL) OR (de_multiplas_notas_fiscais IS NULL) OR (de_multiplas_notas_fiscais = ?)', true, false) }
	scope :mae_e_regular, -> { where('(de_multiplas_notas_fiscais = ? AND liquidacao_mae_id IS NULL) OR (de_multiplas_notas_fiscais IS NULL) OR (de_multiplas_notas_fiscais = ?)', true, false) }

	def empenho_e_numero
		"#{self.empenho.numero_do_empenho}.#{self.numero}"
	end

	def empenho_e_numero_valor_retido
		"#{empenho_e_numero} | Retido: #{valor_das_retencoes.to_d.real_contabil}"
	end

	def numero_e_empenho
		"#{self.numero} - Empenho: #{self.empenho.numero_do_empenho}"
	end

	def numero_e_empenho_e_fornecedor
		"#{self.numero} - Empenho: #{self.empenho.numero_do_empenho} - Fornecedor: #{self.pessoa.nome_e_cpf_ou_cnpj} "
	end

	def status_em_tela
		if (self.status == 'confirmado' || self.status == 'autorizado')
			"Concluído"
		else
			"A Concluir"
		end
	end

	def self.proximo_numero_disponivel empenho_id
		empenho = Contabilidade::Empenho.find(empenho_id)

		numeros_utilizados = where(empenho_id: empenho_id).order(:numero).pluck(:numero).map{ |numero| numero.to_i }

		if numeros_utilizados.empty? and empenho.restos_a_pagar == true
			numeros_utilizados = Contabilidade::Liquidacao.where(empenho_id: empenho.empenho_origem.id).order(:numero).pluck(:numero).map{ |numero| numero.to_i }
		end
		
		return '001' if numeros_utilizados.empty?	
		numeros_utilizados = numeros_utilizados.to_a.sort
		numeros_disponiveis = numeros_utilizados.last + 1
		numeros_disponiveis.to_s.rjust(3, '0')
	end

	def titulo_tipo_folha_pagamento
		Contabilidade::Liquidacao::TIPO_DA_FOLHA.select{|n| n["id"] == tipo_da_folha}.first["title"] rescue nil
	end

	def atribui_proximo_codigo_disponivel
		if self.numero.nil? || self.numero.to_s.empty?
			self.numero = Contabilidade::Liquidacao.proximo_numero_disponivel empenho_id
			self.update_column(:numero, self.numero)
		end
	end

	def tem_folha_de_pagamento?
		(self.empenho.empenho_de_folha? || self.pessoa.folha_de_pagamento?) && ((self.empenho.orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..1] == '31' && self.empenho.envia_detalhamento_folha_ao_sim? ) || (self.empenho.orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..1] != '31')) && (self.empenho.orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..1] != '33') rescue false
	end

	def pode_ter_folha_de_pagamento?
		unless self.empenho.nil?
			self.empenho.empenho_de_folha?
		end
	end

	def numero_da_nota_ja_utilizado?
		if self.aluguel?
			false
		else
			self.empenho.liquidacoes.where('contabilidade_liquidacoes.nota_fiscal_numero = ? and contabilidade_liquidacoes.id != ?', self.nota_fiscal_numero, self.id).any?
		end
	end

	def enviado_ao_sim?
		self.mes_bloqueado? || (arquivo_id.present? && arquivo_id > 0 && arquivo.lote.lote_processado_ou_enviado?)
	end

	def possui_retencoes?
		(self.nota_fiscal.present? && self.retencoes.any?) || self.retencoes_folha.any?
	end

	def deve_possuir_nota_fiscal?
		if aguardando_notas_fiscais?
			liquidacao_mae_id.present? && !sem_nota? && !fatura? && !aluguel?
		else
			(confirmado? || solicitado? ) && !sem_nota? && !fatura? && !aluguel? && nota_fiscal_numero.present?
		end
	end

	def nota_fiscal_a_preencher?(portal_da_transparencia=nil)
		return false if (nota_fiscal.blank? && (self.sem_nota? || self.fatura? ) ) || self.aluguel?
		return true if nota_fiscal.blank? && (!self.sem_nota? && !self.fatura? && !self.aluguel?)
		
		atributos_a_preencher = nota_fiscal.attributes.except(
			'id', 'liquidacao_id', 'tipo_da_nota', 'numero_da_nota', 'created_at', 'updated_at'
		)
		if Configuracao.last.obriga_preenchimento_de_nf? == false || portal_da_transparencia == false && (contexto_atual.exercicio < Date.today.year && self.empenho.empenho_de_restos_a_pagar.present?)
			return false
		else
			atributos_a_preencher.values.all?(&:blank?)
		end
	end

	def liquidacao_confirmada?
		self.confirmado? || self.enviado_para_o_financeiro? || self.recebido_pelo_financeiro? || self.enviado_para_administrativo? || self.autorizado? || self.retornado_pela_contabilidade? || self.retornado_pela_controladoria?
	end

	def detalhamento_do_plano_de_contas
		empenho.try(:detalhamento_do_plano_de_contas)
	end

	def duplica_liquidacao
		liquidacao = self.dup
		liquidacao.numero = nil
		liquidacao.liquidacao_origem_id = self.id
		liquidacao.data_da_liquidacao = Date.today
		liquidacao.estornada = false
		liquidacao.status = :solicitado

		if liquidacao.save
			self.itens_da_nota_fiscal.each do |item_da_nota|
				liquidacao.itens_da_nota_fiscal.find_or_create_by!(ncm_id: item_da_nota.ncm_id, total: item_da_nota.total, item_id: item_da_nota.item_id,quantidade: item_da_nota.quantidade, valor_unitario: item_da_nota.valor_unitario)
			end

			self.retencoes_folha.each do |retencao_folha|
				liquidacao.retencoes_folha.find_or_create_by!(conta_extra_orcamentaria_id: retencao_folha.conta_extra_orcamentaria_id, valor_calculado: retencao_folha.valor_calculado.to_f,tipo_de_acao: retencao_folha.tipo_de_acao)
			end
		end

		return liquidacao
	end

	def porcentagem_do_empenho
		if self.empenho.present?
			((self.valor * 100) / self.empenho.definir_valor_do_empenho.to_f).round(2)
		else
			0.to_f
		end
	end

	def sem_saldo?
		saldo == 0
	end

	def saldo
		saldo_da_liquidacao = estornada? ? 0 : valor.to_f - valor_pago.to_f

		if self.restos_a_pagar == true
			saldo_da_liquidacao = saldo_da_liquidacao - valor_cancelado_em_rp
		end

		return saldo_da_liquidacao
	end

	def valor_cancelado_em_rp
		self.liquidacoes_dos_rps_cancelados.joins(resto_a_pagar_cancelado: :cancelamento_de_resto_a_pagar).where('contabilidade_cancelamentos_de_restos_a_pagar.status = 1').sum(&:valor_cancelado)
	end

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

	def valor_total_dos_itens
		itens_da_nota_fiscal.sum(:total)
	end

	def total_dos_itens_fecha_com_liquidacao?
		valor == valor_total_dos_itens
	end

	def processado?(orcamento)
		self.data_da_liquidacao.year < orcamento.exercicio
	end

	def nao_processado?(orcamento)
		self.data_da_liquidacao.year == orcamento.exercicio
	end

	def contrato_esta_valido?
		if self.empenho.contrato.present?
			if self.data_da_liquidacao.present?
				data_liquidacao = self.data_da_liquidacao
			else
				data_liquidacao = self.try(:data_de_solicitacao)
			end
			self.empenho.contrato.data_final_de_acordo_com_aditivos >= data_liquidacao
		end
	end

	def detalhamento_da_liquidacao_restos_a_pagar
		" #{orcamento.exercicio.to_s }| Número: #{numero.to_s } | Data: #{data_da_liquidacao.to_s } | Valor:#{valor.try(:real_contabil)} | NF- #{nota_fiscal_numero.to_s }"
	end

	def detalhamento_da_liquidacao_orcamentario
		if fatura?
			" Data: #{data_da_liquidacao.to_s } | Número: #{empenho_e_numero.to_s } | Valor:#{valor.try(:real_contabil)} | F: #{numero_da_fatura.to_s }"
		else
			" Data: #{data_da_liquidacao.to_s } | Número: #{empenho_e_numero.to_s } | Valor:#{valor.try(:real_contabil)} | NF: #{nota_fiscal_numero.to_s }"
		end
	end

	def existem_itens?
		(self.mae? == false && itens_da_nota_fiscal.any?) || (self.mae? && self.liquidacoes_filhas.map { |liquidacao| liquidacao.itens_da_nota_fiscal }.flatten.any?)
	end

	def possui_pagamentos?
		if self.mae?
			liquidacoes_filhas.map { |liquidacao| liquidacao.pagamentos }.flatten.any? || liquidacoes_filhas.map { |liquidacao| liquidacao.liquidacoes_do_controle_de_pagamento }.flatten.any?
		else
			pagamentos.any? || liquidacoes_do_controle_de_pagamento.any?
		end
	end

	def possui_pagamentos_de_restos_a_pagar?
		if self.empenho.empenho_de_restos_a_pagar.present?
			liquidacao = self.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.numero).first
			if liquidacao.present?
				liquidacao.pagamentos.any? ? true : false
			else
				return false
			end
		else
			return false
		end
	end

	def totalmente_pago?
		if self.mae?
			self.valor.to_f == liquidacoes_filhas.reduce(0) { |total, liquidacao| liquidacao.pagamentos.sum(:valor).to_f }
		else
			self.valor.to_f == self.pagamentos.sum(:valor).to_f
		end
	end

	def existe_pagamento_sem_estorno?
		pagamentos.ativos.any?
	end

	def pode_excluir?
		ano_comparacao = self.solicitado? ? self.data_de_solicitacao&.year.to_i : self.data_da_liquidacao&.year.to_i

		!self.estornada? && !enviado_ao_sim? && !possui_pagamentos? && !liquidacoes_do_controle_de_pagamento.any? && !possui_pagamentos_de_restos_a_pagar? && !self.mes_bloqueado? && (!self.restos_a_pagar? || self.restos_a_pagar? && ano_comparacao > self.empenho.data_do_empenho&.year.to_i)
	end

	def saldo_do_empenho_referente_a_data
		data_a_utilizar = self.data_da_liquidacao || self.data_de_solicitacao
		valor_das_liquidacoes = Contabilidade::Liquidacao.where(empenho_id: self.empenho_id, liquidacao_mae_id: nil).where('((data_da_liquidacao is not null AND data_da_liquidacao < ?) 
			OR (data_da_liquidacao is null AND data_de_solicitacao < ?)) OR (data_da_liquidacao is not null AND data_da_liquidacao = ? AND CAST(numero as INT) <= ?) 
			OR (data_da_liquidacao is null AND data_de_solicitacao = ? AND CAST(numero as INT) <= ?) ', 
			data_a_utilizar, data_a_utilizar, data_a_utilizar, self.numero.to_i, data_a_utilizar, self.numero.to_i).sum(:valor)
		valor_das_anulacoes = Contabilidade::AnulacaoDoEmpenho.where(empenho_id: self.empenho_id).where('data_da_anulacao <= ?', data_a_utilizar).sum(:valor)
		saldo = self.empenho.valor_total_do_empenho.to_d - valor_das_anulacoes.to_d - valor_das_liquidacoes.to_d + self.empenho.valor_liquidado_estornado.to_d
		return saldo.to_f
	end

	def saldo_do_empenho_referente_a_data_na_solicitacao
		data_a_utilizar = self.data_de_solicitacao
		valor_das_liquidacoes = Contabilidade::Liquidacao.where(empenho_id: self.empenho_id, liquidacao_mae_id: nil).where('(data_da_liquidacao is not null AND data_de_solicitacao <= ?) 
    OR (data_da_liquidacao is null AND data_de_solicitacao <= ? AND CAST(numero AS INT) <= ?)', data_a_utilizar, data_a_utilizar, self.numero.to_i).sum(:valor)
		valor_das_anulacoes = Contabilidade::AnulacaoDoEmpenho.where(empenho_id: self.empenho_id).where('data_da_anulacao <= ?', data_a_utilizar).sum(:valor)
		saldo = self.empenho.valor_total_do_empenho.to_d - valor_das_anulacoes.to_d - valor_das_liquidacoes.to_d + self.empenho.valor_liquidado_estornado.to_d
		return saldo.to_f
	end

	def de_uma_medicao?
		empenho.try(:obra_possui_medicoes?)
	end

	def de_uma_obra?
		empenho.try(:de_uma_obra?)
	end

	def obriga_medicao_da_obra?
		de_uma_obra? && (self.logado_na_contabilidade.present? || Configuracao.last.obriga_medicao_da_obra_na_liquidacao_adm?)
	end

	def valor_das_retencoes
		if retencoes_folha.any?
			self.retencoes_folha.sum(:valor_calculado).to_f
		elsif nota_fiscal.present? && retencoes.any?
			self.retencoes.sum(:valor_calculado).to_f
		else
			return 0
		end
	end

	def valor_liquido
		valor.to_f - valor_das_retencoes.to_f
	end

	def valor_total_pago
		pagamentos.sum { |pagamento| pagamento.valor_total_pago }
	end

	def prepagamentos
		pagamentos.prepagamentos
	end

	def valor_prepago
		prepagamentos.prepagamentos.ativos.sum(:valor)
	end

	def porcentagem_do_valor_prepago
		((valor_prepago * 100) / valor).round(2).to_f
	end

	def pagamentos_sem_prepagos
		pagamentos.confirmados
	end

	def valor_sem_prepago
		pagamentos.confirmados.ativos.sum(:valor)
	end

	def valor_a_ser_pago
		valor.to_f - valor_sem_prepago.to_f
	end

	def porcentagem_do_valor_sem_prepago
		((valor_total_pago * 100) / valor).round(2).to_f
	end

	def adiciona_itens(itens)
		quantidade = 0
		itens.each do |item|
			if self.itens_da_nota_fiscal.build(item_id: item.to_i)
				quantidade += 1
			end
		end
		return quantidade
	end

	def valor_total_dos_itens_da_nota_fiscal
		itens_da_nota_fiscal.inject(0) { |total, item_da_nota| total + item_da_nota.total.to_f }.round(2)
	end

	def gera_nota_fiscal
		return false if nota_fiscal.present?

		nova_nota_fiscal = Contabilidade::NotaFiscal.new(
			liquidacao: self, tipo_da_nota: nota_fiscal_tipo, numero_da_nota: nota_fiscal_numero
		)

		nova_nota_fiscal.save(validate: false)
	end

	def remover_retencoes
		if nota_fiscal.present?
			retencoes.destroy_all
			nota_fiscal.update_attributes(orcamentario_iss: false, extraorcamentario_iss: false,orcamentario_inss_pj: false,extraorcamentario_inss_pj: false,orcamentario_irpj: false,extraorcamentario_irpj: false,extraorcamentario_inss_pf: false,orcamentario_irpf: false,extraorcamentario_irpf: false)
		else
			retencoes_folha.destroy_all
		end
	end

	def retencao_iss_vinculada_a_receita?
		receita = orcamento.contas_extra_orcamentarias.find_by(retencao_para: 1).try(:natureza_da_receita)

		if receita.present?
			receita.unidades_orcamentarias_por_natureza_da_receita.where(unidade_orcamentaria_id: unidade_orcamentaria_do_exercicio_atual.id).any?
		end
	end

	def retencao_irpj_vinculada_a_receita?
		receita = orcamento.contas_extra_orcamentarias.find_by(retencao_para: 5).try(:natureza_da_receita)
		if receita.present?
			receita.unidades_orcamentarias_por_natureza_da_receita.where(unidade_orcamentaria_id: unidade_orcamentaria_do_exercicio_atual.id).any?
		end
	end

	def retencao_irpf_vinculada_a_receita?
		receita = orcamento.contas_extra_orcamentarias.find_by(retencao_para: 4).try(:natureza_da_receita)
		if receita.present?
			receita.unidades_orcamentarias_por_natureza_da_receita.where(unidade_orcamentaria_id: unidade_orcamentaria_do_exercicio_atual.id).any?
		end
	end

	def unidade_orcamentaria_do_exercicio_atual(orcamento_atual = nil)
		# MARCAR PARA TESTAR
		orcamento_atual = self.orcamento unless orcamento_atual.present? # para liquidacoes de restos a pagar lançada em orcamento anteriores, chamar a função passando o orçamento atual
		if empenho.unidade_orcamentaria.orgao.orcamento.id == orcamento_atual.id
			return empenho.unidade_orcamentaria
		else
			cod_orgao = empenho.unidade_orcamentaria.orgao.codigo
			cod_unidade = empenho.unidade_orcamentaria.codigo
			unidade_orcamentaria_do_exercicio = Loa::UnidadeOrcamentaria.joins(:orgao).find_by(codigo: cod_unidade, loa_orgaos: {codigo: cod_orgao, orcamento_id: orcamento_atual.id})
				if unidade_orcamentaria_do_exercicio.blank?
					unidade_orcamentaria_do_exercicio = orcamento_atual.unidades_orcamentarias.joins(:unidades_orcamentaria_vinculada)
						.find_by('loa_unidades_orcamentaria_vinculada.unidade_orcamentaria_vinculada_id = ?', empenho.unidade_orcamentaria.id)
				end
			return unidade_orcamentaria_do_exercicio
		end
	end

	def retencao_de_iss
		if nota_fiscal.present? && retencoes.any?
			retencoes.find_by(imposto_type: 'Contabilidade::ImpostoSobreServico')
		end
	end

	def valida_numero_da_nota_fiscal
		data_referencia = self.try(:data_da_liquidacao).present? ? self.data_da_liquidacao : self.data_de_solicitacao
		errors.add(:nota_fiscal_numero, 'Número da nota fiscal já foi utilizado pelo Fornecedor.') if self.empenho.numero_nf_sendo_utilizado(self.nota_fiscal_numero, data_referencia, self.nota_fiscal_tipo, self.id)
	end

	def valida_data_com_exercicio
		orcamento_atual = self.restos_a_pagar? ? contexto_atual : self.orcamento
		if self.data_da_liquidacao.present? 
			errors.add(:data_da_liquidacao, 'A data da liquidação, não está dentro do exercício logado.') if self.data_da_liquidacao.try(:year) != orcamento_atual.try(:exercicio).to_i
		elsif self.data_de_solicitacao.present? && (self.data_de_solicitacao.try(:year) > self.orcamento.exercicio || self.data_de_solicitacao.try(:year) < self.orcamento.exercicio - 1)
			mensagem = self.data_de_solicitacao.try(:year) > self.orcamento.exercicio ? "superior ao exercício de #{self.orcamento.exercicio}." : "inferior ao exercício de  #{self.orcamento.exercicio - 1}."
			errors.add(:data_de_solicitacao, "A data de solicitação, não pode ser #{mensagem}")
		end
	end

	def mostrar_edit_delete_retencoes?
		!self.autorizado? && !self.enviado_para_controladoria? && !self.enviado_para_o_financeiro? && !self.recebido_pelo_financeiro? && !self.pagamentos.any?
	end

	def descriminar_itens_processo_ou_empenho?
		self.empenho.try(:pessoa).try(:folha_de_pagamento?) ? false : true
	end

	def eh_resto_a_pagar?
		self.restos_a_pagar? || self.pagamentos.map { |p| p.id if p.resto_a_pagar? }.compact.size > 0
	end

	def data_da_liquidacao_superior_a_data_de_solicitacao
		if self.data_de_solicitacao > self.data_da_liquidacao
			errors.add(:data_da_liquidacao, "A data deve ser superior a #{self.data_de_solicitacao} da solicitação da liquidação")
		end
	end

	def data_da_Liquidacao_superior_a_nota_fiscal
		unless aluguel?
			if self.nota_fiscal.data_de_emissao > self.data_da_liquidacao
				errors.add(:data_da_liquidacao, "A data deve ser superior a #{self.nota_fiscal.data_de_emissao} já cadastrada na nota fiscal")
			end
		end
	end

	def valor_liquidado_de_ordem_de_fornecimento_nao_paga
		status_ordem_de_compra = [Licitacao::OrdemDeCompra.status[:recebido_parcialmente_pelo_almoxarifado], Licitacao::OrdemDeCompra.status[:recebido_pelo_almoxarifado]]

		itens_do_recebimento = GestaoDeEstoque::ItemDoRecebimentoDeMaterial.joins(
			recebimento_de_material: [ordem_de_compra: :empenho ]).where(
				licitacao_ordens_de_compra: { status: status_ordem_de_compra },
				contabilidade_empenhos: { id: self.empenho_id },
				gestao_de_estoque_itens_do_recebimento_de_materiais: { item_id: self.itens_da_nota_fiscal.map { |i| i.item_id } }
			).group_by{ |i| i.item_id }

		itens_da_liquidacao_agrupado = self.itens_da_nota_fiscal.group_by{ |i| i.item_id }
		itens_das_outras_liquidacoes_agrupados = Contabilidade::ItemDaNotaFiscal.joins(liquidacao: [:empenho]).where(
			"contabilidade_empenhos.id = #{self.empenho_id} AND contabilidade_liquidacoes.id != #{self.id}"
		).group_by{ |i| i.item_id }

		valor_liquidado_da_ordem_nao_paga = 0
		itens_do_recebimento.each_key do |key|
			if itens_das_outras_liquidacoes_agrupados[key].present? && itens_da_liquidacao_agrupado[key].present?
				if itens_do_recebimento[key].sum(&:total) > itens_das_outras_liquidacoes_agrupados[key].sum(&:valor_total).to_f
					saldo_remanscente = itens_do_recebimento[key].sum(&:total) - itens_das_outras_liquidacoes_agrupados[key].sum(&:valor_total).to_f
					if saldo_remanscente >= itens_da_liquidacao_agrupado[key].sum(&:valor_total)
						saldo_final = itens_da_liquidacao_agrupado[key].sum(&:valor_total)
					else
						saldo_final = saldo_remanscente
					end
					valor_liquidado_da_ordem_nao_paga += saldo_final
				end

			elsif itens_da_liquidacao_agrupado[key].present?
				if itens_da_liquidacao_agrupado[key].sum(&:valor_total) > itens_do_recebimento[key].sum(&:total)
					saldo_final = itens_do_recebimento[key].sum(&:total)
				else
					saldo_final = itens_da_liquidacao_agrupado[key].sum(&:valor_total)
				end
				valor_liquidado_da_ordem_nao_paga += saldo_final
			end
		end

		return valor_liquidado_da_ordem_nao_paga
	end

	def competencia_formatada
		return "#{self.localizar(:mes_de_competencia)}/#{self.ano_de_competencia}" rescue ""
	end

	def valida_se_mes_de_competencia_da_liquidacao_esta_no_periodo_da_data_da_liquidacao
		compentencia_da_liquidacao = Contabilidade::Liquidacao.meses_de_competencia[self.mes_de_competencia]
		mes_da_liquidacao = self.data_da_liquidacao.month
		
		if compentencia_da_liquidacao != mes_da_liquidacao
			errors.add(:mes_de_competencia, "Mês de competencia não deve ser diferente do mês da data da liquidação")
		end
	end

	def valida_se_mes_da_folha_igual_mes_da_data_da_liquidacao
		mes_da_liquidacao = self.data_da_liquidacao.month
		mes_da_folha = Contabilidade::Liquidacao.meses_da_folha[self.mes_da_folha] +1

		if mes_da_liquidacao != mes_da_folha
			errors.add(:mes_da_folha, "Mês da folha não pode ser diferente do mês da data da liquidação")
		end
	end

	def valida_se_data_de_emissao_da_folha_igual_mes_da_folha
		mes_da_emissao_da_folha = self.data_de_emissao_da_folha.month
		mes_da_folha = Contabilidade::Liquidacao.meses_da_folha[self.mes_da_folha] +1

		if mes_da_emissao_da_folha != mes_da_folha
			errors.add(:data_de_emissao_da_folha, "Mês dessa data não pode ser diferente do mês da folha")
		end
	end

	def empenho_esta_em_status_de_alteracao
		if self.empenho.aguardando_alteracao_do_orcamento?
			errors.add(:empenho, "Empenho está em alteração orçamentária")
		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 mes_bloqueado? && acao_atual == 'confirmar_liquidacao'
			errors.add(:sim, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
		end
	end

	def existe_lote_do_sim?
		if data_sim.present? && self.confirmado_ou_acima? == false
			orcamento_id = Orcamento.find_by_exercicio(data_sim.year).id
			lote_sim = Tcm::Lote.find_by(
				orcamento_id: orcamento_id,
				tipo: [Tcm::Lote.tipos[:todos], Tcm::Lote.tipos[:contabilidade]],
				mes_de_referencia: data_sim.month,
				situacao: [Tcm::Lote.situacoes[:gerado], Tcm::Lote.situacoes[:finalizado]]
			)

			return lote_sim.present?
		end

		return false
	end

	def mae?
		de_multiplas_notas_fiscais? && liquidacao_mae_id.nil?
	end

	def filha?
		de_multiplas_notas_fiscais? && liquidacao_mae_id.present?
	end

	def atribui_valores_da_liquidacao_mae
		if liquidacao_mae.present?
			liquidacao_mae.attributes.except('id', 'numero', 'nota_fiscal_numero', 'created_at', 'updated_at', 'valor', 'numero_da_fatura', 'liquidacao_mae_id').each do |atributo|
				self.send("#{atributo[0]}=", atributo[1])
			end
		end
	end

	def valor_liquidacoes_filhas
		@valor_liquidacoes_filhas ||= liquidacoes_filhas.reject(&:marked_for_destruction?).sum { |liquidacao| liquidacao.valor.to_d }
	end

	def todas_liquidacoes_filhas_possuem_notas_validas?
		liquidacoes_filhas.any? && liquidacoes_filhas.all?{ |liquidacao_filha| liquidacao_filha.nota_fiscal_a_preencher? == false && liquidacao_filha.nota_fiscal_tipo.present? }
	end

	def todas_as_liquidacoes_filhas_possuem_itens?
		liquidacoes_filhas.any? && liquidacoes_filhas.all?{ |liquidacao_filha| liquidacao_filha.itens_da_nota_fiscal.any? }
	end

	def liquidacoes_filhas_validas?
		todas_as_liquidacoes_filhas_possuem_itens? && todas_liquidacoes_filhas_possuem_notas_validas?
	end

	def quantidade_de_liquidacoes_filhas_diferente_de_um?
		self.liquidacoes_filhas.size == 1 ? false : true
	end

	def proxima_liquidacao_filha
		liquidacao_mae.liquidacoes_filhas.where('id > ?', id).try(:first)
	end

	def valida_valor_das_liquidacoes_filhas
		errors.add(:valor, "Soma das liquidações deve ser menor ou igual à #{valor.to_f.real_contabil}" ) if valor_liquidacoes_filhas > valor.to_d
	end

	def fornecedor_de_a_cordo_com_o_tipo_da_nota?
		if (servico_avulsa? || servico?) && pessoa.inscricao_municipal.present? == false && Configuracao.last.obriga_inscricao_do_fornecedor_na_liquidacao?
			return false
		elsif (mercadoria? || mercadoria_avulsa? || mercadoria_produtor? || mercadoria_e_servico? ) && pessoa.inscricao_estadual.present? == false && Configuracao.last.obriga_inscricao_do_fornecedor_na_liquidacao?
			return false
		else
			return true
		end
	end
	
	def valida_liquidacao_com_data_futura
		data_atual = Date.today
		if self.data_da_liquidacao.present? 
			errors.add(:data_da_solicitacao, 'A data selecionada não pode ser maior que a data atual') if (self.data_da_liquidacao.present? && self.data_da_liquidacao > data_atual)
		end
	end

	def pagamentos_das_liquidacoes_filhas
		@pagamentos_das_liquidacoes_filhas ||= Contabilidade::Pagamento.where(liquidacao_id: liquidacoes_filhas.ids) rescue Array.new
	end

	def valor_pago_das_liquidacoes_filhas
		pagamentos_das_liquidacoes_filhas.sum(:valor)
	end

	#criei esses metodos, pois os outros semelhantes pegavam valor de campos que não temos certeza estarem sendo preenchidos
	def valor_pago_da_liquidacao
		self.pagamentos.where.not(status: :estornado).sum(&:valor).to_d
	end

	def saldo_da_liquidacao
		saldo_da_liquidacao = estornada? ? 0 : valor.to_d - valor_pago_da_liquidacao.to_d

		if self.restos_a_pagar == true
			saldo_da_liquidacao = saldo_da_liquidacao - valor_cancelado_em_rp
		end

		return saldo_da_liquidacao
	end

	def porcetagem_pago_das_liquidacoes_filhas
		((valor_pago_das_liquidacoes_filhas * 100) / valor).round(2).to_f
	end

	def obriga_nota_fiscal?
		nao_eh_multiplcas_notas = de_multiplas_notas_fiscais? == false || de_multiplas_notas_fiscais.nil?
		nota_fiscal_tipo_exige_nota = (!sem_nota? && !fatura? && !aluguel?) && !nota_fiscal_tipo.nil?
		empenho_nao_eh_encargo_social = empenho.present? && !empenho.encargos_sociais

		nao_eh_multiplcas_notas && ( ( nota_fiscal_tipo_exige_nota && nota_fiscal_tipo.present? ) || 
		empenho_nao_eh_encargo_social && confirmado? && logado_na_contabilidade && nota_fiscal_tipo_exige_nota )
	end

	def inconsistencia_no_sim?
		existe_lote_do_sim? && confirmado? == false
	end

	def data_sim
		data_da_liquidacao
	end

	def nota_de_mercadoria?
		nota_fiscal.mercadoria? || nota_fiscal.mercadoria_avulsa? || nota_fiscal.mercadoria_produtor? || nota_fiscal.mercadoria_e_servico?
	end

	def permite_retencao?
		nota_fiscal.de_servico? || nota_de_mercadoria? || aluguel?
	end

	def confirmado_ou_acima?
		confirmado? || recebido_pelo_financeiro? || autorizado? || enviado_para_o_financeiro? || recebido?
	end

	def gera_linhas_dos_dependentes
		if Configuracao.last.faz_envio_do_sim?
			nota_fiscal.gera_linha_para_arquivo_do_sim if nota_fiscal.present?
			
			itens_da_nota_fiscal.each do |item|
				item.gera_linha_para_arquivo_do_sim
			end
		end
	end

	def apaga_linhas_do_sim_ao_voltar_etapa
		if Configuracao.last.faz_envio_do_sim?
			linha.delete if linha.present?
			nota_fiscal.linha.delete if nota_fiscal.present? &&nota_fiscal.linha.present?
			
			itens_da_nota_fiscal.each do |item|
				item.linha.delete if item.linha.present?
			end
		end
	end
	
	def elemento_de_indenizacao_e_empenho_rgps?
		self&.empenho&.rgps? && self&.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo[0..5] == '319094'
	end

	def preenche_detalhamento_por_vpd?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""
		sub_elemento_codigo = self.empenho.sub_elemento_de_despesa.codigo rescue ""
		
		if (elemento_codigo == "31901100" && sub_elemento_codigo == "51") || (elemento_codigo == "31900400" && ["10", "51"].include?(sub_elemento_codigo)) || (elemento_codigo == "31909400" && self.empenho.rpps?) || (elemento_codigo == "31900100") || (elemento_codigo == "33900800" && ["01", "05", "53", "56"].include?(sub_elemento_codigo))
			return true
		else
			return false
		end
	end

	def pode_estornar_com_base_nas_anulacoes_dos_pag
		return (self.pagamentos.any? && self.pagamentos.map{|pag| pag.estorno_de_pagamento.valor}.sum != self.valor) ?  false :  true
	end

	def faz_controle_cronologico?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""
		sub_elemento_codigo = self.empenho.sub_elemento_de_despesa.codigo rescue ""

		['33903000', '33903100', '33903200', '44903000', '44905200', '33903700', '44905100'].include?(elemento_codigo) ||
		(elemento_codigo == '33909200' && sub_elemento_codigo == '30') ||
		(elemento_codigo == '33904006' && sub_elemento_codigo == '06') ||
		(elemento_codigo == '33903600' && ['14', '15'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33903900' && ['10', '12', '13', '83'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33903600' && !['02', '07', '14', '15', '45', '46'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33903900' && !['10', '12', '13', '43', '44', '59', '83', '96'].include?(sub_elemento_codigo))
	end

	def controle_cronologico_de_fornecimento_de_bens?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""
		sub_elemento_codigo = self.empenho.sub_elemento_de_despesa.codigo rescue ""

		['33903000', '33903100', '33903200', '44903000', '44905200'].include?(elemento_codigo) ||
		(elemento_codigo == '33909200' && sub_elemento_codigo == '30')
	end

	def controle_cronologico_locacao?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""
		sub_elemento_codigo = self.empenho.sub_elemento_de_despesa.codigo rescue ""

		['33903700'].include?(elemento_codigo) ||
		(elemento_codigo == '33903600' && ['14', '15'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33903900' && ['10', '12', '13', '83'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33904006' && sub_elemento_codigo == '06')
	end

	def controle_cronologico_prestacao_de_servicos?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""
		sub_elemento_codigo = self.empenho.sub_elemento_de_despesa.codigo rescue ""

		(elemento_codigo == '33903600' && !['02', '07', '14', '15', '45', '46'].include?(sub_elemento_codigo)) ||
		(elemento_codigo == '33903900' && !['10', '12', '13', '43', '44', '59', '83', '96'].include?(sub_elemento_codigo))
	end

	def controle_cronologico_obras?
		elemento_codigo = self.empenho.orcamento_da_despesa&.elemento_de_despesa_por_subacao&.elemento_de_despesa&.codigo rescue ""

		['44905100'].include?(elemento_codigo)
	end

	def eh_processada?
		self.empenho.empenho_origem.liquidacoes.where(numero: self.numero).present?
	end

	private

	def apaga_no_restos_a_pagar
		liquidacao = self.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.numero).first
		if liquidacao.present?
			if liquidacao.pagamentos.any?
				raise ActiveRecord::Rollback
			else
				liquidacao.destroy
			end
		end
	end

	def cria_liquidacao_no_restos_a_pagar
		unless nao_faz_duplicada_de_rp == true
			liquidacao_de_rp = self.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.numero).first rescue nil

			unless liquidacao_de_rp.present?
				liquidacao_de_rp = self.dup

				liquidacao_de_rp.restos_a_pagar = true
				liquidacao_de_rp.empenho_id = self.empenho.empenho_de_restos_a_pagar.id

				self.itens_da_nota_fiscal.each do |item|
					liquidacao_de_rp.itens_da_nota_fiscal.build(
						quantidade: item.quantidade,
						valor_unitario: item.valor_unitario, 
						item_id: item.item_id,
						total: item.total, 
						ncm_id: item.ncm_id
					)
				end

				liquidacao_de_rp.nao_faz_duplicada_de_rp = true
				liquidacao_de_rp.save(validate: false)
			end
		end
	end

	def lanca_as_mudancas_no_restos_a_pagar_se_tiver
		campos_alterados = self.changed

		liquidacao_de_rp = self.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.numero).first

		if liquidacao_de_rp.present?
			if campos_alterados.size > 0

				campos_alterados.each do |campo|
					unless campo == 'empenho_id'
						liquidacao_de_rp.update_column(campo, self["#{campo}".to_sym])
					end
				end

				liquidacao_de_rp.save(validate: false)
			end

			self.itens_da_nota_fiscal.each do |item_da_nota_fiscal|
				campos_alterados_item_da_nota_fiscal = item_da_nota_fiscal.changed

				if item_da_nota_fiscal.marked_for_destruction?
					item_da_nota_fiscal_rp = liquidacao_de_rp.itens_da_nota_fiscal.where(item_id: item_id_was).first

					item_da_nota_fiscal_rp.destroy

				elsif item_da_nota_fiscal.new_record?
					liquidacao_de_rp.itens_da_nota_fiscal.create(quantidade: item_da_nota_fiscal.quantidade, valor_unitario: item_da_nota_fiscal.valor_unitario, 
						item_id: item_da_nota_fiscal.item_id, total: item_da_nota_fiscal.total, ncm_id: item_da_nota_fiscal.ncm_id)

				else
					if campos_alterados_item_da_nota_fiscal.size > 0
						item_da_nota_fiscal_rp = liquidacao_de_rp.itens_da_nota_fiscal.where(item_id: item_da_nota_fiscal.item_id_was).first rescue nil

						if item_da_nota_fiscal_rp.present?
							campos_alterados_item_da_nota_fiscal.each do |campo|
								unless campo == 'liquidacao_id'
									item_da_nota_fiscal_rp.write_attribute(campo, self["#{campo}".to_sym])
								end
							end

							item_da_nota_fiscal_rp.save(validate: false)
						end
					end
				end
			end
		end
	end
	
	def valor_nao_deve_ser_maior_que_valor_da_medicao
		if new_record?
			if valor.to_f > medicao_da_obra.saldo_a_liquidar.to_f
				errors.add(:valor, 'o valor da liquidação não deve ser maior que o saldo da medição')
			end
		else
			valor_saldo_medicao = valor_was.to_f + medicao_da_obra.saldo_a_liquidar.to_f
			if valor.to_f > valor_saldo_medicao.to_f
				errors.add(:valor, 'o valor da liquidação não deve ser maior que o saldo da medição')
			end
		end
	end

	def valor_nao_deve_ser_igual_do_valor_da_medicao
		soma_dos_valores_detalhamento = self.detalhamentos_por_subelementos.inject(0){|total, detalhamento| total + detalhamento.valor.to_f }

		if valor.to_d != soma_dos_valores_detalhamento.to_d
			errors.add(:valor, 'o valor da liquidação deve ser igual ao valor dos detalhamentos')
		end
	end

	def valor_nao_deve_ser_maior_que_saldo_do_empenho
		valor_total_liquidado_persistido = valor_was
		valor_da_liquidacao = self.valor.to_f - valor_total_liquidado_persistido.to_f
		
		if self.restos_a_pagar?
			errors.add(:valor, "não pode ser maior que o saldo do empenho") if valor_da_liquidacao.to_f > self.empenho.saldo_atual_nao_processado_a_liquidar.to_f.round(2)
		else
			errors.add(:valor, "não pode ser maior que o saldo do empenho") if valor_da_liquidacao.to_f > self.empenho.saldo.to_f
		end
	end

	def data_nao_pode_ser_anterior_a_data_do_empenho
		if empenho.present?
			if empenho.confirmado? && empenho.data_do_empenho
				if data_da_liquidacao.present?
					errors.add(:data_da_liquidacao, "não pode ser anterior a data do empenho #{empenho.data_do_empenho}") if data_da_liquidacao < empenho.data_do_empenho
				else
					errors.add(:data_de_solicitacao, "não pode ser anterior a data do empenho #{empenho.data_do_empenho}") if data_de_solicitacao < empenho.data_do_empenho
				end
			elsif data_de_solicitacao.present?
				errors.add(:data_de_solicitacao, "não pode ser anterior a data de solicitação do empenho #{empenho.data_de_solicitacao}") if data_de_solicitacao < empenho.data_de_solicitacao
			end
		end
	end

	def deleta_o_restos_a_pagar_se_totalmente_pago_no_orcamento
		if self.empenho.empenho_de_restos_a_pagar.present?
			soma_pagamentos = self.pagamentos.where(orcamento_id: self.orcamento_id).sum(:valor)

			if self.valor.to_f == soma_pagamentos.to_f
				liquidacao_de_rp = self.empenho.empenho_de_restos_a_pagar.liquidacoes.where(numero: self.numero).first rescue nil

				if liquidacao_de_rp.present?
					liquidacao_de_rp.destroy
				end
			end
		end
	end

	def valor_dos_itens_bate_com_valor_liquidacao
		return unless itens_da_nota_fiscal.any? && (self.valor.to_f != valor_total_dos_itens_da_nota_fiscal)
		errors.add(:base, 'A soma dos itens da liquidação deve bater com o valor total fornecido.')
	end

	def valida_total_folha_de_pagamento
		valor_retencoes = retencoes_folha.inject(0) { |total, retencao| total + retencao.valor_calculado.to_f }.round(2)
		if valor_retencoes > valor.to_f
			errors.add(:valor_calculado, 'A soma dos valores das retenções deve ser menor igual ao da liquidação')
		end
	end

	def descrimina_itens_processo_ou_empenho_apenas_se_empenho_tem_itens
		if !empenho.possui_itens? && !empenho.derivado_de_licitacao? && descrimina_itens_processo_ou_empenho == true
			errors.add(:descrimina_itens_processo_ou_empenho, 'O empenho não possui itens ou ligação com processo.')
		end
	end

	def apaga_nota_fiscal
		if (self.sem_nota? || self.fatura?)
			self.nota_fiscal_numero = nil 
			nota_fiscal.destroy if nota_fiscal.present?
		end
	end

	def atualiza_numero_e_tipo_da_nota_fiscal
		if self.nota_fiscal.present? && self.nota_fiscal_numero != '' && !self.nota_fiscal.destroyed? && self.nota_fiscal_numero_changed?
			self.nota_fiscal.update_column(:numero_da_nota, self.nota_fiscal_numero)
		end

		if self.nota_fiscal_tipo_changed? && self.nota_fiscal.present?
			unless self.sem_nota? || self.fatura?
				self.nota_fiscal.update_column(:tipo_da_nota, self.nota_fiscal_tipo)
			end
		end
	end

	def preenche_liquidacao_simplificada
		self.nota_fiscal_tipo = :mercadoria_e_servico if self.nota_fiscal_numero.present?
		self.historico = 'Ajuste de Saldo de Restos a pagar.'
		self.status = :confirmado
		self.data_de_solicitacao = self.data_da_liquidacao
		self.mes_de_competencia = self.data_da_liquidacao.month
		self.ano_de_competencia = self.data_da_liquidacao.year
		self.tipo_de_lancamento = :original
		self.restos_a_pagar = false
		self.orcamento_id = Orcamento.find_by_exercicio(self.data_da_liquidacao.year)
		self.descrimina_itens_processo_ou_empenho = false
		self.nao_faz_duplicada_de_rp = true if (self.valor.to_d - self.valor_pago_simplificado.to_d) == 0 
	end
	
	def gera_pagamento_simplificado
		if self.valor_pago_simplificado.to_d.positive?
			pagamento = Contabilidade::Pagamento.new(
				orcamento: self.empenho.orcamento,
				liquidacao_id: self.id,
				#numero: pagamento['numero_nota_pagamento'],
				estornado: false,
				data: self.data_da_liquidacao,
				valor: self.valor_pago_simplificado,
				prepagamento: false
			).save(validate: false)
		end
	end

	def valida_data_da_liquidacao_simplificada

	end

	def valida_valor_pago_simplificado
		if self.valor_pago_simplificado.to_d > 0
			errors.add(:valor_pago_simplificado, 'deve ser menor ou igual ao valor da liquidação') if self.valor_pago_simplificado.to_d > self.valor.to_d
		end
	end

	def lancar_ocorrencia
		if self.status_changed? && self.status != "solicitado"
			Contabilidade::OcorrenciaDaLiquidacao.create(
				liquidacao_id: self.id,
				ocorrencia: self.status
			).save(validate: false)
		end
	end

	def gerar_nota_fiscal_fake_para_aluguel
		unless self.nota_fiscal.present?
			orcamentario_iss = false
			extraorcamentario_iss = false
			orcamentario_irpf = false
			extraorcamentario_irpf = false
			extraorcamentario_inss_pf = false
			orcamentario_inss_pj = false
			orcamentario_irpj = false
			extraorcamentario_inss_pj = false
			extraorcamentario_irpj = false
			if self.empenho.pessoa.pessoa_fisica?
				orcamentario_iss = true
				orcamentario_irpf = true
				extraorcamentario_iss = true
				extraorcamentario_irpf = true
				extraorcamentario_inss_pf = true
			elsif self.empenho.pessoa.pessoa_juridica?
				orcamentario_inss_pj = true
				orcamentario_irpj = true
				extraorcamentario_inss_pj = true
				extraorcamentario_irpj = true
			end

			nova_nota = Contabilidade::NotaFiscal.new(
				liquidacao_id: self.id,
				tipo_da_nota: :aluguel,
				numero_da_nota: '999999',
				serie: 'U',
				tipo_de_emissao: :eletronica_no_padrao_nacional,
				data_de_emissao: Date.today,
				tipo_de_desconto: :sem_desconto,
				data_limite_de_expedicao: Date.today,
				orcamentario_iss: orcamentario_iss,
				orcamentario_inss_pj: orcamentario_inss_pj,
				orcamentario_irpj: orcamentario_irpj,
				orcamentario_irpf: orcamentario_irpf,
				extraorcamentario_inss_pj: extraorcamentario_inss_pj,
				extraorcamentario_iss: extraorcamentario_iss,
				extraorcamentario_irpj: extraorcamentario_irpj,
				extraorcamentario_inss_pf: extraorcamentario_inss_pf,
				extraorcamentario_irpf: extraorcamentario_irpf
			)
			nova_nota.save(validate: false)
		end
	end
end
