class Contabilidade::Pagamento < ApplicationRecord
	include IncrementadorDeCodigoConcern
	include GeradorDeEventosContabeis
	include VistoriavelPagamentosConcern
	include TradutorConcern
	include SimConcern

	has_paper_trail

	#gerador_de_eventos_contabeis codigo: 3, atributo_data: 'data_da_solicitacao', atributo_codigo_movimentacao: 'numero'

	attr_accessor :skip_validacao, :empenho_id, :unidade_orcamentaria_do_empenho_id
	attr_accessor :orcamento_da_liquidacao_id
	attr_accessor :ultimo_pagamento_id
	attr_accessor :pagamento_de_liquidacao_filha
	attr_accessor :conta_bancaria_invalida_id
	attr_accessor :estornados
	attr_accessor :com_capa
	attr_accessor :unidade_para_busca

	attr_default :resto_a_pagar, false
	attr_default :estornado, false
	attr_default :simplificado, false
	#attr_default :unidade_para_busca, []

	belongs_to :liquidacao, required: true
	belongs_to :orcamento
	belongs_to :pessoa_conta_bancaria, class_name: 'Base::PessoaContaBancaria'
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false

	delegate :credor, to: :liquidacao, allow_nil: true
	delegate :contas_unidade_por_empenho, to: :liquidacao, allow_nil: true
	delegate :empenho, to: :liquidacao, allow_nil: true
	delegate :elemento_de_despesa, :sub_elemento_de_despesa, to: :empenho, allow_nil: true
	delegate :subacao, to: :empenho, allow_nil: true
	delegate :acao, to: :subacao, allow_nil: true

	has_one :estorno_de_pagamento, dependent: :restrict_with_exception

	has_many :retencoes, dependent: :destroy, inverse_of: :pagamento
	has_many :contas_bancarias_por_pagamento, class_name: "Base::ContaBancariaPorPagamento"
	has_many :contas_bancarias, through: :contas_bancarias_por_pagamento, source: :conta_bancaria, class_name: 'Base::ContaBancaria'
	has_many :taloes_de_receita, class_name: "Contabilidade::TalaoDeReceita"
	has_many :pagamentos_das_retencoes, through: :retencoes
	has_many :linhas, as: :modulo, class_name: "Tcm::Linha", dependent: :destroy

	accepts_nested_attributes_for :retencoes, allow_destroy: true
	accepts_nested_attributes_for :contas_bancarias_por_pagamento, reject_if: :all_blank, allow_destroy: true

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

	validates_presence_of :data, unless: Proc.new { self.status_changed? || !confirmado? }
	validates_presence_of :valor
	validates_presence_of :data_da_solicitacao, :liquidacao_id, :forma_de_pagamento, unless: proc { self.simplificado? }
	validates_presence_of :numero_do_cheque, if: Proc.new { cheque?}

	validates_numericality_of :valor, greater_than: 0, unless: Proc.new { self.status_changed? }

	validates_associated :retencoes
	validates_associated :contas_bancarias_por_pagamento

	validates :data, sabado_ou_domingo_ou_feriado: true, unless: Proc.new { self.status_changed? || !confirmado? }
	validates :data, date: true, unless: Proc.new { self.status_changed? || !confirmado? }
	validates :data_da_solicitacao, date: true, unless: Proc.new { self.status_changed? }

	validates :retencoes, uniq_nested_attributes: {
		atributo: :imposto_type, mensagem: "imposto deve ser único dentro de pagamento"
	}
	validates :contas_bancarias_por_pagamento, uniq_nested_attributes: {
		atributo: :conta_bancaria_id, mensagem: "conta bancária deve ser única dentro do pagamento"
	}

	validate :data_deve_ser_maior_ou_igual_data_da_liquidacao, if: Proc.new { liquidacao.present? }
	validate :valor_deve_ser_igual_ao_valor_pago_mais_impostos, unless: Proc.new { Rails.env.test? || self.simplificado? }
	#validate :valor_deve_ser_igual_ao_valor_pago_mais_impostos, if: Proc.new { self.valor_changed? || self.remover_retencoes_do_pagamento_changed?} mudaça de regra para sempre verificar se a somatoria das contas é maior que o valor do pagamento
	validate :quando_for_uma_diaria_valor_deve_ser_o_mesmo
	validate :todas_as_contas_devem_possuir_saldo_suficiente, if: Proc.new { empenho.present? }, unless: proc { self.simplificado? }
	validate :valor_deve_ser_igual_ou_menor_ao_saldo_da_liquidacao, if: Proc.new { liquidacao.present? }
	validate :apenas_um_pagamento_pode_herdar_retencoes, if: Proc.new { liquidacao.present? && liquidacao.nota_fiscal.present? && liquidacao.retencoes.any? }
	validate :valida_data_com_exercicio, if: Proc.new {self.data_da_solicitacao_changed?}
	validate :data_do_pagamento_superior_a_conta_bancaria, if: Proc.new { self.data_da_solicitacao.present? && self.contas_bancarias_por_pagamento.any? }
	validate :valida_se_ja_houve_envio_do_sim
	validate :valida_pagamento_confirmado_com_data_futura, if: Proc.new { self.status_changed? && self.data_da_solicitacao.present? }

	after_commit :gera_linha_para_arquivo_do_sim, if: Proc.new { solicitado? == false && Configuracao.last.faz_envio_do_sim? && self.simplificado == false && self.orcamento.exercicio > Date.today.year - 1}
	after_commit :atribui_codigo_disponivel
	
	before_create :atribui_sequencial_do_sim, if: Proc.new { self.sequencial_do_sim.nil? && self.orcamento.present? && self.liquidacao.present? }
	before_create :define_se_eh_resto_a_pagar
	before_create :deleta_ultimo_pagamento

	after_save :cria_retencoes, if: Proc.new { !self.reload.retencoes.any? && !self.remover_retencoes_do_pagamento && liquidacao.try(:nota_fiscal).present? && liquidacao.try(:retencoes).any? }
	after_save :cria_retencoes_de_folha, if: Proc.new { !self.retencoes.any? && !self.remover_retencoes_do_pagamento && liquidacao.try(:retencoes_folha).try(:any?) }
	after_save :gera_linha_para_arquivo_do_sim, if: Proc.new { solicitado? == false && Configuracao.last.faz_envio_do_sim? && self.orcamento.exercicio > Date.today.year - 1 }

	before_update :impedir_update_se_pagamento_estornado, unless: Proc.new { self.status_changed? }
	before_create :set_status

	#after_save :apaga_lancamentos_da_conta_bancaria Essa função está na conta bancaria por pagamento
	after_save :lancar_nas_contas_bancarias
	after_save :cria_talao_de_desconto_iss, if: Proc.new { possui_retencoes_de_iss? && orcamentario_iss.present? }
	after_save :cria_talao_de_desconto_irrf_pj, if: Proc.new { possui_retencoes_de_irrf_pj? && orcamentario_irpf.present? }
	after_save :cria_talao_de_desconto_irrf_pf, if: Proc.new { possui_retencoes_de_irrf_pf? && orcamentario_irpj.present? }

	after_save :atualiza_valor_do_talao, if: Proc.new { taloes_de_receita.any? }
	before_update :remover_retencoes, if: Proc.new { retencoes.any? && self.remover_retencoes_do_pagamento_changed? && self.remover_retencoes_do_pagamento?}

	after_create :setar_valor_a_pagar_do_empenho
	after_destroy :setar_novamente_valores_a_pagar_do_empenho

	after_destroy :apagar_lancamentos_nas_contas
	after_destroy :deleta_taloes_de_receita
	after_destroy :gera_linha_para_arquivo_do_sim, if: Proc.new { solicitado? == false && Configuracao.last.faz_envio_do_sim? && self.orcamento.exercicio > Date.today.year - 1}

	enum decorrente_de: {
		aluguel: 0, # não é obrigatório calcular o inss p/ calcular o irrf
		transporte_de_carga: 1, # abater 40% da base de cálculo do inss e irrf pessoa física
		transporte_de_passageiros: 2, # abater 60% da base de cálculo do inss e irrf pessoa física
		outros: 3
	}

	enum status: {
		solicitado: 1,
		confirmado: 2,
		aguardando_lote: 3,
		lote_gerado: 4,
		confirmado_por_lote_bancario: 5,
		estornado: 99
	}

	enum forma_de_pagamento: {
		caixa: 1,
		lote_bancario: 2,
		debito_em_conta: 3,
		cheque: 4
	}

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

	scope :prepagamentos, -> { where(prepagamento: true) }
	scope :ativos,     -> { where(estornado: false) }
	scope :confirmados, -> { where(status: :confirmado) }
	scope :confirmados_ou_superior, -> {where.not(status: [:solicitado, :estornado])}
	scope :confirmados_ou_superior_com_estornados, -> {where.not(status: [:solicitado])}
	scope :para_portal, -> {where.not(status: [:solicitado])}
	scope :estornados, -> { where("status = 99") }
	scope :do_orcamento, -> { where("contabilidade_pagamentos.resto_a_pagar is false")}
	scope :de_restos_a_pagar, -> { where("contabilidade_pagamentos.resto_a_pagar is true")}
	scope :de_folha_de_pagamento, -> {joins(:liquidacao).where("contabilidade_liquidacoes.data_de_emissao_da_folha is not null")}
	scope :pagamento_comum, -> {joins(:liquidacao).where("contabilidade_liquidacoes.data_de_emissao_da_folha is null")}

	def unidade_orcamentaria
		return liquidacao.unidade_orcamentaria
	end

	def unidade_orcamentaria_do_exercicio
		return liquidacao.unidade_orcamentaria_do_exercicio_atual
	end

	def esta_confirmado?
		confirmado? || lote_gerado? || confirmado_por_lote_bancario?
	end

	def unidade_orcamentaria_atual
		if self.orcamento == liquidacao.orcamento
			unidade =  liquidacao.unidade_orcamentaria_do_exercicio_atual
		else
			cod_orgao = liquidacao.empenho.unidade_orcamentaria.orgao.codigo
			cod_unidade = liquidacao.empenho.unidade_orcamentaria.codigo

			unidade = Loa::UnidadeOrcamentaria.joins(:orgao).find_by(codigo: cod_unidade, loa_orgaos: {codigo: cod_orgao, orcamento_id: self.orcamento.id})
			if unidade.blank?
				unidade = orcamento.unidades_orcamentarias.joins(:unidades_orcamentaria_vinculada).find_by('loa_unidades_orcamentaria_vinculada.unidade_orcamentaria_vinculada_id = ?', liquidacao.empenho.unidade_orcamentaria.id)
			end
		end

		return unidade
	end

	def set_status
		if self.lote_bancario?
			self.status = :aguardando_lote
		else
			self.status = :confirmado
		end
	end

	def valor_liquido
		return (valor.to_f - valor_das_retencoes)
	end

	def valor_das_retencoes
		retencoes.sum(:valor_calculado).to_f
	end

	def liquidacao_tem_valor_disponivel?
		liquidacao.saldo > 0
	end

	def de_folha_de_pagamento?
		liquidacao.data_de_emissao_da_folha.present?
	end

	def valor_total_pago
		valor_liquido_pago.to_f + valor_das_retencoes.to_f
	end

	def valor_liquido_pago
		if retencoes.any? && !liquidacao.nota_fiscal.nil?
			(self.valor - valor_dos_impostos) rescue 0
		else
			contas_bancarias_por_pagamento.inject(0) { |total, conta| total + conta.valor_pago.to_f } rescue 0
		end
	end

	def valor_liquido_para_contas_patrimoniais
		# alteração solicitado por icaro e issac, motivo: diferença de talões sem conta bancaria
		self.valor_liquido_pago + self.taloes_de_receita.where(origem_do_talao: :orcamentario).sum(:valor)
	end

	def cria_talao_de_desconto_iss
		receita_do_talao = contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 1).natureza_da_receita.id rescue nil

		if receita_do_talao.present?
			valor_do_talao = valor_do_iss.to_f
			historico_do_talao = "Arrecadação de Receita de ISS decorrente do pagamento nº #{self.numero}"
			conta_bancaria_pagamento = contas_bancarias.first
			conta_do_talao = conta_bancaria_pagamento.contas_bancarias_por_unidade_orcamentaria.find_by(unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id)
			talao_existente = orcamento.taloes_de_receita.where(natureza_da_receita_id: receita_do_talao, pagamento_id: self.id )
			if !talao_existente.present?
				talao_de_receita = Contabilidade::TalaoDeReceita.new(
					orcamento_id: self.orcamento_id,
					data_do_talao: self.data,
					valor: valor_do_talao,
					historico: historico_do_talao,
					pessoa_id: self.credor.id,
					conta_bancaria_por_unidade_orcamentaria_id: conta_do_talao.id,
					documento_de_credito: '0',
					tipo_de_documento: :outro_tipo_de_documento_de_credito,
					natureza_da_receita_id: receita_do_talao,
					tipo_do_talao: :original,
					origem_do_talao: :orcamentario,
					unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id,
					skip_callback: true,
					pagamento_id: self.id
				)
	
				unidade_por_natureza_da_receita = Loa::UnidadeOrcamentariaPorNaturezaDaReceita.find_by(natureza_da_receita_id: receita_do_talao, unidade_orcamentaria_id: conta_do_talao.unidade_orcamentaria.id)
				fontes_de_recursos = Loa::OrcamentoDaReceita.where("loa_orcamentos_da_receita.valor > 0").where( unidade_orcamentaria_por_natureza_da_receita_id: unidade_por_natureza_da_receita.id).order(:fonte_de_recursos_id)
				valor_total_da_natureza_da_receita = fontes_de_recursos.first.unidade_orcamentaria_por_natureza_da_receita.valor_total
	
				fontes_de_recursos.each do |fonte_de_recurso|
					percentual_da_fonte = ((100 * fonte_de_recurso.valor.to_f) / valor_total_da_natureza_da_receita).to_f.round(2)
					valor_da_fonte = ((percentual_da_fonte * valor_do_talao) / 100).to_f.round(2)
	
					talao_de_receita.complementos_por_fonte_do_talao_de_receita.build(
						complementacao_da_fonte_de_recurso: :sem_complemento,
						orcamento_da_receita_id:  fonte_de_recurso.id,
						talao_de_receita_id: talao_de_receita.id,
						valor: valor_da_fonte
					)
				end
				if talao_de_receita.save
					talao_de_receita.skip_callback = false
					talao_de_receita.gerar_todos_os_movimentos(:data_do_talao, orcamento)
				end
			end
		end
	end

	def cria_talao_de_desconto_irrf_pj
		receita_do_talao = contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 5).natureza_da_receita.id

		if receita_do_talao.present?
			valor_do_talao = valor_do_irrf.to_f
			historico_do_talao = "Arrecadação de Receita de IRPJ decorrente do pagamento nº #{self.numero}"
			conta_bancaria_pagamento = contas_bancarias.first
			conta_do_talao = conta_bancaria_pagamento.contas_bancarias_por_unidade_orcamentaria.find_by(unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id)
			talao_existente = orcamento.taloes_de_receita.where(natureza_da_receita_id: receita_do_talao, pagamento_id: self.id )
			if !talao_existente.present?
				talao_de_receita = Contabilidade::TalaoDeReceita.new(
					orcamento_id: self.orcamento_id,
					data_do_talao: self.data,
					valor: valor_do_talao,
					historico: historico_do_talao,
					pessoa_id: self.credor.id,
					conta_bancaria_por_unidade_orcamentaria_id: conta_do_talao.id,
					documento_de_credito: '0',
					tipo_de_documento: :outro_tipo_de_documento_de_credito,
					natureza_da_receita_id: receita_do_talao,
					tipo_do_talao: :original,
					origem_do_talao: :orcamentario,
					unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id,
					skip_callback: true,
					pagamento_id: self.id
				)
	
				unidade_por_natureza_da_receita = Loa::UnidadeOrcamentariaPorNaturezaDaReceita.find_by(natureza_da_receita_id: receita_do_talao)
				fontes_de_recursos = Loa::OrcamentoDaReceita.where("loa_orcamentos_da_receita.valor > 0").where( unidade_orcamentaria_por_natureza_da_receita_id: unidade_por_natureza_da_receita.id).order(:fonte_de_recursos_id)
				valor_total_da_natureza_da_receita = fontes_de_recursos.first.unidade_orcamentaria_por_natureza_da_receita.valor_total
	
				fontes_de_recursos.each do |fonte_de_recurso|
					percentual_da_fonte = ((100 * fonte_de_recurso.valor.to_f) / valor_total_da_natureza_da_receita).to_f.round(2)
					valor_da_fonte = ((percentual_da_fonte * valor_do_talao) / 100).to_f.round(2)
	
					talao_de_receita.complementos_por_fonte_do_talao_de_receita.build(
						complementacao_da_fonte_de_recurso: :sem_complemento,
						orcamento_da_receita_id:  fonte_de_recurso.id,
						talao_de_receita_id: talao_de_receita.id,
						valor: valor_da_fonte
					)
				end
				if talao_de_receita.save
					talao_de_receita.skip_callback = false
					talao_de_receita.gerar_todos_os_movimentos(:data_do_talao, orcamento)
				end
			end
		end
	end

	def cria_talao_de_desconto_irrf_pf
		receita_do_talao = contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 4).natureza_da_receita.id

		if receita_do_talao.present?
			valor_do_talao = valor_do_irrf.to_f
			historico_do_talao = "Arrecadação de Receita de IRPF decorrente do pagamento nº #{self.numero}"
			conta_bancaria_pagamento = contas_bancarias.first
			conta_do_talao = conta_bancaria_pagamento.contas_bancarias_por_unidade_orcamentaria.find_by(unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id)
			talao_existente = orcamento.taloes_de_receita.where(natureza_da_receita_id: receita_do_talao, pagamento_id: self.id )
			if !talao_existente.present?
				talao_de_receita = Contabilidade::TalaoDeReceita.new(
					orcamento_id: self.orcamento_id,
					data_do_talao: self.data,
					valor: valor_do_talao,
					historico: historico_do_talao,
					pessoa_id: self.credor.id,
					conta_bancaria_por_unidade_orcamentaria_id: conta_do_talao.id,
					documento_de_credito: '0',
					tipo_de_documento: :outro_tipo_de_documento_de_credito,
					natureza_da_receita_id: receita_do_talao,
					tipo_do_talao: :original,
					origem_do_talao: :orcamentario,
					unidade_orcamentaria_id: retorna_unidade_orcamentaria_do_exercicio_atual.id,
					skip_callback: true,
					pagamento_id: self.id
				)
	
				unidade_por_natureza_da_receita = Loa::UnidadeOrcamentariaPorNaturezaDaReceita.find_by(natureza_da_receita_id: receita_do_talao)
				fontes_de_recursos = Loa::OrcamentoDaReceita.where("loa_orcamentos_da_receita.valor > 0").where( unidade_orcamentaria_por_natureza_da_receita_id: unidade_por_natureza_da_receita.id).order(:fonte_de_recursos_id)
				valor_total_da_natureza_da_receita = fontes_de_recursos.first.unidade_orcamentaria_por_natureza_da_receita.valor_total
	
				fontes_de_recursos.each do |fonte_de_recurso|
					percentual_da_fonte = ((100 * fonte_de_recurso.valor.to_f) / valor_total_da_natureza_da_receita).to_f.round(2)
					valor_da_fonte = ((percentual_da_fonte * valor_do_talao) / 100).to_f.round(2)
	
					talao_de_receita.complementos_por_fonte_do_talao_de_receita.build(
						complementacao_da_fonte_de_recurso: :sem_complemento,
						orcamento_da_receita_id:  fonte_de_recurso.id,
						talao_de_receita_id: talao_de_receita.id,
						valor: valor_da_fonte
					)
				end
				if talao_de_receita.save
					talao_de_receita.skip_callback = false
					talao_de_receita.gerar_todos_os_movimentos(:data_do_talao, orcamento)
				end
			end
		end
	end

	def atualiza_valor_do_talao
		if possui_retencoes_de_iss?
			receita_do_talao =  contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 1).natureza_da_receita.id rescue nil

			if receita_do_talao.present?
				valor_do_talao = valor_do_iss.to_f
				talao_existente = self.taloes_de_receita.find_by(natureza_da_receita_id: receita_do_talao )
				if talao_existente.present?
					talao_existente.update_column(:valor, valor_do_talao)
					talao_existente.update_attribute(:data_do_talao, self.data) if talao_existente.data_do_talao != self.data
				end
			end
		end

		if possui_retencoes_de_irrf_pj?
			receita_do_talao = contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 5).natureza_da_receita.id rescue nil
			
			if receita_do_talao.present?
				valor_do_talao = valor_do_irrf.to_f
				talao_existente = self.taloes_de_receita.find_by(natureza_da_receita_id: receita_do_talao )
				if talao_existente.present?
					talao_existente.update_column(:valor, valor_do_talao)
					talao_existente.update_attribute(:data_do_talao, self.data) if talao_existente.data_do_talao != self.data					
				end
			end
		end

		if possui_retencoes_de_irrf_pf?
			receita_do_talao = contexto_atual.contas_extra_orcamentarias.find_by(retencao_para: 4).natureza_da_receita.id rescue nil

			if receita_do_talao.present?
				valor_do_talao = valor_do_irrf.to_f
				talao_existente = self.taloes_de_receita.find_by(natureza_da_receita_id: receita_do_talao )
				if talao_existente.present?
					talao_existente.update_column(:valor, valor_do_talao)
					talao_existente.update_attribute(:data_do_talao, self.data) if talao_existente.data_do_talao != self.data					
				end
			end
		end

		retencoes_de_folha = self.retencoes.where(imposto: nil).all

		retencoes_de_folha.each do |retencao|
			talao_existente = self.taloes_de_receita.find_by(conta_extra_orcamentaria_id: retencao.conta_extra_orcamentaria_id)

			if talao_existente.present?
				talao_existente.update_column(:valor, retencao.valor_calculado) if talao_existente.valor != retencao.valor_calculado
				talao_existente.update_attribute(:data_do_talao, self.data) if talao_existente.data_do_talao != self.data					
			end
		end
	end

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

	def valor_dos_impostos
		self.valor_do_inss + self.valor_do_iss + self.valor_do_irrf
	end

	def atribui_codigo_disponivel
		if self.numero.nil? || self.numero.to_s.empty? || self.data.to_s.gsub("/", "")[0..3] != self.numero.to_s[0..3]
			numeros_despesa = self.orcamento.despesas_extra_orcamentarias.where(data_de_emissao: self.data_da_solicitacao).pluck(:numero_de_caixa).map(&:to_i) 
			numeros_pagamentos = self.orcamento.pagamentos.where(data_da_solicitacao: self.data_da_solicitacao).pluck(:numero).map(&:to_i)
			todos_os_numeros = numeros_despesa + numeros_pagamentos	
			ultimo_numero_gerado = [ultimo_numero_gerado.to_s, todos_os_numeros.max].max if ultimo_numero_gerado && todos_os_numeros.present?
			numero_gerado = ultimo_numero_gerado ? (ultimo_numero_gerado.to_i + 1) : gerar_codigo(data_da_solicitacao, :numero, :data_da_solicitacao, :orcamento_id, self.orcamento_id)
		
			numero_disponivel = (numero_gerado.to_i..Float::INFINITY).lazy.find do |numero|
				!todos_os_numeros.include?(numero.to_i) && self.numero != numero.to_i 
			end
			
			self.numero = numero_disponivel.to_s.rjust(8, '0')
			self.update_column(:numero, self.numero)
		end

		ajustar_descricao_dos_taloes
	end
	
	def ajustar_descricao_dos_taloes
		self.taloes_de_receita.each do |talao|
			if talao.pagamento.present?
				if talao.conta_extra_orcamentaria.present?
					talao.update_column(:historico, "Receita Extraorçamentária - Retenção #{talao&.conta_extra_orcamentaria&.descricao}, decorrente do pagamento #{talao&.pagamento&.numero}. Contribuinte #{talao&.pessoa&.nome}. ")
				else
					talao.update_column(:historico, "Receita Orçamentária - Retenção #{talao&.natureza_da_receita&.descricao}, decorrente do pagamento #{talao&.pagamento&.numero}. Contribuinte #{talao&.pessoa&.nome}. ")
				end
			end
		end
	end

	def atribui_sequencial_do_sim
		numero_do_ultimo_pagamento = self.liquidacao.empenho.pagamentos.last.try(:sequencial_do_sim)

		if numero_do_ultimo_pagamento.present?
			ultimo_numero_identificador = numero_do_ultimo_pagamento[4..7]
			novo_identificador = "#{ultimo_numero_identificador.to_i + 1}"

			self.sequencial_do_sim = "#{self.orcamento.exercicio}#{novo_identificador.insert(0, "0" * (4 - novo_identificador.size) ) }"
		else
			self.sequencial_do_sim = "#{self.orcamento.exercicio}0001"
		end
	end

	def numero_formatado
		self[:numero].to_i.digitos(8) if self[:numero].present?
	end

	def possui_retencoes_de_iss?
		retencoes.where(imposto_type: 'Contabilidade::ImpostoSobreServico').any?
	end

	def possui_retencoes_de_irrf_pj?
		retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaJuridica').any?
	end

	def possui_retencoes_de_irrf_pf?
		retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaFisica').any?
	end

	def possui_retencoes_de_inss_pj?
		retencoes.where(imposto_type: 'Contabilidade::InssPessoaJuridica').any?
	end

	def possui_retencoes_de_inss_pf?
		retencoes.where(imposto_type: 'Contabilidade::InssPessoaFisica').any?
	end

	def detalhamento_do_plano_de_contas
		liquidacao.detalhamento_do_plano_de_contas
	end

	def porcentagem_da_liquidacao
		unless self.liquidacao.blank? || self.estornado?
			((self.valor_total_pago * 100) / self.liquidacao.valor.to_f).round(2)
		else
			0.to_f
		end
	end

	def remover_retencoes
		retencoes.destroy_all
		self.update_column(:remover_retencoes_do_pagamento, true)
		self.update_columns(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)

		if taloes_de_receita.any?
			taloes_de_receita.each do |talao_existente|
				talao_existente.destroy
			end
		end
	end

	def deleta_taloes_de_receita
		if taloes_de_receita.any?
			taloes_de_receita.each do |talao_existente|
				talao_existente.destroy
			end
		end
	end

	def valor_do_inss
		if liquidacao.nota_fiscal.present? && liquidacao.retencoes.any? && !remover_retencoes_do_pagamento
			liquidacao.retencoes.where(imposto_type: 'Contabilidade::InssPessoaJuridica').sum(:valor_calculado) + liquidacao.retencoes.where(imposto_type: 'Contabilidade::InssPessoaFisica').sum(:valor_calculado)
		else
			retencoes.where(imposto_type: 'Contabilidade::InssPessoaJuridica').sum(:valor_calculado) + retencoes.where(imposto_type: 'Contabilidade::InssPessoaFisica').sum(:valor_calculado)
		end
	end

	def taloes_do_inss
		taloes_de_receita.select{|f| f.retencao.imposto_type == "Contabilidade::InssPessoaJuridica" || f.retencao.imposto_type == "Contabilidade::InssPessoaFisica"}.pluck(:numero_do_talao).join(" ")
	end

	def valor_do_iss
		if liquidacao.nota_fiscal.present? && liquidacao.retencoes.any? && !remover_retencoes_do_pagamento
			liquidacao.retencoes.where(imposto_type: 'Contabilidade::ImpostoSobreServico').sum(:valor_calculado)
		else
			retencoes.where(imposto_type: 'Contabilidade::ImpostoSobreServico').sum(:valor_calculado)
		end
	end

	def taloes_de_iss
		taloes_de_receita.select{|f| f.try(:retencao).try(:imposto_type) == "Contabilidade::ImpostoSobreServico"}.pluck(:numero_do_talao).join(" ")
	end

	def valor_do_irrf
		if liquidacao.nota_fiscal.present? && liquidacao.retencoes.any? && !remover_retencoes_do_pagamento
			liquidacao.retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaJuridica').sum(:valor_calculado).to_f + liquidacao.retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaFisica').sum(:valor_calculado).to_f
		else
			retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaJuridica').sum(:valor_calculado).to_f + retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaFisica').sum(:valor_calculado).to_f
		end
	end

	def taloes_de_irrf
		taloes_de_receita.select{|f| f.try(:retencao).try(:imposto_type) == "Contabilidade::IrrfPessoaJuridica" || f.try(:retencao).try(:imposto_type) == "Contabilidade::IrrfPessoaFisica"}.pluck(:numero_do_talao).join(" ")
	end



	def cria_retencoes

		unless self.simplificado?
			liquidacao.retencoes.each do |retencao|
				retencao_nova = Contabilidade::Retencao.new(
					pagamento_id: self.id,
					imposto_id: retencao.imposto_id,
					imposto_type: retencao.imposto_type,
					aliquota: retencao.aliquota,
					base_de_calculo: retencao.base_de_calculo,
					valor_calculado: retencao.valor_calculado,
					tipo_de_acao: retencao.tipo_de_acao
				)

				unless retencao_nova.valid?
					retencao_nova.errors.each do |key, value|
						self.errors.add(:base, "[Erro ao gerar retenção para #{retencao.try(:imposto).class.try(:model_name).try(:human).to_s}] #{value.try(:capitalize)}")
					end
				end

				retencao_nova.save!

				if retencao.try(:nota_fiscal).try(:orcamentario_iss)
					self.update_column(:orcamentario_iss, true)
				elsif retencao.try(:nota_fiscal).try(:extraorcamentario_iss)
					self.update_column(:extraorcamentario_iss, true)
				elsif retencao.try(:nota_fiscal).try(:orcamentario_inss_pj)
					self.update_column(:orcamentario_inss_pj, true)
				elsif retencao.try(:nota_fiscal).try(:extraorcamentario_inss_pj)
					self.update_column(:extraorcamentario_inss_pj, true)
				elsif retencao.try(:nota_fiscal).try(:orcamentario_irpj)
					self.update_column(:orcamentario_irpj, true)
				elsif retencao.try(:nota_fiscal).try(:extraorcamentario_irpj)
					self.update_column(:extraorcamentario_irpj, true)
				elsif retencao.try(:nota_fiscal).try(:orcamentario_irpf)
					self.update_column(:orcamentario_irpf, true)
				elsif retencao.try(:nota_fiscal).try(:extraorcamentario_irpf)
					self.update_column(:extraorcamentario_irpf, true)
				end
			end
		end
	end

	def cria_retencoes_de_folha

		unless self.simplificado?
			liquidacao.retencoes_folha.each do |retencao|
				retencao_nova = Contabilidade::Retencao.new(
					pagamento_id: self.id,
					conta_extra_orcamentaria_id: retencao.conta_extra_orcamentaria_do_exercicio_atual.id,
					valor_calculado: retencao.valor_calculado.to_f,
					tipo_de_acao: retencao.tipo_de_acao
				)
				retencao_nova.save
			end
		end
	end

	def rentencoes_calculadas
		self.orcamentario_iss = retencoes.where(imposto_type: 'Contabilidade::ImpostoSobreServico').any?

		self.orcamentario_irpj = retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaJuridica').any?
		self.orcamentario_irpf = retencoes.where(imposto_type: 'Contabilidade::IrrfPessoaFisica').any?

		self.orcamentario_inss_pj = retencoes.where(imposto_type: 'Contabilidade::InssPessoaJuridica').any?
		self.extraorcamentario_inss_pf = retencoes.where(imposto_type: 'Contabilidade::InssPessoaFisica').any?
	end

	def retem_inss_pf?
		return retencoes.reject(&:marked_for_destruction?).find{|retencao| retencao.imposto_type.eql?('Contabilidade::InssPessoaFisica')}
	end

	# VALIDAÇÕES
	def data_deve_ser_maior_ou_igual_data_da_liquidacao
		data_da_liquidacao = liquidacao.data_da_liquidacao || liquidacao.data_de_solicitacao

		errors.add(:data_da_solicitacao, "deve ser maior ou igual a data da liquidação #{data_da_liquidacao}") if data_da_solicitacao && (data_da_solicitacao < data_da_liquidacao)
	end

	def valor_deve_ser_igual_ou_menor_ao_saldo_da_liquidacao
		errors.add(:valor, "deve ser menor ou igual ao saldo da liquidação ") if valor.to_f.round(2) > (valor_a_liquidar.to_f.round(2) + self.valor_was.to_f)
	end

	def valida_data_com_exercicio
		if self.data_da_solicitacao.present?  && self.orcamento_id.present? && self.data_da_solicitacao.try(:year) != self.orcamento.exercicio
			errors.add(:data_da_solicitacao, 'A data da solicitação, não está dentro do exercício logado.')
		end
	end

	def apenas_um_pagamento_pode_herdar_retencoes
		pagamentos_existentes = liquidacao.pagamentos.where(remover_retencoes_do_pagamento: false, estornado: false).where.not(id: self.id)
		errors.add(:remover_retencoes_do_pagamento, "Já existe um pagamento com as retenções criadas na liquidação") if pagamentos_existentes.any? && !self.remover_retencoes_do_pagamento
	end

	def valor_deve_ser_igual_ao_valor_pago_mais_impostos
		if !self.remover_retencoes_do_pagamento && liquidacao.present? && (liquidacao.possui_retencoes? || liquidacao.retencoes_folha.any?)
			valor_dos_impostos = liquidacao.valor_das_retencoes
		else
			valor_dos_impostos = 0
		end
		valor_pago = contas_bancarias_por_pagamento.inject(0) { |total, conta| total + conta.valor_pago.to_d }

		errors.add(:valor, "Valor deve bater com o somatório das contas e dos impostos") if self.valor.to_d.round(2) != (valor_pago.to_d + valor_dos_impostos.to_d).to_d.round(2)
	end

	def numeros_dos_lotes
		numeros_dos_lotes = self.contas_bancarias_por_pagamento.map { |c| c.pagamentos_do_lote_bancario.joins(:lote_bancario).where("contabilidade_lotes_bancarios.status in (1,2)").map { |l| [l.lote_bancario_id, l.lote_bancario.numero] } }[0] rescue []
		if numeros_dos_lotes.nil?
			return []
		else
			return numeros_dos_lotes
		end
	end

	def numeros_dos_lotes_das_retencoes
		numeros_dos_lotes = self.pagamentos_das_retencoes.map { |p| p.pagamentos_do_lote_bancario.joins(:lote_bancario).where("contabilidade_lotes_bancarios.status in (1,2)").map { |l| [l.lote_bancario_id, l.lote_bancario.numero] } }[0] rescue []
		if numeros_dos_lotes.nil?
			return []
		else
			return numeros_dos_lotes
		end
	end

	def quando_for_uma_diaria_valor_deve_ser_o_mesmo
		if liquidacao.present? && liquidacao.empenho.present? && liquidacao.empenho.diaria_id.present?
			if valor.present?
				unless liquidacao.empenho.diaria.valor_total == valor
					errors.add(:valor, "deve ser o mesmo valor da diária")
				end
			end
		end
	end

	def tem_retencoes_de_folha?
		liquidacao.retencoes_folha.any? && !self.remover_retencoes_do_pagamento
	end

	def retorna_unidade_orcamentaria_do_exercicio_atual
		self.liquidacao.unidade_orcamentaria_do_exercicio_atual(contexto_atual)
	end

	def todas_as_contas_devem_possuir_saldo_suficiente
		unidade_do_empenho = self.liquidacao.unidade_orcamentaria_do_exercicio_atual(contexto_atual)

		contas_bancarias_por_pagamento.each do |conta_por_pagamento|
			conta = conta_por_pagamento.conta_bancaria
			next if conta.blank? || conta_por_pagamento.valor_pago.blank?

			conta_da_unidade = conta_por_pagamento.conta_bancaria.contas_bancarias_por_unidade_orcamentaria.find_by(unidade_orcamentaria_id: unidade_do_empenho.id)

			if conta_da_unidade.present?
				if conta_por_pagamento.changed?
					saldo_inicial = conta_da_unidade.saldo_por_data(self.data)
				else
					saldo_inicial = conta_da_unidade.saldo_por_data(self.data) + conta_por_pagamento.valor_pago_was.to_d - conta_por_pagamento.valor_pago.to_d
				end

				if conta_por_pagamento.valor_pago.to_d > saldo_inicial
					errors.add(:base, "Saldo insuficiente para a conta selecionada, saldo disponível na data selecionada será: #{saldo_inicial.to_d.real_contabil}")
				else
					conta_da_unidade.soma_das_movimentacoes_futuras_agrupadas_por_dia(self.data).each do |movimentacao|
						saldo_inicial = saldo_inicial + movimentacao['valor'].to_d
						errors.add(:base, "Saldo insuficiente para a conta selecionada, saldo disponível em #{I18n.l(Date.parse(movimentacao['data_da_movimentacao']))} será: #{saldo_inicial.to_d.real_contabil}") if conta_por_pagamento.valor_pago.to_d > saldo_inicial
					end
				end

				self.conta_bancaria_invalida_id = conta_da_unidade.try(:conta_bancaria).try(:id) if self.errors[:conta_bancaria_id].size > 0
			end
		end
	end
	

	def conta_por_unidade_do_empenho(conta_bancaria)
		unidade_do_empenho = retorna_unidade_orcamentaria_do_exercicio_atual
		conta_bancaria.contas_bancarias_por_unidade_orcamentaria.find_by(unidade_orcamentaria_id: unidade_do_empenho.id)
	end

	def dados_da_movimentacao_bancaria(conta_bancaria)
		{
			conta_bancaria_por_unidade_orcamentaria_id: conta_por_unidade_do_empenho(conta_bancaria).try(:id),
			modulo: self,
			data_da_movimentacao: data,
			historico: "Pagamento #{self.resto_a_pagar ? 'de Restos a Pagar' : ''} N°: #{self.try(:numero)} - #{self.try(:credor).try(:nome_e_cpf_ou_cnpj).try(:to_s)} - #{self.liquidacao.nota_fiscal.present? ? 'NF: ' +  self.liquidacao.nota_fiscal.numero_da_nota : ''}"
		}
	end

	def movimentacao_da_conta_bancaria(valor)
		Contabilidade::MovimentacaoDaContaBancaria.find_by(modulo: self, valor: valor * -1)
	end

	def lancar_nas_contas_bancarias
		unless self.simplificado?
			return false if contas_bancarias_por_pagamento.empty?
			historico_para_movimentacao_de_pagamento = "Pagamento #{self.resto_a_pagar ? 'de Restos a Pagar' : ''} N°: #{self.try(:numero)} - #{self.try(:credor).try(:nome_e_cpf_ou_cnpj).try(:to_s)} - #{self.liquidacao.nota_fiscal.present? ? 'NF: ' +  self.liquidacao.try(:nota_fiscal).try(:numero_da_nota) : ''}"
			contas_bancarias_por_pagamento.each do |conta_por_pagamento|
				conta_bancaria = conta_por_pagamento.conta_bancaria

				movimentacao = Contabilidade::MovimentacaoDaContaBancaria.find_by(modulo: self)
				movimentacao.destroy if movimentacao.present?

				movimentacao = Contabilidade::MovimentacaoDaContaBancaria.new(dados_da_movimentacao_bancaria(conta_bancaria))
				movimentacao.valor = (self.valor * - 1)
				movimentacao.historico = historico_para_movimentacao_de_pagamento

				movimentacao.save!
			end
		end
	end

	# def apaga_lancamentos_da_conta_bancaria
	# 	movimentos = Contabilidade::MovimentacaoDaContaBancaria.where(modulo_type: 'Contabilidade::Pagamento', modulo_id: self.id)
	# 	movimentos.try(:destroy_all)
	# end

	def setar_valor_a_pagar_do_empenho
		empenho = self.empenho;
		valor_pago_ate_o_momento = empenho.pagamentos.where(estornado: false).sum(:valor);
		saldo_do_empenho = empenho.definir_valor_do_empenho - valor_pago_ate_o_momento;

		self.update_column(:valor_a_pagar_do_empenho, saldo_do_empenho);
	end

	def setar_novamente_valores_a_pagar_do_empenho
		empenho = self.empenho;

		if empenho.pagamentos.any?
			saldo_do_empenho = empenho.definir_valor_do_empenho
			empenho.pagamentos.order(:data).order(:id).each do |pagamento|
				if pagamento.estornado?
					pagamento.update_column(:valor_a_pagar_do_empenho, saldo_do_empenho);			
				else
					saldo_do_empenho = saldo_do_empenho - pagamento.valor;
					pagamento.update_column(:valor_a_pagar_do_empenho, saldo_do_empenho);
				end
			end
		end
	end

	def apagar_lancamentos_nas_contas
		return false if contas_bancarias_por_pagamento.empty?

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

	def data_de_competencia_da_folha
		liquidacao.ano_da_folha.to_s + (liquidacao.read_attribute_before_type_cast(:mes_da_folha) + 1).to_s.rjust(2,'0')
	end

	def valor_a_liquidar
		return self.liquidacao.saldo unless self.ultimo_pagamento_id.present?
		return self.liquidacao.saldo + Contabilidade::Pagamento.find(self.ultimo_pagamento_id).valor if self.ultimo_pagamento_id.present?
	end

	def data_do_pagamento_superior_a_conta_bancaria
		contas_invalidas = self.contas_bancarias_por_pagamento.map{ |conta_bancaria_por_pagamento| conta_bancaria_por_pagamento.conta_bancaria.to_s if conta_bancaria_por_pagamento.conta_bancaria.data_de_abertura.present? && conta_bancaria_por_pagamento.conta_bancaria.data_de_abertura > self.data_da_solicitacao }.join(", ") rescue false
		errors.add(:data_da_solicitacao, "Inferior a Data de Abertura das Seguintes Contas: #{contas_invalidas}") if contas_invalidas.present?
	end

	def esta_em_um_lote_bancario?
		total_em_lote = self.contas_bancarias_por_pagamento.map { |c| c if c.esta_em_um_lote? }.compact.size
		
		total_de_contas_a_pagar = self.contas_bancarias_por_pagamento.size
		if total_em_lote == 0 && total_de_contas_a_pagar == 0
			false
		else
			total_em_lote == total_de_contas_a_pagar
		end
	end

	def define_se_eh_resto_a_pagar
		self.resto_a_pagar = true if self.try(:liquidacao).try(:restos_a_pagar?)
	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?
			errors.add(:sim, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
		end
	end

	def valida_pagamento_confirmado_com_data_futura
		data_atual = Date.today
		if self.data.present? 
			errors.add(:data_da_solicitacao, 'A data selecionada não pode ser maior que a data atual') if (self.data.present? && self.data > data_atual)
		end
	end

	def existe_lote_do_sim?
		if data_sim.present?
			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 inconsistencia_no_sim?
		existe_lote_do_sim? && confirmado? == false
	end

	def data_sim
		data || data_da_solicitacao
	end

	def possui_retencoes_pendentes_de_pagamento?
		if self.retencoes.where("tipo_de_acao in (0, 1, 2)").size > 0
			self.retencoes.where("tipo_de_acao in (0, 1, 2)").size == self.pagamentos_das_retencoes.joins(:retencao).where("contabilidade_retencoes.tipo_de_acao in (0, 1, 2)").size ? false : true
		else
			return false
		end
	end

	def de_obra?
		self&.liquidacao&.empenho&.obra&.obra?
	end
	
	def valor_nao_processado_pago_por_exercicio
		if self.liquidacao && self.liquidacao.data_da_liquidacao.year == contexto_atual.exercicio
			valor_liquidado = self.liquidacao.pagamentos.sum(&:valor).to_d
	
			valor_estornado = self.liquidacao.pagamentos.flat_map do |pagamento|
				pagamento.estorno_de_pagamento
			end.compact.sum(&:valor).to_d
		else
			valor_liquidado = 0.to_d
			valor_estornado = 0.to_d
		end
	
		valor_liquidado - valor_estornado
	end

	def cumpriu_cronologia?
		return false if self.liquidacao.previsao_de_pagamento.nil? || self.data.nil?

		self.data <= self.liquidacao.previsao_de_pagamento
	end

	def saldo_final_da_conta_bancaria_valido?
		existe_conta_negativa = true
		self.contas_bancarias_por_pagamento.each do |conta_bancaria_por_pagamento|
			if conta_bancaria_por_pagamento.conta_bancaria.reload.saldo_atual_por_data(self.data).to_d < 0 || conta_bancaria_por_pagamento.conta_bancaria.reload.saldo_do_exercicio(contexto_atual).to_d < 0
				existe_conta_negativa = false
				break
			end
		end

		return existe_conta_negativa
	end
	
	def valor_processado_pago_por_exercicio(data_inicio, data_fim)
		data_inicio = Date.new(contexto_atual.exercicio, 1, 1)
		data_fim = Date.new(contexto_atual.exercicio, 12, 31)
	
		if self.liquidacao && self.liquidacao.data_da_liquidacao.year <= contexto_atual.exercicio - 1
			self.liquidacao.pagamentos.where('data >= ? AND data <= ? AND estornado is not true', data_inicio, data_fim).sum('valor')
		else
			0.to_d
		end
	end

	private
	def impedir_update_se_pagamento_estornado
		if estornado.eql?(true) && estornado_was.eql?(true)
			errors.add(:base, 'não é possível editar um pagamento estornado')
			return false
		end
	end

	def deleta_ultimo_pagamento
		if self.ultimo_pagamento_id.present?
			Contabilidade::Pagamento.find(self.ultimo_pagamento_id).destroy
		end
	end

end
