class Contabilidade::Empenho < ApplicationRecord
	include IncrementadorDeCodigoConcern
	include GeradorDeEventosContabeis
	include TradutorConcern
	include VistoriavelEmpenhosConcern
	include SimConcern
	include Pcasp::ValidaMovimentacoesConcern
	#gerador_de_eventos_contabeis codigo: 1, atributo_data: 'data_de_solicitacao', atributo_codigo_movimentacao: 'numero_do_empenho'

	has_paper_trail

	attr_default :vincula_processo_contrato, true
	attr_default :descriminacao_obrigatoria_de_itens, true
	attr_default :descrimina_itens_processo_ou_contrato, true
	attr_default :numero_confirmado, false
	attr_default :obrigatoriedade_conta_credor, false
	attr_default :encargos_sociais, false
	attr_default :saldo_cancelado_processado, false
	attr_default :saldo_cancelado_nao_processado, false
	attr_default :utiliza_aditivos_do_contrato, false
	attr_default :configurou_unidade_na_contabilidade, false
	attr_default :restos_a_pagar, false
	
	attr_accessor :vpd_he_obrigatorio
	attr_accessor :elemento_de_despesa_por_subacao_id, :subacao_id, :skip_validacao
	attr_accessor :itens_do_empenho_hidden
	attr_accessor :logado_na_contabilidade
	attr_accessor :logado_no_administrativo
	attr_accessor :detalhamento
	attr_accessor :semiautomatico
	attr_accessor :valor_do_saldo
	attr_accessor :uso_do_bem_da_obra
	attr_accessor :conta_pcasp_da_obra
	attr_accessor :utiliza_aditivos_do_contrato
	attr_accessor :configurou_unidade_na_contabilidade
	attr_accessor :contexto_atual_id
	attr_accessor :modulo_atual
	attr_accessor :nome_do_fornecedor
	attr_accessor :edita_pessoa_conta_bancaria
	attr_accessor :elemento_de_despesa_do_exercicio_anterior_id
	attr_accessor :data_ref

	belongs_to :orcamento, required: true
	belongs_to :diaria
	belongs_to :passagem
	belongs_to :projeto, class_name: 'Licitacao::Projeto'
	belongs_to :contrato, class_name: 'Licitacao::Contrato', inverse_of: :empenhos
	belongs_to :aditivo, class_name: 'Licitacao::Aditivo'
	belongs_to :pessoa, required: true, class_name: 'Base::Pessoa'
	belongs_to :orcamento_da_despesa, class_name: 'Loa::OrcamentoDaDespesa'
	belongs_to :sub_elemento_de_despesa, class_name: 'Contabilidade::SubElementoDeDespesa'
	belongs_to :pessoa_conta_bancaria, class_name: 'Base::PessoaContaBancaria'
	belongs_to :empenho_origem, class_name: 'Contabilidade::Empenho', foreign_key: :empenho_origem_id
	belongs_to :arquivo, class_name: "Tcm::Arquivo"
	belongs_to :unidade_orcamentaria_do_exercicio, class_name: "Loa::UnidadeOrcamentaria", foreign_key: :unidade_orcamentaria_do_exercicio_id
	belongs_to :operacao_de_credito, class_name: 'Obra::OperacaoDeCredito'
	belongs_to :transferencia, class_name: 'Obra::Transferencia'
	belongs_to :conta_credor, inverse_of: :empenhos
	belongs_to :lancamento_manual_do_evento_contabil, class_name: 'Contabilidade::LancamentoManualDoEventoContabil'
	belongs_to :movimentacao_do_plano_de_contas, class_name: 'Contabilidade::MovimentacaoDoPlanoDeContas'
	belongs_to :sub_conta_pcasp, class_name: 'Contabilidade::SubContaPcasp'
	belongs_to :sub_elemento_de_despesa_exercicio_anterior, class_name: 'Contabilidade::SubElementoDeDespesa', foreign_key: :sub_elemento_de_despesa_exercicio_anterior_id
	belongs_to :unidade_orcamentaria, class_name: 'Loa::UnidadeOrcamentaria'
	belongs_to :arquivo, class_name: 'Tcm::Arquivo', required: false

	# delegate :unidade_orcamentaria, to: :orcamento_da_despesa, allow_nil: true
	delegate :acao_codigo_e_nome, to: :orcamento_da_despesa, allow_nil: true
	delegate :fonte_de_recursos_codigo_e_descricao, to: :orcamento_da_despesa, allow_nil: true
	delegate :fonte_de_recursos, to: :orcamento_da_despesa, allow_nil: true
	delegate :elemento_de_despesa_por_subacao, to: :orcamento_da_despesa, allow_nil: true
	delegate :elemento_de_despesa, to: :elemento_de_despesa_por_subacao, allow_nil: true
	delegate :subacao, to: :orcamento_da_despesa, allow_nil: true
	delegate :funcao, to: :subacao, allow_nil: true
	delegate :subfuncao, to: :funcao, allow_nil: true
	delegate :obra, to: :contrato, allow_nil: true
	delegate :uso_do_bem, :conta_pcasp, to: :obra, allow_nil: true
	delegate :pedido, to: :projeto, allow_nil: true

	has_many :liquidacoes, dependent: :restrict_with_exception, inverse_of: :empenho
	has_many :estorno_de_liquidacao, through: :liquidacoes
	has_many :pagamentos, through: :liquidacoes
	has_many :anulacoes_do_empenho, dependent: :restrict_with_exception
	has_many :itens_do_empenho, dependent: :destroy
	has_many :itens, through: :itens_do_empenho
	has_many :suplementacoes_do_empenho, dependent: :restrict_with_exception
	has_many :ordens_de_compra, class_name: "Licitacao::OrdemDeCompra", dependent: :restrict_with_exception
	has_many :contas_unidade_por_empenho, class_name: 'Base::ContaUnidadePorEmpenho'
	has_many :contas_unidade, through: :contas_unidade_por_empenho, source: :conta_unidade, foreign_key: :conta_unidade_id, class_name: 'Base::ContaBancaria'
	has_many :solicitacoes_de_alteracoes_orcamentarias, class_name: 'Contabilidade::SolicitacaoDeAlteracaoOrcamentaria'
	has_many :restos_a_pagar_cancelados, class_name: "Contabilidade::RestoAPagarCancelado"
	has_many :ocorrencias_do_empenho
	has_many :fontes_de_recursos_de_restos_a_pagar, class_name: 'Contabilidade::FonteDeRecursosDeRestosAPagar', dependent: :destroy
	has_many :empenhos_do_recebimento, class_name: 'Patrimonio::EmpenhoDoRecebimento', dependent: :destroy

	has_one :lancamento_do_orcamento_da_despesa, as: :modulo, class_name: 'Contabilidade::LancamentoDoOrcamentoDaDespesa'
	has_one :tipo_de_pessoa, through: :pessoa
	has_one :cronograma_do_empenho, class_name: 'Contabilidade::CronogramaDoEmpenho', dependent: :destroy
	has_one :empenho_de_restos_a_pagar, -> { where(restos_a_pagar: true)}, class_name: 'Contabilidade::Empenho', foreign_key: 'empenho_origem_id'
	has_one :linha, as: :modulo, class_name: "Tcm::Linha", dependent: :destroy

	accepts_nested_attributes_for :itens_do_empenho, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :contas_unidade_por_empenho, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :cronograma_do_empenho, reject_if: :all_blank, allow_destroy: true

	validates_presence_of :orcamento_id, :pessoa_id, :orcamento_da_despesa_id, :sub_elemento_de_despesa_id
	validates_presence_of :complementacao_da_fonte_de_recurso, if: Proc.new { self.logado_na_contabilidade.present? && (self.orcamento.try(:exercicio).to_i < 2022 || ["1706000000", "2706000000", "1710000000", "2710000000"].include?(self.try(:fonte_de_recursos).try(:codigo_completo)))} #obriga apenas na contabilidade
	validates_presence_of :valor, unless: :descriminacao_obrigatoria_de_itens?
	validates_presence_of :data_de_solicitacao, :modalidade, :historico
	validates_presence_of :pessoa_conta_bancaria_id, if: Proc.new { obrigatoriedade_conta_credor? && edita_pessoa_conta_bancaria.nil? || edita_pessoa_conta_bancaria.present? && (self.pessoa_conta_bancaria_id_was == nil && self.pessoa_conta_bancaria_id == nil)}
	validates_presence_of :projeto_id, if: Proc.new { self.vincula_processo_contrato? && !self.diaria }

	#validacao nao esta sendo usada
	#validates_presence_of :data_do_empenho, if: :confirmado?, unless: Proc.new { self[:numero_do_empenho].present? }
	validates_presence_of :elemento_de_despesa_por_subacao_id, :subacao_id, if: lambda{ new_record? && !empenho_origem.present? }, unless: Proc.new { Rails.env.test? }
	validates_presence_of :contrato_id, if: Proc.new { self.reconhecimento_de_divida? && self.vincula_processo_contrato? }
	validates_presence_of :conta_pcasp_da_obra, :uso_do_bem_da_obra, if: Proc.new { (self.de_uma_obra? && self.obra.obra? && (self.restos_a_pagar == false) && !self.obra.foi_classificada? ) && ( self.elemento_de_despesa.present? && (self.elemento_de_despesa.obra? || self.elemento_de_despesa.reconhecimento_de_divida?) )  && ( (self.status_was.nil? && self.confirmado?) || (!self.status_was == "confirmado" && self.confirmado?))}
	validates_presence_of :uso_do_bem_do_empenho, :tipo_do_bem_do_empenho, if: Proc.new { self.aquisicao_de_imoveis? && (self.restos_a_pagar == false) && Configuracao.last.utiliza_evento_contabil?}
	validates_presence_of :aditivo_id, if: Proc.new { self.utiliza_aditivos_do_contrato == "1" }
	validates_presence_of :tipo_de_reconhecimento_do_passivo, if: Proc.new { logado_na_contabilidade }
	validates_presence_of :classificacao_vpd, if: proc { vpd_obrigatorio? && logado_na_contabilidade }
	validates_presence_of :regime, if: proc { regime_obrigatorio? && logado_na_contabilidade }
	validates_presence_of :classificacao_pcasp, if: proc { self.sub_elemento_de_despesa&.elemento_de_despesa&.codigo == "44905100"}
	# validates_presence_of :sub_elemento_de_despesa_exercicio_anterior_id, if: Proc.new { despesa_de_exercicio_anterior? }

	# validates_presence_of :movimentacao_do_plano_de_contas_id, if: Proc.new {exige_movimentacao_do_plano_de_contas? && Configuracao.last.utiliza_evento_contabil?	}

	validates_absence_of :descrimina_itens_processo_ou_contrato, if: Proc.new{ self.projeto_id.nil? && self.contrato_id.nil? && self.descrimina_itens_processo_ou_contrato_changed? && !self.diaria }, message: "Não possui vínculo com processo nem contrato"

	validates_uniqueness_of :diaria_id, scope: :orcamento_id, case_sensitive: false, :allow_blank => true, :allow_nil => true, if: Proc.new { self.restos_a_pagar == false}

	validates_uniqueness_of :numero_do_empenho, scope: [:orcamento_id, :restos_a_pagar], case_sensitive: false, :allow_blank => true, :allow_nil => true, if: Proc.new { empenho_com_mesmo_numero.present?}

	validates_numericality_of :valor, greater_than: 0, unless: :descriminacao_obrigatoria_de_itens?

	before_validation :verifica_saldo_da_dotacao, if: Proc.new {Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho?) && self.confirmado? && self.descriminacao_obrigatoria_de_itens.present? }

	validate :valida_valor_do_empenho, if: Proc.new {!self.descriminacao_obrigatoria_de_itens.present? && (self.restos_a_pagar == false)}
	validate :data_deve_estar_inclusa_na_vigencia_do_contrato, if: Proc.new { self.contrato.present? && !self.reconhecimento_de_divida? && !self.aditivo.present? && (!self.data_do_empenho.blank? || !self.data_de_solicitacao.blank?) }, unless: proc { self.retificadora? }
	validate :remove_descriminacao_sem_projeto_e_contrato, if: Proc.new{ !self.new_record? && diaria.blank? }
	validate :empenho_nao_pode_ter_dados_de_diaria_e_obras
	validate :restricoes_de_diaria, if: Proc.new { diaria.present? }
	validate :valida_saldo_update, if: Proc.new { orcamento_da_despesa.present? && Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho).present? && self.persisted? && self.restos_a_pagar == false && self.possui_itens? && self.confirmado?}
	validate :valida_elemento_de_despesa_para_contrato_de_obra, :valida_dea_para_contrato_de_obra, if: Proc.new { sub_elemento_de_despesa.present? && contrato.present? && contrato.contrato_de_obras? }
	validate :valida_valor_dos_itens_por_contrato_ou_projeto, if: Proc.new { self.projeto.present? && self.descrimina_itens_processo_ou_contrato.present? && (self.restos_a_pagar == false)}
	validate :valida_valor_dos_itens, if: Proc.new { self.restos_a_pagar == false }
	validate :valida_saldo_do_contrato, if: Proc.new { self.contrato.present? && self.restos_a_pagar == false}
	validate :valida_data_com_exercicio, if: Proc.new { (self.data_de_solicitacao_changed? || self.data_do_empenho_changed?) && (self.restos_a_pagar == false)}
	validate :valida_se_ja_houve_envio_do_sim, if: Proc.new { new_record? || data_de_solicitacao_changed? || data_do_empenho_changed? }
	validate :valida_empenho_com_data_futura, if: Proc.new { self.data_de_solicitacao_changed? || self.data_do_empenho_changed? }
	validate :valida_fornecedor_com_o_elemento_de_despesa, if: Proc.new {sub_elemento_de_despesa.present? && pessoa.present?}
	validate :valida_empenho_de_contratacao_por_tempo_determinado, if: Proc.new { sub_elemento_de_despesa.present? && elemento_de_despesa.codigo == "31900400" }
	#validate :valida_obrigatoriedade_sub_conta_e_movimentacao_pcasp, if: Proc.new { Configuracao.last.utiliza_evento_contabil? && elemento_de_despesa.present? && logado_na_contabilidade }, unless: proc { self.orcamento.exercicio < 2023 && Configuracao.last.codigo_do_municipio_no_tcm.to_i == 99  } # unless temporário, para lançamento de restos a pagar de maracanau
	
	#Essas três validações irão voltar no futuro, quando as partes delas estiverm concluidas
	#validate :valida_tipo_de_pessoa_no_elemento_36, if: Proc.new { self.pessoa.present? && self.elemento_de_despesa_por_subacao_id.present? }
	#validate :valida_tipo_de_pessoa_no_elemento_39, if: Proc.new { self.pessoa.present? && self.elemento_de_despesa_por_subacao_id.present? }
	#validate :sub_elemento_sem_evento, if: Proc.new { self.logado_na_contabilidade.present? }

	validate :empenho_de_diaria_deve_possuir_diaria, if: Proc.new { Configuracao.last.present? && sub_elemento_de_despesa.present? }

	validates :data_do_empenho, data_nao_pode_estar_no_futuro: true, if: Proc.new { self.status_was.nil? && !self[:numero_do_empenho].present? }
	validates :data_do_empenho, sabado_ou_domingo_ou_feriado: { flexivel: false }, if: Proc.new { !self[:numero_do_empenho].present? }
	validates :itens_do_empenho, uniq_nested_attributes: { atributo: :item_id, mensagem: "item deve ser único dentro de um empenho" }

	#validacao nao esta sendo usada
	#validates :data_do_empenho, date: true, if: :confirmado?, unless: Proc.new { self[:numero_do_empenho].present? }
	#validates :data_do_empenho, mesmo_exercicio_do_pai: true, unless: Proc.new { skip_validacao || (confirmado? && updated_at?)  || self[:numero_do_empenho].present?}

	validates :contas_unidade_por_empenho, uniq_nested_attributes: { atributo: :conta_unidade_id, mensagem: "Conta bancária deve ser única dentro da Unidade Orçamentária" }

	validates_length_of :numero_processo, :numero_contrato, maximum: 15
	validates_length_of :historico, maximum: 500, if: Proc.new { self.new_record? || self.historico_changed? }

	before_save :atribui_codigo_disponivel, if: Proc.new { self.data_de_solicitacao_changed? }
	before_save :valor_padrao_para_o_valor_do_empenho
	before_save :anula_pessoa_conta_bancaria, if: Proc.new {self.edita_pessoa_conta_bancaria.nil? }
	before_save :limpa_processo_contrato_quando_vincula_processo_contrato
	before_save :verifica_se_elemento_de_despesa_92
	before_save :apagar_movimento_orcamentario, if: Proc.new {self.orcamento_da_despesa_id_changed? || self.sub_elemento_de_despesa_id_changed?}
	before_save :deve_aguardar_alteracao_do_orcamento, if: Proc.new { Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho).present? && ( self.confirmado? == false || self.criado_na_contabilidade? && self.valor_was != self.valor) && !(self.status_was == "confirmado" && self.status == "solicitado") && self.restos_a_pagar == false && (self.descriminacao_obrigatoria_de_itens.present? == false || self.descriminacao_obrigatoria_de_itens.present? && self.possui_itens?) }
	before_save :marca_empenho_como_encargo_social, if: Proc.new {self.orcamento_da_despesa.try(:elemento_de_despesa).try(:codigo) == "31901300" || self.orcamento_da_despesa.try(:elemento_de_despesa).try(:codigo) == "31911300" || (self.orcamento_da_despesa.try(:elemento_de_despesa).try(:codigo) == "31900400" && self.sub_elemento_de_despesa.codigo == "15")}
	before_save :preenche_unidade_orcamentaria, if: Proc.new {self.orcamento_da_despesa.present? }
	before_save :atualiza_classificacao_vpd
	before_save :atualiza_regime
	before_save :checa_se_data_do_empenho_superior_da_liquidacao, if: Proc.new { self.data_do_empenho_changed? }
	before_save :defini_tipo_de_entidade, if: Proc.new { self.orcamento_da_despesa.try(:elemento_de_despesa).try(:codigo) == "33904700" && Configuracao.last.try(:utiliza_evento_contabil?)}

	# Lançamento do Orçamento da Despesa
	after_destroy :apagar_movimento_orcamentario
	after_save :lancar_movimento_orcamentario, if: Proc.new { self.confirmado? && self.restos_a_pagar == false }
	after_save :atualiza_dados_de_obra, if: Proc.new { self.de_uma_obra? && self.obra.obra? }
	after_save :atualiza_campo_valor_total
	after_initialize :carrega_informacoes
	after_save :atualiza_data_sim_do_contrato_aditivo_e_processo, if: Proc.new { (self.confirmado? || self.anulado?) && self.contrato.present? && Configuracao.last.faz_envio_do_sim?}

	after_destroy :atualiza_data_sim_do_contrato_aditivo_e_processo, if: Proc.new { (self.confirmado? || self.anulado?) && self.contrato.present? && Configuracao.last.faz_envio_do_sim?}

	before_save :lancar_ocorrencia
	before_update :lancar_ocorrencia_da_troca_bancaria, if: Proc.new { self.pessoa_conta_bancaria_id_changed? }
	before_update :verifica_se_e_alteracao_orcamentaria, if: Proc.new { self.aguardando_alteracao_do_orcamento?}

	before_save :lanca_as_mudancas_no_restos_a_pagar_se_tiver, if: Proc.new { self.empenho_de_restos_a_pagar.present? }

	scope :ativos, -> { where.not(status: :anulado) }
	scope :aguardando_confirmacao, -> { where.not(status: :confirmado) }
	scope :em_analise, -> { where(status: %i[enviado_para_controladoria enviado_para_copfin]) }
	scope :confirmados, -> { where(status: :confirmado) }
	scope :anulados, -> { where(status: :anulado) }
	scope :reconhecimentos_de_divida, -> { where(reconhecimento_de_divida: true) }
	scope :de_restos_a_pagar, -> { where("contabilidade_empenhos.restos_a_pagar is true") }
	scope :do_orcamento, -> { where("contabilidade_empenhos.restos_a_pagar is false") }
	scope :orcamentarios_validos, -> { where("restos_a_pagar != true AND reconhecimento_de_divida is null") }
	scope :solicitacoes_de_empenho, -> { where.not(status: [:confirmado, :recebido, :enviado_para_administrativo, :retornado_pela_contabilidade, :anulado]) }
	scope :confirmados_ou_anulados_e_superiores, -> { where(status: [:confirmado, :anulado]) }
	scope :de_material_permanente, -> {
		joins(orcamento_da_despesa: [elemento_de_despesa_por_subacao: :elemento_de_despesa]).where("base_elementos_de_despesa.codigo =?", "44905200")
	}

	enum modalidade: {
		ordinario: 0,
		global: 1,
		estimativo: 2
	}

	enum status: {
		solicitado: 0,
		enviado_para_controladoria: 1,
		enviado_para_copfin: 2,
		enviado_para_contabilidade: 3,
		confirmado: 4,
		anulado: 5,
		recebido: 6,
		enviado_para_administrativo: 7,
		aguardando_alteracao_do_orcamento: 8,
		retornado_pela_controladoria: 9,
		retornado_pela_contabilidade: 10
	}

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

	enum complementacao_da_fonte_de_recurso: {
		sem_complemento: 0000,
		beneficios_prev_poder_executivo_plano_prev: 1111,
		beneficios_prev_poder_legislativo_plano_prev: 1121,
		beneficios_prev_poder_executivo_plano_financeiro: 2111,
		beneficios_prev_poder_legislativo_plano_financeiro: 2121,
		transferencia_da_uniao_de_emendas_parlam_individuais: 3110,
		transferencia_da_uniao_de_emendas_parlam_de_bancada: 3120,
		transferencia_dos_estados_de_emendas_parlam_individuais:3210,
		transferencia_dos_estados_de_emendas_parlam_de_bancada: 3220
	}

	enum uso_do_bem_do_empenho: {
		especial: 0,
		dominical: 1,
		comum_do_povo: 2
	}

	enum tipo_de_reconhecimento_do_passivo: {
		reconhecido_na_liquidacao_da_despesa: 1,
		reconhecimento_pelo_controle_de_consumo: 2,
		reconhecimento_programado: 3,
		reconhecimento_eventual: 4,
		reconhecido_antes_da_liquidacao_nesse_exercicio: 5,
		reconhecido_antes_da_liquidacao_exercicio_anterior: 6,
		reconhecimento_no_exercicio_vigente: 7,
		reconhecimento_no_exercicio_anterior: 8
	}

	enum classificacao_vpd: {
		no_pais: 1,
		no_exterior: 2,
		pessoal_civil: 3,
		colaboradores_eventuais: 4,
		conselheiros: 5,
		premiacoes_culturais: 6,
		premiacoes_artisticas: 7,
		premiacoes_cientificas: 8,
		premiacoes_desportivas: 9,
		ordens_honorificas: 10,
		outras_premiacoes: 98,
		outras: 99
	}

	enum regime: {
		rpps: 1,
		rgps: 2
	}

	enum tipo_de_entidade: {
		federal: 1,
		estadual: 2,
		outro_municipio: 3,
		mesmo_municipio: 4
	}

	enum classificacao_pcasp: {
		obras_em_andamento: 1,
		estudos_e_projetos: 2,
		instalacoes: 3,
		benfeitorias_em_propriedade_de_terceiros: 4
	}

	ransacker :numero_formatado_liquidacao do
		Arel.sql("contabilidade_empenhos.numero_do_empenho::text ||'.'|| contabilidade_liquidacoes.numero::text")
	end

	def ordenador_na_data data_a_usar
		unidade = self.unidade_orcamentaria_do_exercicio.present? ? self.unidade_orcamentaria_do_exercicio : orcamento_da_despesa.unidade_orcamentaria
		ordenador_na_data = unidade.ordenadores_de_despesa.find_by("(data_fim_de_gestao >= ? OR data_fim_de_gestao is null) AND data_inicio_da_gestao <= ?", data_a_usar, data_a_usar)
	end

	# BOOLEANS
	def numero_nf_sendo_utilizado(numero_nf, data_referencia=nil, tipo_nf=nil, lq_id=nil)
		if numero_nf.present? && data_referencia.present? && tipo_nf.present?
			data_referencia = data_referencia.class == Date ? data_referencia : Date.new(data_referencia[4..7].to_i, data_referencia[2..3].to_i, data_referencia[0..1].to_i)
			tipo_nf = Contabilidade::Liquidacao.nota_fiscal_tipos[tipo_nf]
			numero_nf = numero_nf.to_s.gsub(/^0+/, '')
			
			liquidacoes = Contabilidade::Liquidacao.find_by_sql("SELECT lq.* FROM contabilidade_liquidacoes lq INNER JOIN contabilidade_empenhos emp on lq.empenho_id = emp.id
				WHERE emp.pessoa_id = #{self.pessoa_id} AND lq.nota_fiscal_tipo NOT IN (0,7,8) AND lq.restos_a_pagar IS FALSE AND (( LTRIM(lq.nota_fiscal_numero, '0') = '#{numero_nf.to_s}' AND lq.empenho_id = #{self.id})
					OR (lq.empenho_id <> #{self.id} AND LTRIM(lq.nota_fiscal_numero, '0') = '#{numero_nf.to_s}' AND lq.data_da_liquidacao <> '#{data_referencia.sim_data}' AND lq.nota_fiscal_tipo = #{tipo_nf}))")
			
			return liquidacoes.any? { |lq| lq.id != lq_id }
		else
			return false
		end
	end

	def numero_das_liquidacoes_e_empenhos_utilizando_a_nf(numero_nf, data_referencia=nil, tipo_nf=nil, lq_id=nil)
		if numero_nf.present? && data_referencia.present? && tipo_nf.present?
			data_referencia = data_referencia.class == Date ? data_referencia : Date.new(data_referencia[4..7].to_i, data_referencia[2..3].to_i, data_referencia[0..1].to_i)
			tipo_nf = Contabilidade::Liquidacao.nota_fiscal_tipos[tipo_nf]
			numero_nf = numero_nf.to_s.gsub(/^0+/, '')
			
			liquidacoes = Contabilidade::Liquidacao.find_by_sql("SELECT lq.* FROM contabilidade_liquidacoes lq INNER JOIN contabilidade_empenhos emp on lq.empenho_id = emp.id
				WHERE emp.pessoa_id = #{self.pessoa_id} AND lq.nota_fiscal_tipo NOT IN (0,7,8) AND lq.restos_a_pagar IS FALSE AND (( LTRIM(lq.nota_fiscal_numero, '0') = '#{numero_nf.to_s}' AND lq.empenho_id = #{self.id})
					OR (lq.empenho_id <> #{self.id} AND LTRIM(lq.nota_fiscal_numero, '0') = '#{numero_nf.to_s}' AND lq.data_da_liquidacao <> '#{data_referencia.sim_data}' AND lq.nota_fiscal_tipo = #{tipo_nf}))")
			
			return liquidacoes.map { |i| "#{i.empenho_e_numero} (#{i.empenho.orcamento.exercicio})" }.join(",") rescue ""
		end
	end

	def confirmado_ou_superior?
		confirmado? || recebido? || enviado_para_administrativo? || retornado_pela_contabilidade?
	end

	def eh_uma_solicitacao?
		solicitado? || enviado_para_controladoria? || enviado_para_copfin? || enviado_para_contabilidade? || retornado_pela_controladoria?
	end

	def atualiza_classificacao_vpd
		self.classificacao_vpd = nil unless self.vpd_obrigatorio?
	end

	def defini_tipo_de_entidade
		self.tipo_de_entidade = self.pessoa.try(:tipo_de_entidade)
	end

	def atualiza_regime
		self.regime = nil unless self.regime_obrigatorio?
	end

	def vpd_obrigatorio?
		sub_elemento = self.sub_elemento_de_despesa_exercicio_anterior.present? ? sub_elemento_de_despesa_exercicio_anterior : sub_elemento_de_despesa
		(sub_elemento.present? && sub_elemento.vpd_obrigatorio?) || orcamento_da_despesa.try(:elemento_de_despesa).try(:codigo) == '33903100'
	end

	def regime_obrigatorio?		
		orcamento_da_despesa.elemento_de_despesa.codigo == '31901100'|| orcamento_da_despesa.elemento_de_despesa.codigo == '31901600'|| orcamento_da_despesa.elemento_de_despesa.codigo == '31909400'|| orcamento_da_despesa.elemento_de_despesa.codigo == '31909600' || orcamento_da_despesa.elemento_de_despesa.codigo == '33904600' || orcamento_da_despesa.elemento_de_despesa.codigo == '33904900'
	end

	def visivel_para? usuario
		unidade_orcamentaria.in? usuario.unidades_orcamentarias
	end

	def existe_liquidacoes?
		self.liquidacoes.size > 0
	end

	def existe_liquidacao_sem_estorno?
		self.liquidacoes.where(estornada: false).size > 0
	end

	def possui_itens?
		itens_do_empenho.any?
	end

	def possui_itens_repetidos?
		itens_do_empenho.validos_no_orcamento.count != itens.distinct.count
	end

	def possui_solicitacoes_de_alteracao_orcamentaria?
		solicitacoes_de_alteracoes_orcamentarias.any?
	end

	def solicitacao_de_alteracao_orcamentaria_esta_confirmada?
		if solicitacoes_de_alteracoes_orcamentarias.present?
			solicitacoes_de_alteracoes_orcamentarias.first.confirmado?
		end
	end

	def valor_dos_itens_diferente_do_empenho?
		itens_do_empenho.present? && (valor.to_f.round(2) != itens_do_empenho.validos_no_orcamento.sum(:total).to_f.round(2))
	end

	def derivado_de_licitacao?
		aquisicao?
	end

	def derivado_de_contrato?
		contrato.present?
	end

	def aquisicao?
		projeto.present?
	end

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

	def restos_a_pagar? orcamento_atual
		orcamento_atual.try(:id) != self.orcamento_id && (saldo_atual_processado > 0 || saldo_atual_nao_processado > 0)
	end

	def valor_processado( orcamento_atual = nil)

		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		data_fim = Date.new(orcamento_atual.exercicio - 1, 12, 31)

		valor_liquidacoes = liquidacoes.valida.confirmadas_ate_autorizadas.nao_estornada.where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).sum(:valor) rescue 0

		numeros_liquidacoes = liquidacoes.valida.confirmadas_ate_autorizadas.nao_estornada.where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).map(&:numero)

		if self.empenho_origem.present?
			valor_pago_regular = empenho_origem.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).where('contabilidade_pagamentos.data <= ? AND contabilidade_pagamentos.estornado = false', data_fim).sum('contabilidade_pagamentos.valor')
		else
			valor_pago_regular = 0
		end

		valor_pago_em_restos_a_pagar_processado = self.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).where('contabilidade_pagamentos.data <= ? AND contabilidade_pagamentos.estornado = false and extract(year from contabilidade_pagamentos.data) > ?', data_fim, self.orcamento&.exercicio.to_i).sum('contabilidade_pagamentos.valor')
		
		return valor_liquidacoes - valor_pago_regular - valor_pago_em_restos_a_pagar_processado - valor_cancelado_processado(orcamento_atual)
	end

	def valor_processado_com_movimentacoes( orcamento_atual = nil, data_fim)
		
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end	

		numeros_liquidacoes = liquidacoes.valida.where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).map(&:numero)
		
		valor_pago_regular = self.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).where('contabilidade_pagamentos.estornado is false').where( 'contabilidade_pagamentos.data between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).sum('contabilidade_pagamentos.valor')

		return self.valor_processado(orcamento_atual) - valor_pago_regular.to_d - valor_cancelado_processado_ate_a_data(orcamento_atual, data_fim)
	end


	def valor_nao_processado_com_movimentacoes( orcamento_atual = nil, data_fim)
		
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		numeros_liquidacoes = liquidacoes.valida.where('data_da_liquidacao between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).map(&:numero)

		valor_pago = self.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('data_da_liquidacao between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).where('contabilidade_pagamentos.estornado is false').where( 'contabilidade_pagamentos.data between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).sum('contabilidade_pagamentos.valor')

		return valor_nao_processado(orcamento_atual).to_d - valor_pago.to_d - valor_cancelado_nao_processado_ate_a_data(orcamento_atual, data_fim)

	end

	def valor_nao_processado_liquidado_com_movimentacoes( orcamento_atual = nil, data_fim)
		
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		valor_liquidacoes = liquidacoes.valida.where("estornada is false").where('data_da_liquidacao between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).sum(:valor)

		numeros_liquidacoes = liquidacoes.valida.where("estornada is false").where('data_da_liquidacao between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).map(&:numero)

		valor_pago = self.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('data_da_liquidacao between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).where('contabilidade_pagamentos.estornado is false').where( 'contabilidade_pagamentos.data between ? and ?', Date.new(orcamento_atual.exercicio, 1, 1), data_fim).sum('contabilidade_pagamentos.valor')

		return valor_liquidacoes.to_d - valor_pago.to_d

	end

	def valor_processado_pago
		data_inicio = Date.new(contexto_atual.exercicio, 1, 1)
		data_fim = Date.new(contexto_atual.exercicio, 12, 31)
		liquidacoes.valida.joins(:pagamentos).where('extract(year from data_da_liquidacao) <= ?', contexto_atual.exercicio - 1).where('contabilidade_pagamentos.data >= ? and contabilidade_pagamentos.data <= ? and contabilidade_pagamentos.estornado is not true', data_inicio, data_fim).sum('contabilidade_pagamentos.valor')
	end

	def saldo_processado
		valor_processado.to_d - valor_processado_pago.to_d
	end

	def valor_nao_processado(orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		data_fim = Date.new(orcamento_atual.exercicio - 1, 12, 31)
		
		numeros_liquidacoes = liquidacoes.valida.where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).map(&:numero)

		valor_pago = self.liquidacoes.valida.where(numero: numeros_liquidacoes).joins(:pagamentos).where('extract(year from data_da_liquidacao) <= ?', orcamento_atual.exercicio - 1).where('contabilidade_pagamentos.data <= ? AND contabilidade_pagamentos.estornado = false and extract(year from contabilidade_pagamentos.data) > ?', data_fim, self.orcamento&.exercicio.to_i).sum('contabilidade_pagamentos.valor')

		(valor_total_do_empenho.to_d - valor_anulado_do_empenho(orcamento_atual).to_d - valor_processado(orcamento_atual).to_d - valor_cancelado_processado(orcamento_atual).to_d - valor_pago_no_orcamento_regular.to_d - valor_pago.to_d - valor_cancelado_nao_processado(orcamento_atual).to_d) rescue 0.00
	end

	def valor_pago_no_orcamento_regular
		if self.restos_a_pagar == true && self.empenho_origem.present?
			begin
				data_inicio = Date.new(self.empenho_origem.orcamento.exercicio, 1, 1)
				data_fim = Date.new(self.empenho_origem.orcamento.exercicio, 12, 31)
				self.empenho_origem.pagamentos.ativos.where(orcamento_id: self.try(:empenho_origem).try(:orcamento_id)).where('data >= ? and data <= ?', data_inicio, data_fim).sum(:valor)
			rescue
				0
			end
		else
			0
		end
	end

	def valor_nao_processado_liquidado
		liquidacoes.confirmadas_ate_autorizadas.where(estornada: false).valida.where('extract(year from data_da_liquidacao) = ?', contexto_atual.exercicio).sum(&:valor)
	end

	def valor_nao_processado_pago
		valor_liquidado = self.liquidacoes.valida.where('extract(year from data_da_liquidacao) = ?', contexto_atual.exercicio).flat_map(&:pagamentos).sum(&:valor).to_d

		valor_estornado = self.liquidacoes.valida.where('extract(year from data_da_liquidacao) = ?', contexto_atual.exercicio).flat_map do |liquidacao| 
			liquidacao.pagamentos.flat_map do |pagamento| 
				pagamento.estorno_de_pagamento 
			end 
		end.compact.sum(&:valor).to_d

		valor_liquidado - valor_estornado
	end

	def saldo_atual_nao_processado
		(valor_nao_processado.to_d - valor_nao_processado_liquidado.to_d  - valor_cancelado_nao_processado_no_orcamento_atual.to_d)
	end

	def valor_anulado_do_empenho(orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		if orcamento_atual.present?
			Contabilidade::AnulacaoDoEmpenho.joins(:empenho).where(contabilidade_empenhos: { id: self.try(:empenho_origem).try(:id) }).where("extract(year from contabilidade_anulacoes_do_empenho.data_da_anulacao) <= ?", orcamento_atual.exercicio - 1).confirmadas.sum(:valor)
		else
			self.anulacoes_do_empenho.confirmadas.sum(:valor)
		end
	end

	def saldo_atual_nao_processado_a_liquidar
		(valor_nao_processado.to_d - valor_nao_processado_liquidado.to_d - liquidacoes.valida.where('data_da_liquidacao IS NULL or status = 0').sum(&:valor).to_d)
	end

	def saldo_atual_processado
		(saldo_processado.to_d - valor_cancelado_processado_no_orcamento_atual.to_d)
	end

	def saldo_de_restos_a_pagar
		(valor_total_do_empenho_sem_restos_a_pagar.to_d + valor_cancelado_processado.to_d - valor_anulado.to_d - valor_liquidado.to_d - valor_cancelado_nao_processado.to_d + valor_liquidado_estornado.to_d).round(2)
	end

	def valor_cancelado_nao_processado( orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		exercicio = orcamento_atual.present? ? orcamento_atual.exercicio : Date.today.year
		self.restos_a_pagar_cancelados.joins(cancelamento_de_resto_a_pagar: :orcamento).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 0 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND orcamentos.exercicio < ?', exercicio).distinct.sum('COALESCE(valor_cancelado, 0)')
	end

	def valor_cancelado_nao_processado_no_orcamento_atual( orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end
		orcamento_atual = self.orcamento if orcamento_atual.nil?

		exercicio = orcamento_atual.present? ? orcamento_atual.exercicio : Date.today.year
		self.restos_a_pagar_cancelados.joins(cancelamento_de_resto_a_pagar: :orcamento).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 0 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND orcamentos.exercicio = ?', exercicio).distinct.sum('COALESCE(valor_cancelado, 0)')
	end

	def valor_cancelado_nao_processado_na_data(data)
		data = Date.today.end_of_year if data.nil?
		self.restos_a_pagar_cancelados.joins(:cancelamento_de_resto_a_pagar).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 0 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.data <= ?', data).distinct.sum('COALESCE(valor_cancelado, 0)')
	end

	def valor_cancelado_processado( orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		exercicio = orcamento_atual.present? ? orcamento_atual.exercicio : Date.today.year
		self.restos_a_pagar_cancelados.joins(cancelamento_de_resto_a_pagar: :orcamento).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND orcamentos.exercicio < ?', exercicio).distinct.sum(&:valor_cancelado)
	end

	def valor_cancelado_processado_no_orcamento_atual( orcamento_atual = nil)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end
		orcamento_atual = self.orcamento if orcamento_atual.nil?

		exercicio = orcamento_atual.present? ? orcamento_atual.exercicio : Date.today.year
		self.restos_a_pagar_cancelados.joins(cancelamento_de_resto_a_pagar: :orcamento).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND orcamentos.exercicio = ?', exercicio).distinct.sum(&:valor_cancelado)
	end

	def valor_cancelado_processado_ate_a_data( orcamento_atual = nil, data)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		self.restos_a_pagar_cancelados.joins(:cancelamento_de_resto_a_pagar).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.orcamento_id = ? AND contabilidade_cancelamentos_de_restos_a_pagar.data <= ?', orcamento_atual, data).distinct.sum(&:valor_cancelado)
	end

	def valor_cancelado_nao_processado_ate_a_data( orcamento_atual = nil, data)
		if contexto_atual.present?
			orcamento_atual = contexto_atual
		else
			orcamento_atual = orcamento_atual
		end

		self.restos_a_pagar_cancelados.joins(:cancelamento_de_resto_a_pagar).where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 0 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1 AND contabilidade_cancelamentos_de_restos_a_pagar.orcamento_id = ? AND contabilidade_cancelamentos_de_restos_a_pagar.data <= ?', orcamento_atual, data).distinct.sum(&:valor_cancelado)
	end

	def saldo_cancelado_em_rp_nao_processado
		self.contrato.itens_do_contrato.map { |item_do_contrato| item_do_contrato.valor_do_item_em_rp_cancelado_nao_processado.to_f.round(2) }.sum
	end

	def saldo_cancelado_em_rp_nao_processado_na_vigencia
		contrato_vigente = contrato_vigente_do_empenho
		data_de_inicio_vigente = contrato_vigente.inicio_da_vigencia
		data_de_fim_da_vigencia = contrato_vigente.fim_da_vigencia
		
		empenhos_de_rp_cancelados = contrato.empenhos.joins(restos_a_pagar_cancelados: :cancelamento_de_resto_a_pagar)
			.where('contabilidade_cancelamentos_de_restos_a_pagar.tipo = 0
				AND contabilidade_cancelamentos_de_restos_a_pagar.data >= ?
				AND contabilidade_cancelamentos_de_restos_a_pagar.data <= ?', data_de_inicio_vigente, data_de_fim_da_vigencia)

		empenhos_de_rp_cancelados.map { |item_do_empenho| item_do_empenho.valor_cancelado_em_rp_nao_processado.to_f.round(2) }.sum
	end

	def aguardando_pagamento?
		if self.confirmado? && self.valor.present? && self.valor > 0
			if self.pagamentos.any?
				return (self.valor == self.pagamentos.sum(:valor)) ? false : true
			else
				return true
			end
		else
			return false
		end
	end

	def deve_aguardar_alteracao_do_orcamento
		saldo_da_dotacao = self.orcamento_da_despesa.try(:saldo).to_f + self.orcamento_da_despesa.lancamentos_do_orcamento_da_despesa.where(modulo_type: 'Contabilidade::Empenho', modulo_id: self.id).first.valor

		if self.valor.present? && (saldo_da_dotacao < self.definir_valor_do_empenho || saldo_da_dotacao <= 0 )
			self.status = 'aguardando_alteracao_do_orcamento'
		end

		# temporário, para maracanau cadastrar os empenhos de restos a pagar
		if self.orcamento.exercicio < 2023 && Configuracao.last.codigo_do_municipio_no_tcm.to_i == 99 
			self.status = :confirmado
		end
	end

	def marca_empenho_como_encargo_social
		self.encargos_sociais = true
	end

	def valida_complementacao_da_fonte_de_recurso
		if !complementacao_da_fonte_de_recurso.present? && self.orcamento.try(:exercicio).to_i < 2022 # a partir de 2022 esse dado não é mais obrigatório
			raise "Não existe Complementação da Fonte de Recurso cadastrada para este Empenho: " << "#{self.numero_do_empenho}" << " (id: " << "#{self.id.to_s})"
		end
	end

	def valida_gestor_da_unidade
		if self.aditivo.present?
			self.aditivo.valida_gestor_da_unidade
		elsif self.contrato.present?
			self.contrato.valida_gestor_da_unidade
		end
	end

	def unidade_orcamentaria_do_exercicio_atual(orcamento_atual = nil)
		# MARCAR PARA TESTAR
		orcamento_atual = self.orcamento unless orcamento_atual.present?
		if self.unidade_orcamentaria.orgao.orcamento.id == orcamento_atual.id
			return self.unidade_orcamentaria
		else
			cod_orgao = self.unidade_orcamentaria.orgao.codigo
			cod_unidade = self.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 = ?', self.unidade_orcamentaria.id)
				end
			return unidade_orcamentaria_do_exercicio
		end
	end

	def valida_valor_dos_itens_por_contrato_ou_projeto
		total_itens = self.itens_do_empenho.inject(0) { |sum, item_no_empenho| sum.to_d + item_no_empenho.total.to_d }.to_d
		if projeto.present?
			if contrato.present? && (data_do_empenho.present? || data_de_solicitacao.present?)
				if (self.contrato.valor_total_do_contrato.to_d - self.contrato.valor_empenhado.to_d) < self.definir_valor_do_empenho.to_d
					# if self.valor_a_empenhar_do_contrato_vigente.to_d <= 0
					# 	errors.add(:total_erro, 'O valor a empenhar do contrato/aditivo é 0(zero)')
					# elsif (self.valor_a_empenhar_do_contrato_vigente.to_f.round(2) + self.itens_do_empenho.sum(:total).to_f).to_f.round(2) < total_itens.to_f.round(2)
					# 	errors.add(:total_erro, 'A soma dos valores deve ser menor ou igual ao valor do contrato escolhido')
					# end
					if (self.contrato.valor_total_do_contrato.to_d - self.contrato.valor_empenhado.to_d) < 0
						errors.add(:total_erro, 'O valor a empenhar do contrato/aditivo é 0(zero)')
					elsif ((self.contrato.valor_total_do_contrato.to_d - self.contrato.valor_empenhado.to_d) + self.itens_do_empenho.sum(:total).to_d).to_d < total_itens.to_d
						errors.add(:total_erro, 'A soma dos valores deve ser menor ou igual ao valor do contrato escolhido')
					end
				end
			else
				errors.add(:total_erro, 'A soma dos valores deve ser menor ou igual ao valor do projeto escolhido') if (self.projeto.valor_a_contratar.to_f + self.itens_do_empenho.sum(:total).to_f).to_f.round(2) < total_itens.to_f.round(2)
			end
		end
	end

	def valida_valor_dos_itens
		if self.projeto.present?
			total_itens = self.itens_do_empenho.inject(0) { |sum, item_no_empenho| sum.to_d + item_no_empenho.total.to_d }.to_d
			if self.contrato.present?
				errors.add(:total_erro, 'A soma dos valores deve ser menor ou igual ao valor do contrato escolhido') if (self.valor_a_empenhar_do_contrato_vigente.to_f + self.valor_total_do_empenho.to_f).round(2) < total_itens.to_f.round(2)
			else
				errors.add(:valor_unitario, 'A soma dos valores deve ser menor ou igual ao valor do projeto escolhido') if (self.projeto.valor_a_contratar.to_f + self.itens_do_empenho.sum(:total).to_f).to_f.round(2) < total_itens.to_f.round(2)
			end
		end
	end


	def valida_data_com_exercicio
		if self.data_do_empenho.present? && self.data_do_empenho.try(:year) != self.try(:orcamento).try(:exercicio)
			errors.add(:data_do_empenho, 'A data do empenho, não está dentro do exercício logado.')
		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 do empenho, não pode ser  #{mensagem}")
		end
	end

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

	def pode_duplicar_ou_criar_empenho_complementar?
		self.empenho_complementar == false && self.orcamento == contexto_atual rescue false
	end

	def pode_editar_e_excluir_no_adm?
		self.solicitado? || self.aguardando_alteracao_do_orcamento? || self.enviado_para_administrativo? || self.retornado_pela_controladoria? || self.retornado_pela_contabilidade?
	end

	def pode_editar_e_excluir_na_contabilidade?
		self.solicitado? || self.enviado_para_contabilidade? || self.recebido? || self.aguardando_alteracao_do_orcamento?
	end

	def pode_editar_itens?
		self.retornado_pela_controladoria? || self.retornado_pela_contabilidade? || self.aguardando_alteracao_do_orcamento?
	end

	def pode_voltar_para_solicitado?
		self.confirmado? && self.liquidacoes.empty? && self.arquivo_id.nil? && (self.logado_na_contabilidade.present? || 
			(self.logado_no_administrativo.present? && !Configuracao.last.envia_empenho_para_contabilidade? && !Configuracao.last.utiliza_evento_contabil?)) &&
			((self.ordens_de_compra.any? && self.ordens_de_compra.count == self.ordens_de_compra.retornados.count) || self.ordens_de_compra.empty?)
	end

	def pode_criar_parecer_da_controladoria?
		!self.confirmado? && !self.solicitado? && !self.enviado_para_contabilidade? && !self.enviado_para_administrativo? && !self.aguardando_alteracao_do_orcamento?
	end

	def pode_confirmar?
		(!self.data_do_empenho.blank? && !self.data_de_solicitacao.blank?) && 
		(self.conta_bancaria_com_a_mesma_do_empenho.present? && self.contas_unidade_por_empenho.present? || self.contas_unidade_por_empenho.blank?) && 
		((self.logado_no_administrativo.present? && !Configuracao.last.envia_empenho_para_contabilidade? && !Configuracao.last.utiliza_evento_contabil?) || (self.logado_na_contabilidade.present? && self.tipo_de_reconhecimento_correto?)) &&
		tem_operacao_de_credito_ou_subconta?
	end

	def tem_operacao_de_credito_ou_subconta?
		return true if !Configuracao.last.try(:utiliza_evento_contabil?)
		
		#se já foi cadastrada a subconta, não é necessario o cadastro da operação de credito
		((self.precisa_de_subconta? && self.sub_conta_pcasp_id.present?) || (!self.precisa_de_subconta? && self.sub_conta_pcasp_id.nil?)) &&
		((self.precisa_de_operacao_de_credito? && self.sub_conta_pcasp_id.present?) || (!self.precisa_de_operacao_de_credito? && self.operacao_de_credito_id.nil?))
	end

	def tipo_de_reconhecimento_correto?
		if Configuracao.last.present? && Configuracao.last.utiliza_evento_contabil?
			lista = ['67', '91', '71', '72', '73', '74', '75', '76', '77']
			elemento = self.elemento_de_despesa.codigo[4..5]
			(lista.include?(elemento) && (self.reconhecido_antes_da_liquidacao_nesse_exercicio? || self.reconhecido_antes_da_liquidacao_exercicio_anterior?)) || (!lista.include?(elemento) && self.reconhecido_na_liquidacao_da_despesa?) || (elemento == '92' && (self.reconhecimento_no_exercicio_anterior? || self.reconhecimento_no_exercicio_vigente?))
		else
			return true
		end
	end

	#VALORES
	def saldo_vigente_do_contrato
		data = data_a_utilizar_no_empenho
		aditivos_de_prazo_do_contrato = contrato.aditivos.confirmados.aditivos_de_prazo.where('licitacao_aditivos.inicio_da_vigencia <= ? AND licitacao_aditivos.fim_da_vigencia >= ?', data, data)
		
		if !contrato.dentro_da_vigencia_original_do_contrato(data) && aditivos_de_prazo_do_contrato.present? && aditivos_de_prazo_do_contrato.last.itens_do_aditivo.any?
			aditivo_de_acrescimo = contrato.aditivos.confirmados.acrescimo.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', aditivos_de_prazo_do_contrato.last.inicio_da_vigencia, aditivos_de_prazo_do_contrato.last.fim_da_vigencia).sum(&:valor_total)
			aditivo_de_decrescimo = contrato.aditivos.confirmados.reducao.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', aditivos_de_prazo_do_contrato.last.inicio_da_vigencia, aditivos_de_prazo_do_contrato.last.fim_da_vigencia).sum(&:valor_total)
			aditivo_de_prazo_vigente = aditivos_de_prazo_do_contrato.where("inicio_da_vigencia <= ? and fim_da_vigencia >= ?", data, data).first
			aditivo_de_prazo_vigente.valor_total.to_d.round(2) - contrato.valor_empenhado_no_periodo_vigente(data) - contrato.valor_reconhecimento_de_divida_do_periodo_vigente(aditivo_de_prazo_vigente.inicio_da_vigencia) + (aditivo_de_acrescimo - aditivo_de_decrescimo) + valor_dos_aditivos_de_reajuste_de_valor(data)
		else
			data_inicio = contrato.inicio_da_vigencia
			if aditivos_de_prazo_do_contrato.present? && aditivos_de_prazo_do_contrato.last.itens_do_aditivo.size ==  0
				data_fim = aditivos_de_prazo_do_contrato.last.fim_da_vigencia
			else
				data_fim = contrato.fim_da_vigencia
			end
			aditivo_de_acrescimo = contrato.aditivos.confirmados.acrescimo.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', data_inicio, data_fim).sum(&:valor_total)
			aditivo_de_decrescimo = contrato.aditivos.confirmados.reducao.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', data_inicio, data_fim).sum(&:valor_total)
			aditivo_de_acrescimo_ou_decrescimo = aditivo_de_acrescimo - aditivo_de_decrescimo
			contrato.valor_do_contrato.to_d.round(2) - contrato.valor_empenhado_no_periodo_vigente(data) - contrato.valor_reconhecimento_de_divida_do_periodo_vigente(data_fim) + (aditivo_de_acrescimo - aditivo_de_decrescimo) + valor_dos_aditivos_de_reajuste_de_valor(data)
		end
	end

	def valor_ultrapassa_saldo_vigente?
		#soma-se o valor do empenho ao saldo vigente, apenas para fazer o teste se o saldo vigente anterior ao empenho permitiria o total do empenho
		valor_total_do_empenho.to_f.round(2) > (valor_a_empenhar_do_contrato_vigente.to_f.round(2) + valor_total_do_empenho.to_f.round(2))
	end

	def compra_direta?
		aquisicao? && contrato.nil?
	end

	def elemento_de_encargo_social?
		codigos_de_encargos_sociais = ['31900400','31901300', '31911300']
		codigos_de_encargos_sociais.include?(elemento_de_despesa_por_subacao.elemento_de_despesa.codigo)
	end

	def possui_anulacoes?
		anulacoes_do_empenho.any?
	end

	def possui_anulacoes_confirmadas?
		anulacoes_do_empenho.confirmadas.any?
	end

	def possui_anulacoes_confirmadas_no_periodo(data_inicial, data_final)
		anulacoes_do_empenho.select { |anulacao| anulacao.data_da_anulacao >= data_inicial && anulacao.data_da_anulacao <= data_final}.any?(&:confirmado?)
	end

	def obra_possui_medicoes?
		de_uma_obra? && obra.medicoes_da_obra.where(status: [ Contabilidade::MedicaoDaObra.status[:confirmada], Contabilidade::MedicaoDaObra.status[:lancada] ] ).any?
	end

	def de_uma_obra?
		contrato.present? && contrato.obra.present?
	end

	def empenho_de_obra_e_falta_dados?
		self.de_uma_obra? && ((self.obra.obra? && (self.conta_pcasp.nil? || self.uso_do_bem.nil?)) || self.obra.servico? && self.obra.classificacao_do_bem.nil?) && self.confirmado?
	end

	def ordens_de_servicos_do_contrato
		obra.ordens_de_servico.joins(obra: :contrato).where(licitacao_contratos: {id: contrato.id}).all
	end

	def pode_configurar_numero?
		# a pedido da Eduarda, por enquanto a contabilidade também vai poder configurar o número
		#!Configuracao.last.envia_empenho_para_contabilidade && !self.enviado_para_controladoria? && !self.enviado_para_copfin? && !self.enviado_para_contabilidade? && !self.confirmado?
		!self.enviado_para_controladoria? && !self.enviado_para_copfin? && !self.enviado_para_contabilidade? && (self.enviado_ao_sim? == false || (self.enviado_ao_sim? == true && self.solicitado?))
	end

	def elemento_de_despesa_por_subacao_do_tipo_51?
		tipo = Loa::ElementoDeDespesaPorSubacao.find(self.elemento_de_despesa_por_subacao_id).codigo_e_descricao_elemento
		tipo[7..8].eql?("51")
	end

	def possui_pagamento_atrelado_a_conta? conta_bancaria_id
		pagamentos.joins(:contas_bancarias_por_pagamento).where(base_contas_bancarias_por_pagamento: {conta_bancaria_id: conta_bancaria_id}).any?
	end

	# LISTAGEM

	def empenhos_complementares
		Contabilidade::Empenho.where(empenho_origem_id: self.id, empenho_complementar: true)
	end

	def grupo_de_natureza_da_despesa
    sub_elemento_de_despesa = Contabilidade::SubElementoDeDespesa.find(self.sub_elemento_de_despesa_id)
    if sub_elemento_de_despesa
      grupo_natureza_despesa = ::Base::GrupoDeNaturezaDaDespesa.find_by(codigo: sub_elemento_de_despesa.grupo_de_natureza_da_despesa)
    end
  end

	# VALORES
	def valor_total_dos_itens
		# Obtém os itens válidos da associação itens_do_empenho
		itens = self.itens_do_empenho.validos_no_orcamento
		# Se os itens já estiverem carregados, soma a coluna total
		if itens.loaded?
			itens.sum(:total) 
		# Caso contrário, busca todos os itens válidos do banco de dados e soma a coluna total
		else
			self.itens_do_empenho.validos_no_orcamento.sum(:total)
		end
	end

	def definir_valor_do_empenho
		@definir_valor_do_empenho ||=
			if self.descriminacao_obrigatoria_de_itens?
				valor_total_dos_itens.to_d
			else
				self.valor.to_d
			end
	end

	def definir_valor_do_empenho_sem_restos_a_pagar
		if self.descriminacao_obrigatoria_de_itens?
			self.itens_do_empenho.validos_no_orcamento.sum(:total).to_f
		else
			self.valor.to_f
		end
	end

	def valor_total_do_empenho
		definir_valor_do_empenho + self.valor_suplementado.to_f
	end

	def valor_total_do_empenho_sem_restos_a_pagar
		definir_valor_do_empenho_sem_restos_a_pagar + self.valor_suplementado.to_f
	end

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

	def valor_anulado
		anulacoes_do_empenho.confirmadas.sum(:valor)
	end

	def valor_anulado_ate_a_data(data)
		possui_anulacoes_confirmadas? ? anulacoes_do_empenho.where("data_da_anulacao <= ?", data).confirmadas.sum(:valor) : 0
	end

	def valor_anulado_no_periodo(data_inicial, data_final)
		possui_anulacoes_confirmadas_no_periodo(data_inicial, data_final) ? anulacoes_do_empenho.where('data_da_anulacao >= ? AND data_da_anulacao <= ?', data_inicial, data_final).confirmadas.sum(:valor) : 0
	end

	def valor_anulado_da_vigencia
		data = data_a_utilizar_no_empenho
		aditivos_de_prazo_do_contrato = contrato.aditivos.confirmados.por_prazo.where('licitacao_aditivos.inicio_da_vigencia <= ? AND licitacao_aditivos.fim_da_vigencia >= ?', data, data)

		if contrato.dentro_da_vigencia_original_do_contrato(data) || (aditivos_de_prazo_do_contrato.present? && aditivos_de_prazo_do_contrato.last.itens_do_aditivo.size ==  0) || aditivos_de_prazo_do_contrato.blank? || aditivos_de_prazo_do_contrato.nil?
			data_inicio = contrato.inicio_da_vigencia.to_date
			if aditivos_de_prazo_do_contrato.present? && aditivos_de_prazo_do_contrato.last.itens_do_aditivo.size ==  0
				data_fim = aditivos_de_prazo_do_contrato.last.fim_da_vigencia.to_date
			else
				data_fim = contrato.fim_da_vigencia.to_date
			end
		else
			data_inicio = aditivos_de_prazo_do_contrato.last.inicio_da_vigencia.to_date
			data_fim = aditivos_de_prazo_do_contrato.last.fim_da_vigencia.to_date
		end
		contrato.valor_anulado_no_periodo_vigente(data_inicio,data_fim)
	end

	def valor_liquidado
		liquidacoes.valida.sum(:valor)
	end

	def valor_liquidado_ate_a_data(data)
		#liquidacoes.confirmadas_ate_autorizadas.nao_estornada.where("data_da_liquidacao <= ?", data).valida.sum(:valor) if liquidacoes.present?
		liquidacoes.confirmadas_ate_autorizadas.where("data_da_liquidacao <= ?", data).valida.sum(:valor) if liquidacoes.present?
	end

	def valor_liquidado_nao_pago
		liquidacoes.sum(&:valor_a_ser_pago).to_d - valor_liquidado_estornado.to_d
	end

	def valor_liquidado_pago
		liquidacoes.sum(:valor_pago)
	end

	def valor_liquidado_estornado
		estorno_de_liquidacao.sum(&:valor)
	end

	def valor_liquidado_estornado_ate_a_data(data)
		estorno_de_liquidacao.where("data_do_estorno <= ?", data).sum(&:valor)
	end

	def valor_total_liquidado
		valor_liquidado.to_d - valor_liquidado_estornado.to_d
	end

	def valor_total_liquidado_restos_a_pagar(orcamento_id)
		liquidacoes.where(orcamento_id: orcamento_id).sum(&:valor_a_ser_pago)
	end

	def valor_liquidado_pago_restos_a_pagar(orcamento_id)
		liquidacoes.where(orcamento_id: orcamento_id).sum(&:valor_pago)
	end
	
	def valor_liquidado_restos_a_pagar(orcamento_id)
		liquidacoes.where(orcamento_id: orcamento_id).sum(&:valor)
	end

	def saldo_empenhado_a_pagar
		valor_liquidado.to_d - valor_liquidado_estornado.to_d - liquidacoes.sum(&:valor_pago).to_d
	end

	def saldo_empenhado_a_pagar_ate_a_data(data)
		valor_liquidado_ate_a_data(data).to_d - valor_liquidado_estornado_ate_a_data(data).to_d - liquidacoes.where("data_da_liquidacao <= ?", data).sum(&:valor_pago).to_d
	end

	def valor_liquidado_empenhado_a_pagar(data_limite = nil)
		if data_limite.present?
			liquidacoes.confirmadas_ate_autorizadas.do_orcamento.where("data_da_liquidacao <= ?", data_limite).sum(:valor)
		else
			liquidacoes.confirmadas_ate_autorizadas.do_orcamento.sum(:valor)
		end
	end

	def saldo_liquidado_a_pagar(data_limite = nil)
		if data_limite.present?
			valor_liquidado_empenhado_a_pagar(data_limite).to_d - valor_liquidado_estornado_ate_a_data(data_limite).to_d - pagamentos.where("data <= ?", data_limite).sum(&:valor) + pagamentos.map { |i| i.estorno_de_pagamento }.compact.select { |i| i.data_do_estorno <= data_limite }.sum(&:valor).to_d
		else
			valor_liquidado_empenhado_a_pagar.to_d - valor_liquidado_estornado.to_d - pagamentos.ativos.sum(&:valor)
		end
	end

	def saldo
		(valor_total_do_empenho.to_f - valor_anulado.to_f - valor_liquidado.to_f + valor_cancelado_processado_no_orcamento_atual.to_f - valor_cancelado_nao_processado_no_orcamento_atual.to_d + valor_liquidado_estornado.to_f).round(2)
	end

	def saldo_ate_a_data(data)
		(valor_total_do_empenho.to_d - valor_anulado_no_periodo(self.data_do_empenho, data).to_d - valor_liquidado_ate_a_data(data).to_d + valor_cancelado_processado_ate_a_data(data).to_d - valor_cancelado_nao_processado_na_data(data).to_d + valor_liquidado_estornado_ate_a_data(data).to_d)
	end

	def saldo_subempenho(numero_da_liquidacao)
		numero_formatado = numero_da_liquidacao.tr('.', '')
		valor_liquidado_subempenho = liquidacoes.where("CAST(contabilidade_liquidacoes.numero AS bigint) < ?", numero_formatado).sum(:valor)
		valor_liquidado_estornado_subempenho = liquidacoes.where("CAST(contabilidade_liquidacoes.numero AS bigint) < ?", numero_formatado).where(estornada: true).sum(:valor)
		(valor_total_do_empenho - valor_anulado.to_f - valor_liquidado_subempenho.to_f + valor_liquidado_estornado_subempenho.to_f).round(2)
	end

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

	def porcentagem_do_saldo_do_valor_liquidado
		((self.valor_total_liquidado.to_f * 100) / (valor_total_do_empenho.to_f.nonzero? || 1)).round(2)
	end

	def porcentagem_do_saldo_do_valor_liquidado_pago
		((self.valor_liquidado_pago.to_f * 100) / (valor_total_do_empenho.to_f.nonzero? || 1)).round(2)
	end

	def valor_total_ordens_de_compra
		self.ordens_de_compra.valido.to_a.sum(&:valor_total).to_f
	end

	def valor_total_ordens_de_compra_recebida_parcial_ou_total
		self.ordens_de_compra.sum(&:recebimento_de_materiais).select{|rec| rec.status == 'recebido_parcialmente' || rec.status == 'recebido' }.to_a.sum(&:valor_total_do_recebimento).to_f
	end

	def valor_total_empenhos_vinculados_ao_recebimento
		self.empenhos_do_recebimento.to_a.sum(&:valor).to_f
	end

	def saldo_para_ordem_de_compra
		self.valor_total_do_empenho.to_f - valor_anulado.to_f - valor_total_ordens_de_compra - valor_total_empenhos_vinculados_ao_recebimento
	end

	def saldo_para_recebimento_multiplos
		self.valor_total_do_empenho.to_f - valor_anulado.to_f - valor_total_ordens_de_compra_recebida_parcial_ou_total - valor_total_empenhos_vinculados_ao_recebimento
	end

	def saldo_da_dotacao_antes_do_empenho
		orcamento_da_despesa_id = self.orcamento_da_despesa.id
		lancamento_do_orcamento_da_despesa = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Contabilidade::Empenho", modulo_id: self.id).last

		if lancamento_do_orcamento_da_despesa.present?
			lancamento_do_orcamento_da_despesa.saldo_antes_do_lancamento.to_f
		else
			lancamentos_do_orcamento_da_despesa = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Loa::OrcamentoDaDespesa")
			saldo_orcamento = lancamentos_do_orcamento_da_despesa.nil? ? 0 : lancamentos_do_orcamento_da_despesa.sum(&:valor)

			lancamentos_do_orcamento_da_despesa_dos_empenhos = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Contabilidade::Empenho").where.not(modulo_id: self.id)
			valor_empenhado = lancamentos_do_orcamento_da_despesa_dos_empenhos.nil? ? 0 : lancamentos_do_orcamento_da_despesa_dos_empenhos.sum(&:valor)

			saldo = (saldo_orcamento - valor_empenhado).to_f
		end
	end

	def saldo_da_dotacao_apos_o_empenho
		orcamento_da_despesa_id = self.orcamento_da_despesa.id
		lancamento_do_orcamento_da_despesa = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Contabilidade::Empenho", modulo_id: self.id).last

		if lancamento_do_orcamento_da_despesa.present?
			lancamento_do_orcamento_da_despesa.saldo_ate_o_lancamento.to_f
		else
			lancamentos_do_orcamento_da_despesa = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Loa::OrcamentoDaDespesa")
			saldo_orcamento = lancamentos_do_orcamento_da_despesa.nil? ? 0 : lancamentos_do_orcamento_da_despesa.sum(&:valor)

			lancamentos_do_orcamento_da_despesa_dos_empenhos = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(orcamento_da_despesa_id: orcamento_da_despesa_id, modulo_type: "Contabilidade::Empenho")
			valor_empenhado = lancamentos_do_orcamento_da_despesa_dos_empenhos.nil? ? 0 : lancamentos_do_orcamento_da_despesa_dos_empenhos.sum(&:valor)

			saldo = (saldo_orcamento - valor_empenhado).to_f
		end
	end

	def valor_do_processo_a_contratar
		projeto.try(:valor_a_contratar)
	end

	def quantidade_total_por_item(item_do_empenho)
		itens_do_empenho.select("sum(quantidade) as quantidade_total").group("item_do_empenho.item_id")
	end

	def valor_dos_aditivos_de_reajuste_de_valor data
		valor_dos_aditivos_de_reajuste_de_valor = 0
		aditivo_vigente = contrato.aditivo_de_prazo_vigente(data)
		if !contrato.dentro_da_vigencia_original_do_contrato(data) && aditivo_vigente.present? && aditivo_vigente.itens_do_aditivo.size > 0
			data_inicio_do_aditivo_vigente = aditivo_vigente.inicio_da_vigencia.to_date
			data_fim_do_aditivo_vigente = aditivo_vigente.fim_da_vigencia.to_date
			valor_de_reajuste_de_acrescimo = contrato.aditivos.confirmados.reajuste_de_valor_acrescimo.where('licitacao_aditivos.inicio_da_vigencia >= ? AND licitacao_aditivos.inicio_da_vigencia <= ? ', data_inicio_do_aditivo_vigente, data_fim_do_aditivo_vigente).to_a.sum(&:valor_total).to_f
			valor_de_reajuste_de_decrescimo = contrato.aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia >= ? AND licitacao_aditivos.inicio_da_vigencia <= ? ', data_inicio_do_aditivo_vigente, data_fim_do_aditivo_vigente).to_a.sum(&:valor_total).to_f
		else
			if aditivo_vigente.present? && aditivo_vigente.itens_do_aditivo.size == 0
				data_fim = aditivo_vigente.fim_da_vigencia.to_date
			else
				data_fim = contrato.fim_da_vigencia
			end
			valor_de_reajuste_de_acrescimo = contrato.aditivos.confirmados.reajuste_de_valor_acrescimo.where('licitacao_aditivos.inicio_da_vigencia <= ? ',data_fim).to_a.sum(&:valor_total).to_f
			valor_de_reajuste_de_decrescimo = contrato.aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia <= ? ',data_fim).to_a.sum(&:valor_total).to_f
		end

		valor_dos_aditivos_de_reajuste_de_valor = valor_de_reajuste_de_acrescimo - valor_de_reajuste_de_decrescimo
		return valor_dos_aditivos_de_reajuste_de_valor.to_f
	end

	def data_a_utilizar_no_empenho
		if self.reconhecimento_de_divida?
			if aditivo.nil?
				data = contrato.fim_da_vigencia.to_date
			else
				data = aditivo.fim_da_vigencia.to_date
			end
		else
			data = confirmado? ? data_do_empenho : data_de_solicitacao
		end
		return data
	end

	# AÇÕES

	def verifica_se_elemento_de_despesa_92
		if self.elemento_de_despesa.present?
			if( self.elemento_de_despesa.codigo[4..5].eql?( "92") )
				self.reconhecimento_de_divida = true
			end
		end
	end

	def remove_descriminacao_sem_projeto_e_contrato
		update_attribute(:descrimina_itens_processo_ou_contrato, false) if self.projeto_id.nil? && self.contrato_id.nil?
	end

	def limpa_processo_contrato_quando_vincula_processo_contrato
		if self.vincula_processo_contrato?
			self.modalidade_processo = nil
			self.legislacao_processo = nil
			self.numero_processo = nil
			self.numero_contrato = nil
		else
			self.projeto_id = nil
			self.contrato_id = nil
		end
	end

	def duplica_empenho
		empenho = self.dup

		empenho.empenho_origem_id = self.id
		empenho.data_do_empenho = Date.today unless Rails.env.test?
		empenho.data_de_solicitacao = Date.today unless Rails.env.test?
		empenho.status = 'solicitado'
		empenho.numero_do_empenho = nil
		empenho.arquivo_id = nil

		return empenho.save!
	end

	def duplica_restos_a_pagar(exercicio)
		empenho_original = self
		ids_itens_com_saldo_do_empenho_original = empenho_original.itens_do_empenho.map{|item| item.id if item.quantidade_disponivel_a_liquidar > 0}.compact

		Contabilidade::ItemDoEmpenho.where(id: ids_itens_com_saldo_do_empenho_original).each do |item|
			total_item = -(item.quantidade_disponivel_a_liquidar * item.valor_unitario)
			novo_item = empenho_original.itens_do_empenho.new(item_id: item.item_id, quantidade: -item.quantidade_disponivel_a_liquidar, valor_unitario: item.valor_unitario, total: total_item)
			novo_item.save(validate: false)
		end

		empenho = empenho_original.dup

		empenho.empenho_origem_id = empenho_original.id
		empenho.restos_a_pagar = true
		empenho.valor = empenho_original.valor
		empenho.valor_liquidado = 0
		empenho.save(validate: false)

		if empenho_original.itens_do_empenho.any?
			empenho_original.itens_do_empenho.validos_no_orcamento.each do |item|
				novo_item = empenho.itens_do_empenho.new(item_id: item.item_id, quantidade: item.quantidade, valor_unitario: item.valor_unitario, total: item.total)
				novo_item.save(validate: false)
			end
		end

		if empenho_original.liquidacoes.any?
			empenho_original.liquidacoes.each do |liquidacao|
				unless liquidacao.totalmente_pago?
					liquidacao_nova = liquidacao.dup

					liquidacao_nova.empenho_id = empenho.id
					if liquidacao.pagamentos.any?
						liquidacao_nova.valor_pago_em_rp = liquidacao.pagamentos.sum(:valor)
					else
						liquidacao_nova.valor_pago_em_rp = 0
					end
					liquidacao_nova.restos_a_pagar = true
					liquidacao_nova.save(validate: false)

					liquidacao.itens_da_nota_fiscal.each do |item_da_liquidacao|
						item_novo = Contabilidade::ItemDaNotaFiscal.new(liquidacao_id: liquidacao_nova.id, quantidade: item_da_liquidacao.quantidade, valor_unitario: item_da_liquidacao.valor_unitario, item_id: item_da_liquidacao.item_id, total: item_da_liquidacao.total, ncm_id: item_da_liquidacao.ncm_id)
						item_novo.save(validate: false)
					end
				end
			end
		end

		if empenho_original.anulacoes_do_empenho.confirmadas.any?
			empenho_original.anulacoes_do_empenho.confirmadas.each do |anulacao|
				nova_anulacao = anulacao.dup
				nova_anulacao.empenho_id = empenho.id
				nova_anulacao.save(validate: false)

				anulacao.itens_anulados.valido.each do |item_da_anulacao|
					novo_item_da_anulacao = item_da_anulacao.dup
					item_do_empenho_original = Contabilidade::ItemDoEmpenho.find(item_da_anulacao.item_do_empenho_id)
					item_do_novo_empenho =  empenho.itens_do_empenho.find_by(item_id: item_do_empenho_original.item_id)
					novo_item_da_anulacao.item_do_empenho_id = item_do_novo_empenho.id
					novo_item_da_anulacao.anulacao_do_empenho_id = nova_anulacao.id
					novo_item_da_anulacao.save(validate: false)
				end
			end
		end

		if empenho_original.contas_unidade_por_empenho.any?
			empenho_original.contas_unidade_por_empenho.each do |conta|
				nova_conta = conta.dup
				nova_conta.empenho_id = empenho.id
				nova_conta.save(validate: false)
			end
		end

		empenho.numero_do_empenho = empenho_original.numero_do_empenho
		return empenho.save(validate: false)
	end

	def cria_restos_a_pagar
		ids_itens_com_saldo = self.itens_do_empenho.map{|item| item.id if item.quantidade_disponivel_a_liquidar > 0}.compact

		Contabilidade::ItemDoEmpenho.where(id: ids_itens_com_saldo).each do |item|
			total_item = -(item.quantidade_disponivel_a_liquidar * item.valor_unitario)
			novo_item = self.itens_do_empenho.new(item_id: item.item_id, quantidade: -item.quantidade_disponivel_a_liquidar, valor_unitario: item.valor_unitario, total: total_item)
			novo_item.save(validate: false)
		end

		empenho = self.dup

		empenho.empenho_origem_id = self.id
		empenho.restos_a_pagar = true
		empenho.valor = self.valor
		empenho.valor_liquidado = 0
		empenho.save(validate: false)

		if self.itens_do_empenho.any?
			self.itens_do_empenho.validos_no_orcamento.each do |item|
				novo_item = empenho.itens_do_empenho.new(item_id: item.item_id, quantidade: item.quantidade, valor_unitario: item.valor_unitario, total: item.total)
				novo_item.save(validate: false)
			end
		end

		if self.liquidacoes.any?
			self.liquidacoes.each do |liquidacao|
				liquidacao_nova = liquidacao.dup

				liquidacao_nova.empenho_id = empenho.id
				if liquidacao.pagamentos.any?
					liquidacao_nova.valor_pago_em_rp = liquidacao.pagamentos.sum(:valor)
				else
					liquidacao_nova.valor_pago_em_rp = 0
				end
				liquidacao_nova.restos_a_pagar = true
				liquidacao_nova.nao_faz_duplicada_de_rp = true
				liquidacao_nova.save(validate: false)

				liquidacao_nova.retencoes_folha.each do |retencao|
					retencao_nova = retencao.dup
					retencao_nova.liquidacao_id = liquidacao_nova.id
					retencao_nova.save(validate: false)
				end

				if liquidacao.nota_fiscal.present?
					nota_fiscal_nova = liquidacao.nota_fiscal.dup
					nota_fiscal_nova.liquidacao_id = liquidacao_nova.id

					if nota_fiscal_nova.save(validate: false)

						liquidacao.nota_fiscal.retencoes.each do |retencao|
							retencao_nova = retencao.dup
							retencao_nova.nota_fiscal_id = nota_fiscal_nova.id
							retencao_nova.save(validate: false)
						end
						
						liquidacao.itens_da_nota_fiscal.each do |item_da_liquidacao|
							item_da_liquidacao_novo = liquidacao_nova.itens_da_nota_fiscal.find_by(item_id: item_da_liquidacao.item_id)

							unless item_da_liquidacao_novo.present?
								item_da_liquidacao_novo = item_da_liquidacao.dup
								item_da_liquidacao_novo.liquidacao_id = liquidacao_nova.id
								item_da_liquidacao_novo.save(validate: false)
							end
						end
					end
				end

			end
		end

		if self.anulacoes_do_empenho.confirmadas.any?
			self.anulacoes_do_empenho.confirmadas.each do |anulacao|
				nova_anulacao = anulacao.dup
				nova_anulacao.empenho_id = empenho.id
				nova_anulacao.save(validate: false)

				anulacao.itens_anulados.valido.each do |item_da_anulacao|
					novo_item_da_anulacao = item_da_anulacao.dup
					item_do_empenho_original = Contabilidade::ItemDoEmpenho.find(item_da_anulacao.item_do_empenho_id)
					item_do_novo_empenho =  empenho.itens_do_empenho.find_by(item_id: item_do_empenho_original.item_id)
					novo_item_da_anulacao.item_do_empenho_id = item_do_novo_empenho.id
					novo_item_da_anulacao.anulacao_do_empenho_id = nova_anulacao.id
					novo_item_da_anulacao.save(validate: false)
				end
			end
		end

		if self.contas_unidade_por_empenho.any?
			self.contas_unidade_por_empenho.each do |conta|
				nova_conta = conta.dup
				nova_conta.empenho_id = empenho.id
				nova_conta.save(validate: false)
			end
		end

		empenho.numero_do_empenho = self.numero_do_empenho
		return empenho.save(validate: false)
	end

	def pode_criar_restos_a_pagar?(exercicio)
		Contabilidade::Empenho.where(empenho_origem_id: self.id, orcamento: exercicio.id, restos_a_pagar: true).any?
	end

	def itens_validos_do_empenho
		self.itens_do_empenho.validos_no_orcamento
	end

	def origem
		contrato || projeto
	end

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

	def itens_dos_lotes_do_ganhador
		if compra_direta?
			projeto.itens_dos_lotes.joins(:lote).where(licitacao_lotes: {ganhador_id: self.pessoa_id})
		end
	end

	def numero_do_contrato
		self.contrato.numero if !compra_direta? && contrato.present?
	end

	def numero_e_contratado
		"#{self.numero_do_empenho + " - " + self.contrato.contratado.pessoa.nome}"
	end

	def numero_e_fornecedor
		"#{self.numero_do_empenho.to_s + " - " + self.pessoa.nome.to_s}"
	end

	def numero_do_processo
		if compra_direta?
			self.projeto.numero_do_processo
		end
	end

	def detalhamento_do_plano_de_contas
		"#{unidade_orcamentaria.try(:codigo_completo)}
		#{orcamento_da_despesa.subacao.funcao.try(:codigo)}
		#{orcamento_da_despesa.subacao.subfuncao.try(:codigo)}
		#{orcamento_da_despesa.acao.programa_de_governo.try(:codigo)}
		#{orcamento_da_despesa.acao.try(:codigo_completo)}
		#{orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.try(:codigo_formatado)}
		#{orcamento_da_despesa.fonte_de_recursos.try(:codigo_completo)}"
	end

	def categorias_dos_itens
		self.itens_do_empenho.map(&:categoria_do_item).flatten
	end

	def retorna_conta_bancaria_por_unidade conta_bancaria_id
		::Base::ContaBancariaPorUnidadeOrcamentaria.find_by(unidade_orcamentaria_id: unidade_orcamentaria.try(:id), conta_bancaria_id: conta_bancaria_id)
	end

	def conta_bancaria_com_a_mesma_do_empenho
		self.contas_unidade_por_empenho.select{ |conta| self.retorna_conta_bancaria_por_unidade(conta.conta_unidade.id) }.any?
	end

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

	def anula_pessoa_conta_bancaria
		unless self.obrigatoriedade_conta_credor?
			self.pessoa_conta_bancaria = nil
		end
	end

	def atualiza_e_confirma_numero_do_empenho(numero_do_empenho, data_do_empenho)
		numero_do_empenho.insert(0, "0" * (8 - numero_do_empenho.size) )
		empenho_existente = Contabilidade::Empenho.find_by('contabilidade_empenhos.numero_do_empenho = ? and contabilidade_empenhos.id != ? and contabilidade_empenhos.orcamento_id = ?', numero_do_empenho, self.id, self.orcamento_id)

		if (empenho_existente.present? && empenho_existente.confirmado?)
			errors.add(:numero_do_empenho, "Codigo já esá em uso")
			return false
		elsif existe_lote_do_sim?(data_do_empenho)
			errors.add(:sim, "O SIM do mês já foi enviado")
			return false
		elsif self.mes_bloqueado?
			errors.add(:sim, 'O mês do objeto está bloqueado, solicite o desbloqueio ao administrador')
			return false
		elsif empenho_existente.blank? || (empenho_existente.present? && !empenho_existente.confirmado?)
			self.update_attributes(numero_do_empenho: numero_do_empenho, data_do_empenho: data_do_empenho, numero_confirmado: true)

			if !self.valid?
				errors.add(:numero_do_empenho, self.errors.full_messages.to_sentence)
				return false
			end
			return true
		end
	end

	def precisa_de_subconta?
		#se for de elementos de precatorio ou obrigações precisa da subconta
		elementos_que_precisam = ['67', '91', '71', '72', '73', '74', '75', '76', '77']
		tipos = ['Reconhecido Antes da Liquidação Nesse Exercício', 'Reconhecido Antes da Liquidação Exercício Anterior']
		if elementos_que_precisam.include?(self.orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[4..5]) || tipos.include?(self.tipo_de_reconhecimento_do_passivo_i18n)
			true
		else
			false
		end
	end

	def precisa_de_operacao_de_credito?
		self.orcamento_da_despesa.elemento_de_despesa_por_subacao.elemento_de_despesa.codigo[0..4] == "46907"
	end

	def atualiza_subconta_do_empenho(subconta, movimento)
		if !self.confirmado? && !self.anulado?
			self.update_attributes(sub_conta_pcasp_id: subconta, movimentacao_do_plano_de_contas_id: movimento)
			return true
		else
			return false
		end
	end

	def atualiza_op_do_empenho(operacao_de_credito)
		if !self.confirmado? && !self.anulado?
			self.update_attributes(operacao_de_credito_id: operacao_de_credito.id, sub_conta_pcasp_id: operacao_de_credito.sub_conta_pcasp_id, pessoa_id: operacao_de_credito&.financiador_id)
			return true
		else
			return false
		end
	end
	
	def atualiza_e_confirma_numero_de_solicitacao_do_empenho(numero_do_empenho, data_do_empenho)
		empenho_existente = Contabilidade::Empenho.find_by('contabilidade_empenhos.numero_da_solicitacao_do_empenho = ? and contabilidade_empenhos.id != ? and contabilidade_empenhos.orcamento_id = ?', numero_do_empenho, self.id, self.orcamento_id)

		if empenho_existente.present? && empenho_existente.confirmado?
			errors.add(:numero_da_solicitacao_do_empenho, "Codigo já esá em uso")
			return false
		elsif empenho_existente.blank? || (empenho_existente.present? && !empenho_existente.confirmado?)
			self.update_attributes(numero_da_solicitacao_do_empenho: numero_do_empenho, data_de_solicitacao: data_do_empenho, numero_confirmado: true)
			return true
		end
	end

	def valor_restante_da_dotacao
		self.orcamento_da_despesa.saldo.to_f + self.definir_valor_do_empenho.to_f
	end

	def dotacao_do_empenho_possui_saldo?
		saldo_do_dia = 0
		if self.data_do_empenho.present?
			saldo_do_dia = self.orcamento_da_despesa.saldo_da_dotacao_por_data(self.data_do_empenho)
		else
			saldo_do_dia = self.orcamento_da_despesa.saldo_da_dotacao_por_data(self.data_de_solicitacao)
		end
		(saldo_do_dia.to_d - self.definir_valor_do_empenho.to_d >= 0) && (self.orcamento_da_despesa.saldo.to_d - self.definir_valor_do_empenho.to_d >= 0)
	end

	def valor_comprometido_da_dotacao_passa_saldo_total?
		(self.orcamento_da_despesa.saldo.to_f.round(2) - self.orcamento_da_despesa.valor_comprometido_com_empenhos.to_f.round(2)) < 0
	end

	def valor_do_defict_do_orcamento
		self.orcamento_da_despesa.saldo.to_f - self.definir_valor_do_empenho.to_f
	end

	# VALIDAÇÕES
	def valida_saldo_update
		lancamentos = self.orcamento_da_despesa.lancamentos_do_orcamento_da_despesa.order(:data_do_lancamento)
		valor_saldo_da_dotacao = self.orcamento_da_despesa.valor.to_d + lancamentos.where("modulo_type = 'Contabilidade::DotacaoDestino'").sum(&:valor).to_d - lancamentos.where("modulo_type <> 'Contabilidade::DotacaoDestino' AND modulo_type <> 'Loa::OrcamentoDaDespesa'").sum(&:valor).to_d
		lancamento_do_empenho = lancamentos.find_by(modulo: self)

		if lancamento_do_empenho.present?
			valor_saldo_da_dotacao = valor_saldo_da_dotacao.to_d + lancamento_do_empenho.valor.to_d
		end

		if (self.definir_valor_do_empenho.to_d > valor_saldo_da_dotacao.to_d) && Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho).present?
			errors.add(:valor, "A dotação escolhida não possui saldo suficiente")
		end
	end

	def valida_elemento_de_despesa_para_contrato_de_obra
		if !sub_elemento_de_despesa.elemento_de_despesa.obra? && self.contrato.vigente_na_data(self.data_de_solicitacao)
			errors.add(:elemento_de_despesa_por_subacao_id, "Para empenhos de Contratos de Obra, o elemento de despesa deve ser o 51")
		end
	end

	def valida_dea_para_contrato_de_obra
		if !sub_elemento_de_despesa.elemento_de_despesa.reconhecimento_de_divida? && !self.contrato.vigente_na_data(self.data_de_solicitacao) && !self.retificadora?
			errors.add(:elemento_de_despesa_por_subacao_id, "Para empenho de DEA, o elemento de despesa deve ser o 92")
		end
	end

	def valida_fornecedor_com_o_elemento_de_despesa
		cod_elemento = self.sub_elemento_de_despesa.elemento_de_despesa.codigo.to_s[4..5]
		cod_subelemento = self.sub_elemento_de_despesa.codigo

		if cod_elemento.include?("36") && !self.pessoa.pessoa_fisica?
			errors.add(:pessoa_id, "Para o Elemento 36, o Fornecedor deve ser pessoa Física") unless (cod_subelemento == "45" || (self.sub_elemento_de_despesa.elemento_de_despesa.codigo == "33903600" && cod_subelemento == "99") || (cod_subelemento == "07" && empenho_de_folha?))
		end

		elementos_juridicos = ["33", "37", "40"] #removido a pedido do isaac o 39
		errors.add(:pessoa_id, "Para o Elemento #{cod_elemento}, o Fornecedor deve der pessoa Jurídica") if elementos_juridicos.include?(cod_elemento) && !self.pessoa.pessoa_juridica?
	end

	def valor_a_empenhar_do_contrato_com_aditivos
		data = confirmado? ? data_do_empenho : data_de_solicitacao
		valor_de_reajuste_de_acrescimo = contrato.aditivos.confirmados.reajuste_de_valor_acrescimo.where('licitacao_aditivos.inicio_da_vigencia < ? OR licitacao_aditivos.inicio_da_vigencia = ?', data.to_date,data.to_date).to_a.sum(&:valor_total).to_f
		valor_de_reajuste_de_decrescimo = contrato.aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia < ? OR licitacao_aditivos.inicio_da_vigencia = ?', data.to_date,data.to_date).to_a.sum(&:valor_total).to_f

		valor_total_do_contrato = contrato.valor_do_contrato + contrato.valor_dos_aditivos + (valor_de_reajuste_de_acrescimo - valor_de_reajuste_de_decrescimo) + contrato.valor_dos_aditivos_de_prorrogacao.to_f
		return valor_total_do_contrato.round(2) - contrato.valor_empenhado.round(2)
	end

	def valor_a_empenhar_do_contrato_vigente
		if self.aditivo_id.present? && self.aditivo.prazo_com_itens?
			return aditivo.valor_a_empenhar
		else
			if Configuracao.last.controlar_empenho_por_vigencia?
				valor_anulado = self.contrato.empenhos.where(descrimina_itens_processo_ou_contrato: true).any? ? saldo_anulado_na_vigencia_sem_aditivo : contrato.valor_anulado
				saldo_vigente_do_contrato_sem_aditivo.to_d + valor_anulado_da_vigencia.to_d  rescue 0
			else
				saldo_vigente_do_contrato.round(2).to_d + valor_anulado_da_vigencia.to_d rescue 0
			end
		end
	end

	def valor_a_ser_empenhado
		if projeto.present?
			if aditivo.present?
				self.aditivo.valor_a_empenhar.to_f
			elsif contrato.present? && self.reconhecimento_de_divida?
				self.contrato.saldo_reconhecimento_de_divida.to_f
			elsif contrato.present? && (data_do_empenho.present? || data_de_solicitacao.present?)
				self.valor_a_empenhar_do_contrato_com_aditivos.to_f
			else
				self.projeto.valor_a_contratar.to_f
			end
		end
	end

	def contrato_vigente_do_empenho
		if Configuracao.last.controlar_empenho_por_vigencia?
			contrato_ou_aditivo_na_vigencia = self.aditivo_id.present? ? self.contrato : self.aditivo
		else
			if (self.data_do_empenho.present? && self.contrato.fim_da_vigencia >= self.data_do_empenho) || (!self.data_do_empenho.present? && self.contrato.fim_da_vigencia >= self.data_de_solicitacao)
				contrato_ou_aditivo_na_vigencia = self.contrato
			else
				if self.data_do_empenho.present?
					contrato_ou_aditivo_na_vigencia = self.contrato.aditvos.where('inicio_da_vigencia <= ? AND fim_da_vigencia >= ?', self.data_do_empenho, self.data_do_empenho).last
				else
					contrato_ou_aditivo_na_vigencia = self.contrato.aditvos.where('inicio_da_vigencia <= ? AND fim_da_vigencia >= ?', self.data_de_solicitacao, self.data_de_solicitacao).last
				end
			end
		end
	end

	def modalidade_para_o_sim
		if ordinario?
			return "O"
		elsif global?
			return "G"
		elsif estimativo?
			return "E"
		end
	end

	def quantidade_disponivel_na_origem_da_compra
		self.itens_do_empenho.to_a.sum(&:quantidade_disponivel).to_f - self.ordens_de_compra.valido.joins(:itens_da_ordem_de_compra).sum(:quantidade).to_f
	end

	def aquisicao_de_imoveis?
		self.orcamento_da_despesa.elemento_de_despesa.categoria == "61" rescue false
	end

	def nome_do_bem
		Contabilidade::Conta.find_by(id: self.tipo_do_bem_do_empenho).nome rescue ""
	end

	def retorna_codigo_disponivel
		atribui_codigo_disponivel
		self.numero_do_empenho
	end

	def retorna_codigo_solicitacao
		atribui_codigo_solicitacao
		self.numero_da_solicitacao_do_empenho
	end

	def saldo_vigente_do_contrato_sem_aditivo
		saldo_do_contrato = self.contrato.itens_do_contrato.map { |item_do_contrato| item_do_contrato.valor_total }.sum
		saldo_empenhado = self.contrato.valor_empenhado_sem_aditivo
		saldo_de_acrescimo = self.contrato.aditivos.confirmados.de_acrescimo.to_a.sum(&:valor_total)
		saldo_do_contrato - saldo_empenhado + saldo_de_acrescimo
	end

	def saldo_anulado_na_vigencia_sem_aditivo
		self.contrato.itens_do_contrato.map { |item_do_contrato| item_do_contrato.itens_dos_empenho_descriminados_sem_aditivo.joins(:empenho).sum(&:quantidade_anulada) * item_do_contrato.valor_unitario.to_f.round(2) }.sum
	end

	def saldo_cancelado_em_rp_nao_processado
		self.contrato.itens_do_contrato.map { |item_do_contrato| item_do_contrato.valor_do_item_em_rp_cancelado_nao_processado.to_f.round(2) }.sum
	end

	def saldo_cancelado_em_rp_nao_processado_na_vigencia
		contrato_vigente = contrato_vigente_do_empenho
		data_de_inicio_vigente = contrato_vigente.inicio_da_vigencia
		data_de_fim_da_vigencia = contrato_vigente.fim_da_vigencia

		empenhos_de_rp_cancelados = contrato.empenhos.joins(restos_a_pagar_cancelados: :cancelamento_de_resto_a_pagar)
			.where('contabilidade_cancelamentos_de_restos_a_pagar.tipo = 0
				AND contabilidade_cancelamentos_de_restos_a_pagar.data >= ?
				AND contabilidade_cancelamentos_de_restos_a_pagar.data <= ?', data_de_inicio_vigente, data_de_fim_da_vigencia)

		empenhos_de_rp_cancelados.map { |item_do_empenho| item_do_empenho.valor_cancelado_em_rp_nao_processado.to_f.round(2) }.sum
	end

	def codigo_disponivel_para_solicitacao(data_da_solicitacao, solicitacao)
		if solicitacao == "true"
			codigos_utilizados = Contabilidade::Empenho.where(orcamento_id:  self.orcamento_id)
			.where("numero_da_solicitacao_do_empenho like '#{data_da_solicitacao}%'")
			.where.not(id: self.id)
			.order(:numero_da_solicitacao_do_empenho)
			.pluck(:numero_da_solicitacao_do_empenho)
			.map{ |codigo|
				if codigo.to_s.length == 8
					if codigo.to_s[0..3] == data_da_solicitacao
						codigo.to_s[4..7]
					end
				else
					codigo_aux = "0" + codigo.to_s[0..2]
					if codigo_aux == data_da_solicitacao
						codigo.to_s[3..6]
					end
				end
			}
		else
			codigos_utilizados = Contabilidade::Empenho.where(orcamento_id:  self.orcamento_id)
			.where("numero_do_empenho like '#{data_da_solicitacao}%'")
			.where.not(id: self.id)
			.order(:numero_do_empenho)
			.pluck(:numero_do_empenho)
			.map{ |codigo|
				if codigo.to_s.length == 8
					if codigo.to_s[0..3] == data_da_solicitacao
						codigo.to_s[4..7]
					end
				else
					codigo_aux = "0" + codigo.to_s[0..2]
					if codigo_aux == data_da_solicitacao
						codigo.to_s[3..6]
					end
				end
			}
		end

		if codigos_utilizados.compact.empty?
			numero_solicitado = "#{data_da_solicitacao}0001"
		else
			codigos_disponiveis = (1..codigos_utilizados.compact.sort.last.to_i + 1).to_a - codigos_utilizados.compact.map(&:to_i)
			numero_solicitado =  "#{data_da_solicitacao}#{codigos_disponiveis.first.digitos(4)}"
		end

		return numero_solicitado
	end

	def empenho_de_consumo_ou_material_permanente?
		( self.elemento_de_despesa.codigo == "33903000" || self.elemento_de_despesa.codigo == "44903000" ) || ( self.elemento_de_despesa.codigo == "44905200" )
	end
	def sub_elemento_sem_evento
		if self.sub_elemento_de_despesa.present? && self.sub_elemento_de_despesa.orcamentos_da_despesa_por_evento_contabil.empty?
			#errors.add(:sub_elemento_de_despesa_id, "O Subelemento escolhido no empenho deve ser vinculado a um Evento Contábil.")
		end
	end

	def empenho_de_diaria_deve_possuir_diaria
		configuracao = Configuracao.last
		if configuracao.usa_modulo_contabil? && configuracao.envia_sim_contabilidade? && diaria? && diaria_id.nil?
			errors.add(:elemento_de_despesa_por_subacao_id, "Não foi possível cadastrar empenho sem vínculo com a diária.")
		end
	end

	def valida_empenho_de_contratacao_por_tempo_determinado
		if self.sub_elemento_de_despesa.codigo == "15"
			if self.encargos_sociais == false
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for da dotação 3.1.90.04.15, ele deve ser Encargos Sociais.")
			end
			if self.envia_detalhamento_folha_ao_sim == true
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for da dotação 3.1.90.04.15, ele não pode ter Detalhamento de Folha enviado ao SIM.")
			end
			if !self.pessoa&.nome&.to_s.upcase.include?("INSS")
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for da dotação 3.1.90.04.15, ele deve ter credor INSS.")
			end
		else
			if self.encargos_sociais == true
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for do elemento 3.1.90.04.00 se subelemento diferente de 15, ele não deve ser Encargos Sociais.")
			end
			if self.envia_detalhamento_folha_ao_sim == false
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for do elemento 3.1.90.04.00 se subelemento diferente de 15, ele deve ter Detalhamento de Folha enviado ao SIM.")
			end
			if self.pessoa&.tipo_de_pessoa&.descricao.to_s != "Folha de Pagamento"
				errors.add(:sub_elemento_de_despesa_id, "Se o empenho for do elemento 3.1.90.04.00 se subelemento diferente de 15, ele deve ter credor Folha de Pagamento.")
			end
		end
	end

	def valida_obrigatoriedade_sub_conta_e_movimentacao_pcasp
		elementos = ['67', '71', '72', '73', '74', '75', '76', '77','91']

		if !self.operacao_de_credito_id.present? && (elementos.include?(self.sub_elemento_de_despesa.elemento_de_despesa.codigo.to_s[4..5]) ||  self.reconhecido_antes_da_liquidacao_nesse_exercicio? || self.reconhecido_antes_da_liquidacao_exercicio_anterior?)
			errors.add(:sub_conta_pcasp_id, "Campo obrigatório para o elemento selecionado") if self.sub_conta_pcasp.nil?
			errors.add(:movimentacao_do_plano_de_contas_id, "Campo obrigatório para o elemento selecionado") if self.movimentacao_do_plano_de_contas_id.nil?
		end
	end

	def valida_tipo_de_pessoa_no_elemento_36
		elemento_de_despesa = Loa::ElementoDeDespesaPorSubacao.find(elemento_de_despesa_por_subacao_id).try(:elemento_de_despesa)
		if elemento_de_despesa.present? && ( elemento_de_despesa.codigo.eql?("33903600") || elemento_de_despesa.codigo.eql?("44903600") ) && !['45', '99'].include?(self.sub_elemento_de_despesa.codigo.to_s)
			errors.add(:pessoa_id, "Pessoa precia ser física no elemento de despesa #{elemento_de_despesa.codigo_formatado}") unless self.pessoa.pessoa_fisica?
		end
	end

	def valida_tipo_de_pessoa_no_elemento_39
		elemento_de_despesa = Loa::ElementoDeDespesaPorSubacao.find(elemento_de_despesa_por_subacao_id).try(:elemento_de_despesa)
		if elemento_de_despesa.present? && ( elemento_de_despesa.codigo.eql?("33903900") || elemento_de_despesa.codigo.eql?("33913900") || elemento_de_despesa.codigo.eql?("44903900") )
			errors.add(:pessoa_id, "Pessoa precia ser jurídica no elemento de despesa #{elemento_de_despesa.codigo_formatado}") unless self.pessoa.pessoa_juridica?
		end
	end

	def lancar_ocorrencia_da_troca_bancaria
		Contabilidade::OcorrenciaDoEmpenho.create(
			empenho_id: self.id,
			ocorrencia: "troca_de_conta_bancaria",
			pessoa_conta_bancaria_antiga_id: self.pessoa_conta_bancaria_id_was,
			pessoa_conta_bancaria_nova_id: self.pessoa_conta_bancaria_id
		).save(validate: false)
	end

	def verifica_se_e_alteracao_orcamentaria
		saldo_da_dotacao = self.orcamento_da_despesa.try(:saldo).to_f + self.orcamento_da_despesa.lancamentos_do_orcamento_da_despesa.where(modulo_type: 'Contabilidade::Empenho', modulo_id: self.id).first.valor

		if self.valor.present? && (saldo_da_dotacao > self.definir_valor_do_empenho ) && logado_na_contabilidade.present?
			self.status = 'confirmado'
		elsif self.valor.present? && (self.definir_valor_do_empenho > saldo_da_dotacao )
			self.status = 'aguardando_alteracao_do_orcamento'
		else
			self.status = 'solicitado'
		end
	end

	def retorna_categorias_dos_itens_que_nao_pertencem_ao_sub_elemento
		return ::Base::Categoria.where(id: self.itens.pluck(:categoria_id).uniq).where.not(titulo: self.sub_elemento_de_despesa.descricao)
	end

	def retorna_texto_plularizado_dos_itens(itens_que_nao_compem_o_sub_elemento)
		return itens_que_nao_compem_o_sub_elemento.size > 1 ? "Itens Nas Categorias" : "Item Na Categoria"
	end

	def totalmente_anulado?
		return self.definir_valor_do_empenho.to_d == self.valor_anulado.to_d
	end

	def necessita_de_cronograma?
		reconhecimento_programado?
	end

	def cronograma_totalmente_preenchido?
		cronograma_do_empenho.present? && definir_valor_do_empenho.to_d > 0 && definir_valor_do_empenho.to_d == cronograma_do_empenho.valor_total.to_d
	end

	def empenho_com_mesmo_numero
		@empenho_com_mesmo_numero ||= orcamento.empenhos.where.not(id: id, numero_do_empenho: nil, status: "anulado").find_by(numero_do_empenho: numero_do_empenho, restos_a_pagar: restos_a_pagar)
	end

	def valida_se_ja_houve_envio_do_sim
		errors.add(:sim, 'O SIM do mês já foi enviado') if existe_lote_do_sim?
	end

	def existe_lote_do_sim?(data_do_empenho = nil)
		if data_do_empenho.nil?
			ultima_data = data_sim
		else
			ultima_data = data_do_empenho.to_date
		end

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

			return lote_sim.present?
		end

		return false
	end

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

	def data_sim
		data_do_empenho || data_de_solicitacao
	end

	def precatorio?
		return false if sub_elemento_de_despesa.nil?

		sub_elemento_de_despesa.elemento_de_despesa.codigo[4..5] == "91"
	end

	def obrigacoes?
		return false if sub_elemento_de_despesa.nil?

		sub_elemento_de_despesa.elemento_de_despesa.codigo[4..5] == "71"
	end

	def diaria?
		sub_elemento_de_despesa.elemento_de_despesa.codigo == "33901400"
	end

	alias_method :exige_movimentacao_do_plano_de_contas?, :precatorio?

	def despesa_de_exercicio_anterior?
		return false if sub_elemento_de_despesa_id.nil?

		elementos_de_exercicio_anterior = %w[33909200 31909200 31919200 44909200]
		elementos_de_exercicio_anterior.include?(sub_elemento_de_despesa.elemento_de_despesa.codigo)
	end

	def carrega_informacoes
		self.vpd_he_obrigatorio = self.vpd_obrigatorio?
		self.elemento_de_despesa_do_exercicio_anterior_id = sub_elemento_de_despesa_exercicio_anterior.try(:elemento_de_despesa_id) if sub_elemento_de_despesa_exercicio_anterior.present?
	end

	def saldo_a_pagar(orcamento_atual = nil)
		self.definir_valor_do_empenho - valor_liquidado_pago - valor_anulado.to_d
	end

	def saldo_a_liquidar(orcamento_atual = nil)
		definir_valor_do_empenho - valor_liquidado - valor_anulado.to_d
	end

	def apagar_movimento_orcamentario
		Contabilidade::LancamentoDoOrcamentoDaDespesa.where(modulo: self).destroy_all
	end

	def apaga_ordens_de_compras
		if self.ordens_de_compra.any? && self.ordens_de_compra.count == self.ordens_de_compra.retornados.count
			self.ordens_de_compra.destroy_all
		end
	end

	def lancar_movimento_orcamentario
		if descriminacao_obrigatoria_de_itens?
			apagar_movimento_orcamentario
		else
			movimento = Contabilidade::LancamentoDoOrcamentoDaDespesa.where(modulo: self).first
			movimento.update_column(:data_do_lancamento, self.data_do_empenho) if movimento.present? && self.data_do_empenho != movimento.data_do_lancamento
		end

		if definir_valor_do_empenho.to_f > 0 && (lancamento_do_orcamento_da_despesa.try(:valor).to_f != definir_valor_do_empenho.to_f || !lancamento_do_orcamento_da_despesa.present? )
			if descriminacao_obrigatoria_de_itens?
				total = self.itens_do_empenho.inject(0) { |total, item_do_empenho| total + item_do_empenho.total.to_f}
			else
				total =  self.valor
			end

			if lancamento_do_orcamento_da_despesa.present?
				valor_saldo_da_dotacao = self.orcamento_da_despesa.try(:saldo).to_f + self.definir_valor_do_empenho.to_f
			else
				valor_saldo_da_dotacao = self.orcamento_da_despesa.try(:saldo).to_f
			end

			if ((total.to_f <= valor_saldo_da_dotacao &&  Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho?)) || !Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho?)) && self.orcamento_da_despesa.present?
				apagar_movimento_orcamentario
				self.orcamento_da_despesa.reload
				movimentacao = Contabilidade::LancamentoDoOrcamentoDaDespesa.new(
					orcamento_da_despesa: self.orcamento_da_despesa,
					data_do_lancamento: self.data_do_empenho,
					valor: definir_valor_do_empenho,
					modulo: self
				)
				movimentacao.save

				if logado_na_contabilidade.present? && self.aguardando_alteracao_do_orcamento?
					self.status = 'confirmado'
					self.save(validate: false)
				elsif self.aguardando_alteracao_do_orcamento?
					self.status = 'solicitado'
					self.save(validate: false)
				end
			end
		end
	end

	def checa_se_data_do_empenho_superior_da_liquidacao
		existe_data_inferior = false
		if self.data_do_empenho.present? && self.liquidacoes.any?
			self.liquidacoes.each do |liquidacao|
				existe_data_inferior = true if (liquidacao.data_da_liquidacao.present? && liquidacao.data_da_liquidacao < self.data_do_empenho) || (liquidacao.data_de_solicitacao.present? && liquidacao.data_de_solicitacao < self.data_do_empenho)
			end

			if existe_data_inferior
				errors.add(:data_do_empenho, "Data do empenho não pode ser superior a da liquidação.")
			end
		end
	end

	def fonte_de_recursos_de_restos_a_pagar_do_orcamento_atual(orcamento = nil)
		orcamento = contexto_atual if orcamento.nil?

		self.fontes_de_recursos_de_restos_a_pagar.where(orcamento: orcamento).last.fonte_de_recursos rescue nil
	end

	def existe_fonte_no_orcamento_atual?(orcamento = nil)
		orcamento = contexto_atual if orcamento.nil?

		fonte_stn = ::Base::FontesDeRecursos::FonteStn.where(codigo_tipo_exercicio: self.fonte_de_recursos&.fonte_stn&.codigo_tipo_exercicio, codigo_principal: self.fonte_de_recursos&.fonte_stn&.codigo_principal, detalhamento_sintetico: self.fonte_de_recursos&.fonte_stn&.detalhamento_sintetico, orcamento: orcamento).first

		fonte_stn.present?
	end

	def atualiza_linhas
		if self.confirmado? || self.anualado?
			self.gera_linha_para_arquivo_do_sim
			
			self.liquidacoes.where('status IN (2,5,6,8)').each do |liquidacao|
				liquidacao.gera_linha_para_arquivo_do_sim
				liquidacao.gera_linhas_dos_dependentes
			end

			self.pagamentos.where('contabilidade_pagamentos.status <> 1').each do |pagamento|
				pagamento.gera_linha_para_arquivo_do_sim
			end
		end
	end

	def atualiza_data_sim_do_contrato_aditivo_e_processo
		self.contrato.empenhos.where('status IN (4,5) AND data_do_empenho IS NOT NULL').group_by{|emp| emp.aditivo_id}.each do |aditivo, empenhos|
			primeiro_empenho = empenhos.sort_by(&:data_do_empenho).first
			contrato = primeiro_empenho&.contrato
			aditivo = primeiro_empenho&.aditivo

			if primeiro_empenho.present?
				# o empenho pode se de um aditivo, se for o caso e o aditivo não tiver ido ao SIM ainda sera atualizado a data de envio para o mesmo mês do seu primeiro empenho
				if aditivo.present?
					if aditivo.arquivo_id.nil? || (aditivo.arquivo_id.present? && !aditivo.arquivo.lote.finalizado?)
						aditivo.update_columns(envia_pro_sim: true, data_de_envio_pro_sim: primeiro_empenho.data_do_empenho.end_of_month)
					end
				# se o empenho for do contrato, e contrato não tiver ido ao SIM ainda sera atualizado a data de envio para o mesmo mês do seu primeiro empenho
				else
					if contrato.arquivo_id.nil? || (contrato.arquivo_id.present? && !contrato.arquivo.lote.finalizado?)
						contrato.update_columns(envia_pro_sim: true, data_de_envio_pro_sim: primeiro_empenho.data_do_empenho.end_of_month)
					end
				end
			end
		end
		#atualiza o processo caso não tenha sido enviado ainda e adiciona a data de envio para oo mesmo mes do contrato
		emp = self.contrato.empenhos.where('status IN (4,5) AND data_do_empenho IS NOT NULL').order('data_do_empenho ASC').first
		if emp.present? && emp.projeto.present?
			if emp.projeto.arquivo_id.nil? || (emp.projeto.arquivo.present? && !emp.projeto.arquivo.lote.finalizado?)
				emp.projeto.update_columns(envia_pro_sim: true, data_de_envio_pro_sim: emp.data_do_empenho.end_of_month)
			end
		end
	end

	private
	def preenche_unidade_orcamentaria
		self.unidade_orcamentaria = self.orcamento_da_despesa.try(:unidade_orcamentaria)
	end

	def lanca_as_mudancas_no_restos_a_pagar_se_tiver
		campos_alterados = self.changed

		if campos_alterados.size > 0
			campos_alterados.each do |campo|
				self.empenho_de_restos_a_pagar.write_attribute(campo, self["#{campo}".to_sym])
			end

			self.empenho_de_restos_a_pagar.save(validate: false)
		end

		self.contas_unidade_por_empenho.each do |conta|
			campos_alterados_contas_unidade_por_empenho = conta.changed

			if conta.marked_for_destruction?
				conta_unidade_rp = self.empenho_de_restos_a_pagar.contas_unidade_por_empenho.where(conta_unidade_id: conta.conta_unidade_id_was).first rescue nil

				conta_unidade_rp.destroy if conta_unidade_rp.present?

			elsif conta.new_record?
				self.empenho_de_restos_a_pagar.contas_unidade_por_empenho.create(conta_unidade_id: conta.conta_unidade_id)

			else
				if campos_alterados_contas_unidade_por_empenho.size > 0
					conta_unidade_rp = self.empenho_de_restos_a_pagar.contas_unidade_por_empenho.where(conta_unidade_id: conta.conta_unidade_id_was).first rescue nil

					if conta_unidade_rp.present?
						unless campo == 'empenho_id'
							conta_unidade_rp.conta_unidade_id = conta.conta_unidade_id
						end
					end

					conta_unidade_rp.save(validate: false)
				end

			end
		end

		self.itens_do_empenho.each do |item_do_empenho|
			campos_alterados_item_do_empenho = item_do_empenho.changed

			if item_do_empenho.marked_for_destruction?
				item_do_empenho_rp = self.empenho_de_restos_a_pagar.itens_do_empenho.where(item_id: item_do_empenho.item_id_was).first rescue nil

				item_do_empenho_rp.destroy if item_do_empenho_rp.present?
			elsif item_do_empenho.new_record?
				self.empenho_de_restos_a_pagar.itens_do_empenho.create(item_id: item_do_empenho.item_id, quantidade: item_do_empenho.quantidade, valor_unitario: item_do_empenho.valor_unitario, total: item_do_empenho.total)

			else
				if campos_alterados_item_do_empenho.size > 0
					item_do_empenho_rp = self.empenho_de_restos_a_pagar.itens_do_empenho.where(item_id: item_do_empenho.item_id_was).first rescue nil

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

						item_do_empenho_rp.save(validate: false)
					end
				end

			end
		end
	end

	def valida_valor_do_empenho
		if projeto.present?
			if aditivo.present?
				errors.add(:valor, 'Não pode ser maior que o saldo do aditivo escolhido') if self.aditivo.valor_a_empenhar.to_f.round(2) + self.valor_was.to_f.round(2) < self.valor.to_f.round(2)
			elsif contrato.present? && self.reconhecimento_de_divida?
				errors.add(:valor, 'Não pode ser maior que o saldo do contrato escolhido') if self.contrato.saldo_reconhecimento_de_divida.to_f.round(2) + self.valor_was.to_f.round(2) < self.valor.to_f.round(2)
			elsif contrato.present? && (data_do_empenho.present? || data_de_solicitacao.present?)
				errors.add(:valor, "Não pode ser maior que o saldo vigente do contrato escolhido #{self.valor_a_empenhar_do_contrato_com_aditivos.to_f.real_contabil}") if self.valor_a_empenhar_do_contrato_com_aditivos.to_f.round(2) + self.valor_was.to_f.round(2) < self.definir_valor_do_empenho.to_f.round(2)
			else
				errors.add(:valor, 'Não pode ser maior que o saldo do projeto escolhido') if self.projeto.valor_a_contratar.to_f.round(2) + self.valor_was.to_f.round(2) < self.valor.to_f.round(2)
			end
		end
	end

	def valida_saldo_do_contrato
		total_itens = self.itens_do_empenho.inject(0) { |sum, item_no_empenho| sum.to_d + item_no_empenho.total.to_d }.to_d
		errors.add(:valor, "Não pode ser maior que o saldo vigente do contrato escolhido #{self.valor_a_empenhar_do_contrato_vigente.to_d.real_contabil}") if (self.valor_a_empenhar_do_contrato_vigente.to_d + definir_valor_do_empenho.to_f).to_d < total_itens.to_d
	end

	def data_deve_estar_inclusa_na_vigencia_do_contrato
		data = self.data_do_empenho.present? ? :data_do_empenho : :data_de_solicitacao
		if contrato.inicio_da_vigencia.present? && contrato.data_final_de_acordo_com_aditivos.present?
			unless send(data).between? contrato.inicio_da_vigencia, contrato.data_final_de_acordo_com_aditivos
				errors.add(data, "Deve estar dentro da vigência do contrato (#{contrato.inicio_da_vigencia} à #{contrato.data_final_de_acordo_com_aditivos})")
			end
		end
	end

	def atribui_codigo_disponivel
		gerar_codigo(send(:data_de_solicitacao), :numero_da_solicitacao_do_empenho, :data_de_solicitacao, :orcamento_id, self.orcamento_id)
		gerar_codigo(send(:data_do_empenho), :numero_do_empenho, :data_do_empenho, :orcamento_id, self.orcamento_id) if self.confirmado? && self.numero_do_empenho.blank?
	end

	def atribui_codigo_solicitacao
		atributo_data = confirmado? ? :data_do_empenho : :data_de_solicitacao
		gerar_codigo(send(atributo_data), :numero_da_solicitacao_do_empenho, atributo_data, :orcamento_id, self.orcamento_id)
	end

	def empenho_nao_pode_ter_dados_de_diaria_e_obras
		if diaria_id.present? && obra.present?
			errors.add(:diaria_id, 'não pode salvar caso tenha obra cadastrada')
		end
	end

	def restricoes_de_diaria
		# diaria deve ter empenho na modalidade ordinario
		if modalidade.present? && !ordinario?
			errors.add(:modalidade, "deve ser do tipo ordinário quando diária estiver preenchida")
		end

		# a pessoa da diária deve ser a mesma do empenho
		if pessoa.present? && (diaria.agente_publico_municipal.pessoa != pessoa)
			errors.add(:pessoa_id, "deve ser a mesma informada na diária")
		end

		# deve ter o mesmo valor da diária
		if valor.present?
			errors.add(:valor, "deve ser o mesmo informado na diária") if valor.to_f.round(2) != diaria.valor_total.to_f.round(2)
		end
	end

	def valor_padrao_para_o_valor_do_empenho
		self.valor ||= 0
	end

	def verifica_saldo_da_dotacao
		total_novos_itens = self.itens_do_empenho.reject(&:marked_for_destruction?).inject(0) { |total, item_do_empenho| total + item_do_empenho.total.to_f}
		valor_saldo_da_dotacao = self.orcamento_da_despesa.saldo.to_f + self.definir_valor_do_empenho.to_f

		if (total_novos_itens.to_f > valor_saldo_da_dotacao) && Configuracao.last.try(:valida_saldo_da_dotacao_no_empenho).present?
			self.status = 'aguardando_alteracao_do_orcamento'
			self.save(validate: false)
		end
	end

	def atualiza_dados_de_obra
		if self.uso_do_bem.nil? || self.conta_pcasp.nil?
			if self.uso_do_bem.nil? && !self.uso_do_bem_da_obra.blank?
				uso_do_bem = self.uso_do_bem_da_obra
			else
				uso_do_bem = self.uso_do_bem
			end

			if self.conta_pcasp.nil? && !self.conta_pcasp_da_obra.blank?
				conta_pcasp = self.conta_pcasp_da_obra
			else
				conta_pcasp = self.conta_pcasp
			end
			self.obra.update_columns(uso_do_bem: uso_do_bem, conta_pcasp_id: conta_pcasp)
		end
	end

	def atualiza_campo_valor_total
		self.update_column(:saldo_total, self.definir_valor_do_empenho)
	end

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