class Licitacao::Contrato < ApplicationRecord
	has_paper_trail

	include AASM
	include TradutorConcern
	include VistoriavelContratosConcern
	include IncrementadorDeCodigoConcern
	include GeradorDeEventosContabeis

	attr_default :status, :aberto
	attr_default :envia_pro_sim, true
	attr_default :skip_callbacks, false
	attr_accessor :pessoa_do_projeto_id
	attr_accessor :fornecedor_id
	attr_accessor :cpf_do_responsavel
	attr_accessor :nome_do_responsavel
	attr_accessor :lotes_marcados_para_excluir
	attr_accessor :form_principal
	attr_accessor :skip_callbacks

	belongs_to :arquivo, class_name: "Tcm::Arquivo"
	belongs_to :contratado, class_name: "Licitacao::Contratado", inverse_of: :contrato, dependent: :destroy
	belongs_to :modelo_de_documento, class_name: "Licitacao::ModeloDeDocumento"
	belongs_to :orcamento, class_name: "Orcamento"
	belongs_to :projeto, class_name: "Licitacao::Projeto", inverse_of: :contratos
	belongs_to :unidade_orcamentaria_do_exercicio, class_name: "Loa::UnidadeOrcamentaria", foreign_key: :unidade_orcamentaria_do_exercicio_id
	belongs_to :unidade_orcamentaria_por_pedido, class_name: "Licitacao::UnidadeOrcamentariaPorPedido"
	belongs_to :ata_de_registro_de_precos, class_name: "Licitacao::AtaDeRegistroDePrecos", foreign_key: :ata_de_registro_de_preco_id
	belongs_to :responsavel, class_name: "Base::Responsavel", foreign_key: :responsavel_fornecedor_id
	belongs_to :responsavel_do_pedido, class_name: "Base::AgentePublicoMunicipal", foreign_key: :responsavel_do_pedido_id

	delegate :pessoa_do_projeto, to: :contratado
	delegate :pessoa, to: :pessoa_do_projeto
	delegate :pessoa_id, to: :pessoa_do_projeto
	delegate :cpf_ou_cnpj_e_nome, to: :pessoa
	delegate :unidade_orcamentaria, :pedido, to: :unidade_orcamentaria_por_pedido, allow_nil: true

	has_many :documentos_do_contrato, class_name: 'Licitacao::DocumentoDoContrato', inverse_of: :contrato, dependent: :destroy
	has_many :empenhos, class_name: 'Contabilidade::Empenho', dependent: :restrict_with_exception, inverse_of: :contrato
	has_many :itens_dos_empenhos, through: :empenhos, source: 'itens_do_empenho', class_name: 'Contabilidade::ItemDoEmpenho'
	has_many :empenhos_retroativos_do_contrato, class_name: 'Licitacao::EmpenhoRetroativoDoContrato'
	has_many :itens_do_empenho_retroativo_do_contrato, through: :empenhos_retroativos_do_contrato, class_name: 'Licitacao::ItemDoEmpenhoRetroativoDoContrato'
	has_many :itens_do_contrato, class_name: 'Licitacao::ItemDoContrato', inverse_of: :contrato, dependent: :destroy
	has_many :lotes_do_contrato, class_name: 'Licitacao::LoteDoContrato', inverse_of: :contrato, dependent: :destroy
	has_many :lotes, through: :lotes_do_contrato
	has_many :itens_dos_lotes, through: :lotes, source: :itens_do_lote
	has_many :itens_do_lote_do_contrato, through: :itens_do_contrato, source: :item_do_lote
	has_many :orcamentos_da_despesa_do_contrato, class_name: 'Licitacao::OrcamentoDaDespesaDoContrato', inverse_of: :contrato, dependent: :destroy
	has_many :orcamentos_da_despesa, through: :orcamentos_da_despesa_do_contrato
	has_many :itens_dos_orcamentos_da_despesa_do_contrato, through: :orcamentos_da_despesa_do_contrato, source: :itens_do_orcamento_da_despesa_do_contrato, class_name: "Licitacao::ItemDoOrcamentoDaDespesaDoContrato"
	has_many :sub_elementos_de_despesa, through: :orcamentos_da_despesa_do_contrato
	has_many :fonte_de_recursos, through: :orcamentos_da_despesa,class_name: "Base::FonteDeRecursos"
	has_many :aditivos, class_name: "Licitacao::Aditivo", dependent: :restrict_with_exception, inverse_of: :contrato
	has_many :itens_do_aditivo, through: :aditivos
	has_many :itens_do_aditivo_de_mudanca, through: :aditivos
	has_many :itens_do_aditivo_de_alteracao_de_marca, through: :aditivos
	has_many :itens_dos_lotes_dos_aditivos, through: :itens_do_aditivo, source: :item_do_lote
	has_many :contratos_da_obra, class_name: 'Obra::ContratoDaObra', inverse_of: :contrato
	has_one :obra, class_name: "Contabilidade::Obra"
	has_many :operacoes_de_credito_do_contrato, class_name: 'Licitacao::OperacaoDeCreditoDoContrato', dependent: :destroy
	has_many :operacoes_de_credito, through: :operacoes_de_credito_do_contrato, class_name: 'Obra::OperacaoDeCredito'
	has_many :componentes_da_operacao_de_credito, through: :operacoes_de_credito, class_name: 'Obra::ComponenteDaOperacaoDeCredito'
	has_many :acoes_do_componente, through: :componentes_da_operacao_de_credito, class_name: 'Obra::AcaoDoComponente'
	has_many :acoes_da_operacao_de_credito_do_contrato, through: :operacoes_de_credito_do_contrato, class_name: 'Licitacao::AcaoDaOperacaoDeCreditoDoContrato'
	has_many :apostilamentos, class_name: 'Licitacao::Apostilamento'
	has_many :passagens, class_name: 'Contabilidade::Passagem'
	has_many :fiscais_do_contrato, class_name: "Licitacao::FiscalDoContrato", dependent: :destroy
	has_many :gestores_do_contrato, class_name: "Licitacao::GestorDoContrato", dependent: :destroy
	has_many :criticas_de_envio_pncp, as: :modulo, class_name: "Pncp::CriticasDeEnvio"


	accepts_nested_attributes_for :lotes_do_contrato, reject_if: :all_blank
	accepts_nested_attributes_for :orcamentos_da_despesa_do_contrato, reject_if: :all_blank
	accepts_nested_attributes_for :itens_do_contrato, reject_if: :all_blank, allow_destroy: true
	accepts_nested_attributes_for :operacoes_de_credito_do_contrato, reject_if: :all_blank, allow_destroy: true

	validates_presence_of :lotes_do_contrato, message: "Por favor, selecione ao menos um lote", unless: Proc.new { (self.try(:projeto).try(:pedido).try(:projeto_simplificado).present? && !self.try(:projeto).try(:bid_obra_ou_servico)) || !self.try(:discriminacao_obrigatoria_de_itens?) || self.try(:projeto).try(:por_item?)}
	validates_presence_of :tipo_de_contrato, :unidade_orcamentaria_por_pedido_id
	validates_presence_of :data_da_solicitacao, if: :de_ata?
	validates_presence_of :motivo_do_cancelamento, if: :cancelado?
	validates_presence_of :objeto, :justificativa, if: :parceria?
	validates_presence_of :nome_do_responsavel, :cpf_do_responsavel, on: :create, if: Proc.new { self.try(:projeto).try(:parceria_osc?) && self.try(:projeto).try(:pedido).try(:projeto_simplificado).present? && !self.try(:projeto).try(:bid_obra_ou_servico) }
	validates_presence_of :valor, unless: :discriminacao_obrigatoria_de_itens?

	validates_cpf :cpf_do_responsavel, allow_blank: true

	validates_uniqueness_of :numero, :allow_blank => true

	validates :data_do_contrato, sabado_ou_domingo_ou_feriado: { flexivel: true }
	validates :inicio_da_vigencia, sabado_ou_domingo_ou_feriado: { flexivel: true }
	validates :itens_do_contrato, uniq_nested_attributes: { atributo: :item_do_lote_id, mensagem: "item deve ser único dentro de um contrato" }
	validates :operacoes_de_credito_do_contrato, uniq_nested_attributes: { atributo: :operacao_de_credito_id, mensagem: "operação de crédito deve ser única dentro de um contrato" }
	validates_associated :itens_do_contrato, on: :create

	validate :verifica_unicidade_do_numero_do_contrato
	validate :data_da_solicitacao_dentro_da_vigencia_da_ata, if: :de_ata?
	validate :data_do_contrato_dentro_do_exercicio
	#validação retirada, pois haviam casos de solicitação de ata final de dezembro que só eram formalizadas em janeiro do exercicio seguinte
	#validate :data_da_solicitacao_contrato_dentro_do_exercicio, if: :de_ata?
	validate :data_do_contrato_apos_data_do_projeto
	validate :data_do_contrato_apos_o_inicio_da_vigencia
	validate :inicio_da_vigencia_apos_data_do_projeto
	validate :inicio_da_vigencia_dentro_da_vigencia_da_ata, if: :de_ata?
	validate :fim_da_vigencia_apos_inicio_da_vigencia
	validate :valor_total_nao_pode_ser_maior_que_a_origem, if: Proc.new { self[:valor].present? }, unless: Proc.new {self.skip_callbacks == true}
	validate :valor_dentro_do_disponivel_para_unidade_gestora, if: Proc.new { self[:valor].present? && de_ata? && ata_de_registro_de_precos.contratos.present? }, unless: Proc.new {self.skip_callbacks == true}
	validate :ata_sem_discrimanacao_de_itens, if: Proc.new { de_ata? && ata_de_registro_de_precos.contratos.present?}
	validate :processo_sem_discrimanacao_de_itens, if: Proc.new { !de_ata? && projeto.try(:contratos).present?}
	validate :data_da_solicitacao_menor_ou_igual_a_data_do_contrato, if: Proc.new { data_da_solicitacao.present? && data_do_contrato.present? }

	after_create :criar_operacoes_e_acoes_no_contrato, if: Proc.new { self.projeto.operacoes_de_credito_do_projeto.any? }
	after_create :criar_lotes_do_contrato, if: Proc.new { projeto.por_item? }
	after_create :gera_lote_inicial_simplificado, if: Proc.new { projeto.pedido.projeto_simplificado.present? && !projeto.bid_obra_ou_servico }
	after_create :criar_itens_contrato, unless: Proc.new { self.projeto.registro_de_preco? || !self.discriminacao_obrigatoria_de_itens?}

	before_validation :seta_pessoa_do_projeto, on: :create, if: Proc.new { contratado.nil? && projeto && projeto.pedido.projeto_simplificado.present? && !projeto.bid_obra_ou_servico }
	before_validation :seta_contratado, on: :create, if: Proc.new { contratado.nil? }
	before_validation :seta_unidade_orcamentaria_do_exercicio_atual
	before_validation :atribui_numero_da_solicitacao

	after_save :atualiza_campo_valor_total, unless: Proc.new {self.skip_callbacks == true}

	before_save :exclui_lotes_desmarcados_do_contrato, on: :update, if: Proc.new { self.aberto? && self.itens_do_contrato.any? && self.ata_de_registro_de_precos.present? }
	before_save :exclui_lotes_do_contrato, on: :update, if: Proc.new { self.aberto? && self.itens_do_contrato.empty? && self.discriminacao_obrigatoria_de_itens?}

	enum tipo_de_contrato: {
		contrato_de_obras: 1,
		servico_de_engenharia: 2,
		outros_contratos: 3,
		termo_de_colaboracao: 4,
		termo_de_fomento: 5,
		acordo_de_cooperacao: 6
	}

	enum status: {
		aberto: 0,
		cancelado: 1,
		fechado: 2,
		enviado_para_controladoria: 3,
		enviado_para_copfin: 4,
		enviado_para_licitacao: 5,
		confirmado: 6,
		rescindido: 7
	}

	enum tipo_contrato_pncp: {
		termo_inicial_pncp: 1,
		comodato_pncp: 2,
		arrendamento_pncp: 3,
		concessao_pncp: 4,
		termo_de_adesao_pncp: 5,
		convenio_pncp: 6,
		empenho_pncp: 7,
		outros_pncp: 8,
		execucao_descentralizada_pncp: 9,
		acordo_de_cooperacao_pncp: 10,
		termo_de_compromisso_pncp: 11,
		carta_contrato_pncp: 12
	}

	enum tipo_processo_pncp: {
		cessao_pncp: 1,
		compras_pncp: 2,
		informática_pncp: 3,
		internacional_pncp: 4,
		locacao_imoveis_pncp: 5,
		mao_de_obra_pncp: 6,
		obra_pncp: 7,
		servico_pncp: 8,
		servico_eng_pncp: 9,
		servico_saude_pncp: 10
	}

	scope :vigentes, -> {
		current_date = Date.today
		left_joins(:aditivos).includes(contratado: [pessoa_do_projeto: :pessoa], aditivos: :itens_do_aditivo)
			.select('licitacao_contratos.*, MAX(licitacao_aditivos.fim_da_vigencia)')
			.group('licitacao_contratos.id')
			.having('(MAX(licitacao_aditivos.fim_da_vigencia) IS NOT NULL AND MAX(licitacao_aditivos.fim_da_vigencia) >= :current_date) OR (licitacao_contratos.fim_da_vigencia IS NOT NULL AND licitacao_contratos.fim_da_vigencia >= :current_date AND MAX(licitacao_aditivos.fim_da_vigencia) IS NULL)', current_date: current_date)
	}

	scope :vencidos, -> {
		current_date = Date.today
		left_joins(:aditivos).includes(contratado: [pessoa_do_projeto: :pessoa], aditivos: :itens_do_aditivo)
			.select('licitacao_contratos.*, MAX(licitacao_aditivos.fim_da_vigencia)')
			.group('licitacao_contratos.id')
			.having('(MAX(licitacao_aditivos.fim_da_vigencia) IS NOT NULL AND MAX(licitacao_aditivos.fim_da_vigencia) < :current_date) OR (licitacao_contratos.fim_da_vigencia IS NOT NULL AND licitacao_contratos.fim_da_vigencia < :current_date AND MAX(licitacao_aditivos.fim_da_vigencia) IS NULL)', current_date: current_date)
	}

	scope :usado_no_reconhecimento_de_divida, -> { self.where("licitacao_contratos.status in (1, 2, 6, 7) AND licitacao_contratos.fim_da_vigencia is NOT NULL")  }

	scope :vao_para_o_portal, -> { self.where("licitacao_contratos.status in (2, 6, 7) AND licitacao_contratos.fim_da_vigencia is NOT NULL")  }

	def self.ransackable_scopes(auth_object = nil)
		[:vigentes, :vencidos]
	end

	def numero_e_vigencia
		"#{self.numero} - #{self.inicio_da_vigencia} a #{self.data_final_de_acordo_com_aditivos}"
	end

	def descricao_contrato_de_obra
		obra.present? ? "#{self.numero_e_vigencia} - Obra: #{obra.descricao_da_obra}" : "#{self.numero_e_vigencia}"
	end

	def justificativa_atualizada
		ultimo_aditivo_com_justificativa = self.aditivos.alteracao_contratual.confirmado.where("justificativa IS NOT NULL").last

		if ultimo_aditivo_com_justificativa.present?
			return ultimo_aditivo_com_justificativa.justificativa
		else
			return self.justificativa
		end
	end

	def objeto_atualizada
		ultimo_aditivo_com_objeto = self.aditivos.alteracao_contratual.confirmado.where("objeto_do_contrato IS NOT NULL and objeto_do_contrato != ''").last

		if ultimo_aditivo_com_objeto.present?
			return ultimo_aditivo_com_objeto.objeto_do_contrato
		else
			if self.objeto.present?
				return self.objeto
			else
				return self.projeto.pedido.objeto
			end
		end
	end

	def data_inicial_da_vigencia_atual data_do_periodo
		vigencia_do_contrato = dentro_da_vigencia_original_do_contrato(data_do_periodo)
		aditivo = aditivo_de_prazo_vigente(data_do_periodo)

		data_inicio = inicio_da_vigencia.to_date
		if !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size > 0
			data_inicio = aditivo.inicio_da_vigencia.to_date
		end

		return data_inicio
	end

	def data_final_da_vigencia_atual data_do_periodo
		vigencia_do_contrato = dentro_da_vigencia_original_do_contrato(data_do_periodo)
		aditivo = aditivo_de_prazo_vigente(data_do_periodo)
		data_fim = fim_da_vigencia.to_date
		if !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size > 0
			data_fim = aditivo.fim_da_vigencia.to_date
		elsif self.aditivos.por_prazo.present? && self.aditivos.por_prazo.last.itens_do_aditivo.size == 0
			data_fim = self.aditivos.por_prazo.last.fim_da_vigencia.to_date
		end

		return data_fim
	end

	def movimentacoes_de_eventos_contabeis_do_contrato
		Contabilidade::MovimentacaoDoPlanoDeContas.where(gerador_type: "Licitacao::Contrato").where(gerador_id: self.id)
	end

	# BOOLEANS
	def parceria?
		self.contratado && self.projeto.parceria_osc?
	end

	def obra_ou_servico?
		self.contrato_de_obras? || self.servico_de_engenharia?
	end

	def de_ata?
		ata_de_registro_de_precos.present?
	end

	def tem_aditivos?
		aditivos.any?
	end

	def tem_aditivos_de_reajuste_de_valor?
		aditivos.reajuste_de_valor_acrescimo.any? || aditivos.reajuste_de_valor_decrescimo.any?
	end

	def tem_aditivo_de_prazo?
		aditivos.aditivos_de_prazo.any?
	end

	def tem_empenhos?
		empenhos.any?
	end

	def tem_itens?
		itens_do_contrato.any?
	end

	def pode_adicionar_itens?
		(projeto.registro_de_preco? || importado_do_tcm? || projeto.pedido.projeto_simplificado? || projeto.por_item?)
	end

	def tem_dotacao?
		self.orcamentos_da_despesa_do_contrato.any?
	end

	def por_lote?
		self.projeto.por_lote?
	end

	def dotacoes_batem_com_valor_do_contrato?
		valor_do_contrato.to_f == orcamentos_da_despesa_do_contrato.sum(:valor).to_f
	end

	def pode_editar?
		(self.aberto? || self.enviado_para_licitacao? || (ata_de_registro_de_precos.present? && self.confirmado?) || falta_preechimento_de_dados?) && enviado_para_o_sim? == false
	end

	def itens_da_ata_por_lote
		unidade_da_ata = self.ata_de_registro_de_precos.unidades_orcamentarias_da_ata.where(unidade_orcamentaria_id: unidade_orcamentaria.id).first
		itens_do_lote = unidade_da_ata.itens_dos_lotes_por_unidade
		itens_da_ata = self.ata_de_registro_de_precos.itens_da_ata.joins(:item_do_lote).where('licitacao_itens_do_lote.id IN (?)', itens_do_lote.ids)
		return itens_da_ata
	end

	def itens_da_ata_por_lote_do_fornecedor_vencedor
		self.ata_de_registro_de_precos.itens_da_ata.joins(item_do_lote: [:lote]).where("licitacao_lotes.ganhador_id = ?", self.contratado.pessoa_do_projeto.id)
	end

	def aditivo_com_dotacao?
		aditivos.confirmados.nova_unidade_orcamentaria.any? && aditivos.confirmados.nova_unidade_orcamentaria.select{|aditivo| aditivo.orcamentos_da_despesa_do_aditivo.any? }.any?
	end

	def apostilamentos_com_dotacao?
		apostilamentos.dotacao.any? && apostilamentos.dotacao.select{|apostilamento| apostilamento.orcamentos_da_despesa_do_apostilamento.any? }.any?
	end

	def dotacoes_ativas
		if apostilamentos_com_dotacao? && aditivo_com_dotacao?
			if apostilamentos.dotacao.last.created_at > aditivos.confirmados.nova_unidade_orcamentaria.last.created_at
				if apostilamentos.dotacao.last.orcamento.id == orcamento.id
					dotacoes_ultimo_apostilamento + dotacoes_ultimo_aditivo
				else
					dotacoes_ultimo_apostilamento
				end
			else
				dotacoes_ultimo_aditivo
			end
		elsif !apostilamentos_com_dotacao? && aditivo_com_dotacao?
			dotacoes_ultimo_aditivo
		elsif apostilamentos_com_dotacao? && !aditivo_com_dotacao?
			if apostilamentos.dotacao.last.orcamento.id == orcamento.id
				dotacoes_ultimo_apostilamento + orcamentos_da_despesa_do_contrato
			else
				dotacoes_ultimo_apostilamento
			end
		else
			orcamentos_da_despesa_do_contrato
		end
	end

	def orcamentos_da_despesa_ativos
		if apostilamentos_com_dotacao? && aditivo_com_dotacao?
			if apostilamentos.dotacao.last.created_at > aditivos.confirmados.nova_unidade_orcamentaria.last.created_at
				if apostilamentos.dotacao.last.orcamento.id == orcamento.id
					orcamento_ids = orcamentos_ultimo_apostilamento.ids + orcamentos_ultimo_aditivo.ids
					Loa::OrcamentoDaDespesa.where(id: orcamento_ids)
				else
					orcamentos_ultimo_apostilamento
				end
			else
				orcamentos_ultimo_aditivo
			end
		elsif !apostilamentos_com_dotacao? && aditivo_com_dotacao?
			orcamentos_ultimo_aditivo
		elsif apostilamentos_com_dotacao? && !aditivo_com_dotacao?
			if apostilamentos.dotacao.last.orcamento.id == orcamento.id
				orcamento_ids = orcamentos_ultimo_apostilamento.ids + orcamentos_da_despesa.ids
				Loa::OrcamentoDaDespesa.where(id: orcamento_ids)
			else
				orcamentos_ultimo_apostilamento
			end
		else
			orcamentos_da_despesa
		end
	end

	def a_empenhar?
		!empenhos.any?
	end

	def ata_sem_discrimanacao_de_itens
		if discriminacao_obrigatoria_de_itens? && !ata_de_registro_de_precos.contratos_com_discriminacao_de_itens?
			errors.add(:discriminacao_obrigatoria_de_itens, "Os contratos da ata escolhida não devem ter discriminação obrigatória de itens")
		elsif !discriminacao_obrigatoria_de_itens? && ata_de_registro_de_precos.contratos_com_discriminacao_de_itens?
			errors.add(:discriminacao_obrigatoria_de_itens, "Os contratos da ata escolhida devem ter discriminação obrigatória de itens")
		end
	end

	def processo_sem_discrimanacao_de_itens
		if discriminacao_obrigatoria_de_itens? && !projeto.contratos_com_discriminacao_de_itens?
			errors.add(:discriminacao_obrigatoria_de_itens, "Os contratos do processo escolhido não devem ter discriminação obrigatória de itens")
		elsif !discriminacao_obrigatoria_de_itens? && projeto.contratos_com_discriminacao_de_itens?
			errors.add(:discriminacao_obrigatoria_de_itens, "Os contratos do processo escolhido devem ter discriminação obrigatória de itens")
		end
	end

	def empenhado_parcial?
		empenhos.any? && valor_total_do_contrato.to_f > 0 && valor_a_empenhar.to_f > 0
	end

	def empenhado_total?
		empenhos.any? && valor_total_do_contrato.to_f > 0 && valor_a_empenhar.to_f == 0
	end

	def liquidado?
		empenhado_total? && empenhos.inject(0) {|sum, empenho| sum + empenho.saldo}.to_f == 0
	end

	def vigente?
		data_final_de_acordo_com_aditivos >= Date.today
	end

	def vigente_na_data data_de_solicitacao
		data_de_solicitacao.present? && (data_final_de_acordo_com_aditivos >= data_de_solicitacao)
	end

	def pode_gerar_aditivo?
		self.fechado?
	end

	def importado_do_tcm?
		self.arquivo_id == 0
	end

	def enviado_para_o_sim?
		self.arquivo_id.present? && self.arquivo_id > 0
	end

	def tem_lote_de_servico?
		lotes.any? { |lote| lote.servico? }
	end

	def tem_fontes_de_recursos_de_operacao_de_credito?
		if fonte_de_recursos.any?
			fontes_iguais = fonte_de_recursos.map(&:codigo_completo).select {|codigo_da_fonte| ["1130000000", "1230000000", "1920000000", "2230000000", "2920000000"].include?(codigo_da_fonte)}.uniq
			fontes_iguais.empty? ? false : true
		end
	end

	def mesma_unidade_orcamentaria_do_pedido_e_do_exercicio?
		(self.unidade_orcamentaria_do_exercicio_id == unidade_orcamentaria_por_pedido.unidade_orcamentaria.id) ||
			((unidade_orcamentaria_por_pedido.unidade_orcamentaria.codigo == unidade_orcamentaria_do_exercicio.codigo) &&
				(unidade_orcamentaria_por_pedido.unidade_orcamentaria.orgao.codigo == unidade_orcamentaria_do_exercicio.orgao.codigo))
	end

	def dentro_da_vigencia_original_do_contrato(data_solicitada)
		(inicio_da_vigencia <= data_solicitada && fim_da_vigencia >= data_solicitada) if data_solicitada.present? && self.inicio_da_vigencia.present? && self.fim_da_vigencia.present?
	end

	#
	def dentro_da_vigencia_do_contrato(data_solicitada)
		data_solicitada.to_date >= inicio_da_vigencia.to_date && data_solicitada.to_date <= data_final_de_acordo_com_aditivos.to_date if data_solicitada.present?
	end

	def aditivo_de_prazo_vigente(data_solicitada)
		aditivos.confirmados.aditivos_de_prazo.where("inicio_da_vigencia <= ? AND fim_da_vigencia >= ?",data_solicitada, data_solicitada).first
	end

	def saldo_apostilados_vigente(data_solicitada)
		apostilamentos_vigentes = self.apostilamentos.where("licitacao_apostilamentos.modalidade in (?) AND data_apostilamento <= ? ", [Licitacao::Apostilamento.modalidades[:acrescimo], Licitacao::Apostilamento.modalidades[:reducao]] , data_solicitada)

		apostilamentos_redutivos = apostilamentos_vigentes.reducao.inject(0){ |total, apostilamento| total + apostilamento.itens_do_apostilamento.sum(&:saldo_para_calculos) } rescue 0
		apostilamentos_acrescidos = apostilamentos_vigentes.acrescimo.inject(0){ |total, apostilamento| total + apostilamento.itens_do_apostilamento.sum(&:saldo_para_calculos) } rescue 0

		return apostilamentos_acrescidos - apostilamentos_redutivos
	end

	# QUANTIDADES
	def quantidade_total_por_item(item)
		itens_do_contrato.joins(item_do_lote: :item_do_pedido).find_by(licitacao_itens_do_pedido: {item_id: item.id}).try(:quantidade).to_f +
		quantidade_dos_aditivos_total_por_item(item)
	end

	def quantidade_dos_aditivos_total_por_item(item)
		acrescimo = itens_do_aditivo.acrescimo.joins(item_do_lote: :item_do_pedido).where(licitacao_itens_do_pedido: {item_id: item.id}).sum(:quantidade).to_f
		reducao = itens_do_aditivo.reducao.joins(item_do_lote: :item_do_pedido).where(licitacao_itens_do_pedido: {item_id: item.id}).sum(:quantidade).to_f
		acrescimo - reducao + quantidade_dos_aditivos_de_prazo_por_item(item)
	end

	def quantidade_dos_aditivos_de_prazo_por_item(item)
		prazo = 0
		# Quando for serviço e tiver aditivo de prazo com controle de itens, atualizar a quantidade do contrato
		aditivos.confirmados.aditivos_de_prazo.each do |aditivo|
			if aditivo.prazo_com_controle_de_itens? && aditivo.itens_do_aditivo.size > 0
				prazo += aditivo.itens_do_aditivo.joins(item_do_lote: :item_do_pedido).where(licitacao_itens_do_pedido: {item_id: item.id}).sum(:quantidade).to_f
			end
		end
		return prazo
	end

	def quantidade_liquidada_por_item(item)
		empenhos.joins(liquidacoes: :itens_da_nota_fiscal).where(contabilidade_itens_da_nota_fiscal: {item_id: item.id}).sum(:quantidade)
	end

	# VALORES
	def fontes_de_recursos_de_operacao_de_credito
		fonte_de_recursos.select {|codigo_da_fonte| ["1130000000", "1230000000", "1920000000", "2230000000", "2920000000"].include?(codigo_da_fonte.codigo_completo)}
	end

	def valor_dos_aditivos
		aditivos.confirmados.de_acrescimo_ou_reducao.sum(&:valor_total).to_f
	end

	def valor_dos_aditivos_de_prorrogacao
		total_por_prazo = 0
		aditivos.confirmados.includes(:itens_do_aditivo).aditivos_de_prazo.each do |aditivo|
			if aditivo.prazo_com_controle_de_itens? && aditivo.itens_do_aditivo.size > 0
				total_por_prazo += aditivo.itens_do_aditivo.sum(:total).to_d.round(2)
			end
		end
		total_por_prazo
	end

	def valor_dos_aditivos_de_acrescimo
		aditivos.confirmados.acrescimo.to_a.sum(&:valor_total).to_f
	end

	def valor_dos_aditivos_de_reajuste_de_valor
		aditivos.confirmados.de_reajuste_de_valor.to_a.sum(&:valor_total).to_f
	end

	def total_reajuste_de_valor_acrescimo
		aditivos.confirmados.reajuste_de_valor_acrescimo.to_a.sum(&:valor_total).to_d
	end

	def total_reajuste_de_valor_decrescimo
		aditivos.confirmados.reajuste_de_valor_decrescimo.to_a.sum(&:valor_total).to_d
	end

	def valor_total_itens_do_contrato
		itens_do_contrato.includes([item_do_lote: [:item_do_pedido, lote: :processo]]).to_a.sum(&:valor_original).to_d
	end

	def valor_dos_itens_igual_ao_total_do_contrato?
		valor_total_itens_do_contrato == valor_total_do_contrato
	end

	def valor_do_contrato
		if self.discriminacao_obrigatoria_de_itens?
			valor_total_itens_do_contrato
		else
			self.valor.to_d
		end
	end

	def valor_total_do_contrato
		valor_do_contrato.to_d + valor_dos_apostilamentos + valor_dos_aditivos.to_d + (total_reajuste_de_valor_acrescimo - total_reajuste_de_valor_decrescimo).to_d + valor_dos_aditivos_de_prorrogacao.to_d
	end

	def saldo_reconhecimento_de_divida
		(valor_do_contrato.round(2) - empenhos.where('contabilidade_empenhos.data_de_solicitacao >= ? AND contabilidade_empenhos.data_de_solicitacao <= ? ', self.inicio_da_vigencia, self.fim_da_vigencia).to_a.sum(&:definir_valor_do_empenho).round(2))
	end

	def valor_dos_apostilamentos
		return self.itens_do_contrato.sum(&:valor_apostilado)
	end

	def valor_anulado
		empenhos.do_orcamento.to_a.sum(&:valor_anulado).round(2)
	end

	def valor_empenhado
		empenhos.do_orcamento.to_a.sum(&:definir_valor_do_empenho).round(2) + empenhos_retroativos_do_contrato.to_a.sum(&:definir_valor_do_empenho_retroativo).round(2) - valor_anulado.to_d - valor_de_cancelamento_de_restos_a_pagar_nao_processados.to_d
	end

	def valor_empenhado_sem_aditivo
		empenhos.where(restos_a_pagar: false, aditivo_id: nil).to_a.sum(&:definir_valor_do_empenho) + empenhos_retroativos_do_contrato.to_a.sum(&:definir_valor_do_empenho_retroativo) - valor_de_cancelamento_de_restos_a_pagar_nao_processados.to_d
	end

	def valor_anulado_no_periodo_vigente(data_inicio,data_fim)
		vl_anulado_no_periodo_vigente = 0
		empenhos.do_orcamento.where('data_do_empenho <= ? AND data_do_empenho >= ?', data_fim, data_inicio).each do |empenho|
			vl_anulado_no_periodo_vigente += empenho.anulacoes_do_empenho.confirmadas.sum(:valor).to_d
		end
		vl_anulado_no_periodo_vigente
	end

	def valor_empenhado_no_periodo_vigente(data_do_periodo)
		vigencia_do_contrato = dentro_da_vigencia_original_do_contrato(data_do_periodo)
		aditivo = aditivo_de_prazo_vigente(data_do_periodo)

		if !vigencia_do_contrato && !aditivo.present?
			# não está na vigencia nem do contrato ou de aditivos
			valor = 0
		else
			if vigencia_do_contrato
				# está na vigencia do contrato
				data_inicio = inicio_da_vigencia.to_date
				data_fim = fim_da_vigencia.to_date
			elsif !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size > 0
				# está na vigencia do aditivo de prazo
				data_inicio = aditivo.inicio_da_vigencia.to_date
				data_fim = aditivo.fim_da_vigencia.to_date
			elsif !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size == 0
				# está na vigencia do aditivo de prazo, porem esse não tem itens
				data_inicio = inicio_da_vigencia.to_date
				data_fim = aditivo.fim_da_vigencia.to_date
			end
			if Configuracao.last.controlar_empenho_por_vigencia && !vigencia_do_contrato && (aditivo.present? && aditivo.itens_do_aditivo.size > 0 || aditivo.por_prazo?) 
				valor = empenhos.where("restos_a_pagar = false").where("(reconhecimento_de_divida is NULL and data_do_empenho >= ? and data_do_empenho <= ? and data_do_empenho is NOT NULL) OR (data_de_solicitacao >= ? AND data_do_empenho is NULL)", data_inicio, data_fim, data_inicio).sum(&:definir_valor_do_empenho) + empenhos_retroativos_do_contrato.where("data_do_empenho >= ? and data_do_empenho <= ?", data_inicio, data_fim).sum(&:definir_valor_do_empenho_retroativo)
			else
				valor = empenhos.where("restos_a_pagar = false").where("(reconhecimento_de_divida is NULL and data_do_empenho >= ? and data_do_empenho <= ? and aditivo_id is NULL and data_do_empenho is not NULL) OR (data_de_solicitacao >= ? AND data_de_solicitacao <= ? and data_do_empenho is NULL)", data_inicio, data_fim, data_inicio, data_fim).sum(&:definir_valor_do_empenho) + empenhos_retroativos_do_contrato.where("data_do_empenho >= ? and data_do_empenho <= ?", data_inicio, data_fim).sum(&:definir_valor_do_empenho_retroativo)
			end
		end
		return valor
	end

	def valor_reconhecimento_de_divida_do_periodo_vigente(data_do_periodo)
		if !dentro_da_vigencia_original_do_contrato(data_do_periodo) && aditivo_de_prazo_vigente(data_do_periodo).present?
			aditivo = aditivo_de_prazo_vigente(data_do_periodo)
			query_empenho_reconhecimento_de_divida = "reconhecimento_de_divida = true and aditivo_id  = #{aditivo.id}"
		else
			query_empenho_reconhecimento_de_divida = "reconhecimento_de_divida = true and aditivo_id is null"
		end

		valor = 0
		empenho_de_reconhecimento_de_divida = empenhos.where(query_empenho_reconhecimento_de_divida)
		empenho_de_reconhecimento_de_divida.each do |dea|
			valor += dea.definir_valor_do_empenho.to_f
		end
		return valor
	end

	def valor_a_empenhar
		valor_total_do_contrato.to_f - valor_empenhado.to_f
	end

	def valor_a_empenhar_no_periodo_vigente
		data_para_pesquisa = Date.today
		valor_do_contrato_no_periodo_vigente(data_para_pesquisa) - valor_empenhado_no_periodo_vigente(data_para_pesquisa) + valor_de_cancelamento_de_restos_a_pagar_nao_processados_no_periodo_vigente
	end

	def valor_de_cancelamento_de_restos_a_pagar_nao_processados
		empenhos.map { |emp| emp.valor_cancelado_nao_processado_na_data("#{contexto_atual.present? ? contexto_atual.exercicio : Date.today.year}-12-31".to_date).to_d }.sum
	end

	def valor_de_cancelamento_de_restos_a_pagar_nao_processados_no_periodo_vigente
		ano_atual = contexto_atual.present? ? contexto_atual.exercicio : Date.today.year
	
		empenhos.map do |emp|
			emp.restos_a_pagar_cancelados
				 .joins(:cancelamento_de_resto_a_pagar)
				 .where('EXTRACT(YEAR FROM contabilidade_cancelamentos_de_restos_a_pagar.data) = ?', ano_atual)
				 .where('COALESCE(contabilidade_cancelamentos_de_restos_a_pagar.tipo, 0) = 0 AND contabilidade_cancelamentos_de_restos_a_pagar.status = 1')
				 .distinct
				 .sum('COALESCE(valor_cancelado, 0)')
				 .to_d
		end.sum
	end
	

	def valor_do_contrato_no_periodo_vigente(data_do_periodo)
		valor_dos_aditivos_de_reajuste_de_valor = 0
		aditivo = aditivo_de_prazo_vigente(data_do_periodo)
		vigencia_do_contrato = dentro_da_vigencia_original_do_contrato(data_do_periodo)
		saldo_do_apostilamento = saldo_apostilados_vigente(data_do_periodo)

		if !vigencia_do_contrato && !aditivo.present?
			# contrato e aditivo está vencido
			valor = 0
		elsif vigencia_do_contrato
			# está dentro da vigencia do contrato

			data_inicio = self.inicio_da_vigencia
			data_fim = self.fim_da_vigencia

			valor_de_reajuste_de_acrescimo = 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 = aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia <= ?', data_fim).to_a.sum(&:valor_total).to_f
			aditivo_de_acrescimo = 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 = aditivos.confirmados.reducao.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', data_inicio, data_fim).sum(&:valor_total)

			valor = valor_do_contrato + (aditivo_de_acrescimo - aditivo_de_decrescimo) + ( valor_de_reajuste_de_acrescimo- valor_de_reajuste_de_decrescimo) - valor_reconhecimento_de_divida_do_periodo_vigente(data_fim) + valor_anulado_no_periodo_vigente(data_inicio, data_fim) + saldo_do_apostilamento

		elsif !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size > 0
			# está dentro da vigencia do aditivo
			valor_de_reajuste_de_acrescimo = aditivos.confirmados.reajuste_de_valor_acrescimo.where('licitacao_aditivos.inicio_da_vigencia >= ? AND licitacao_aditivos.inicio_da_vigencia <= ?', aditivo.inicio_da_vigencia, aditivo.fim_da_vigencia).to_a.sum(&:valor_total).to_f
			valor_de_reajuste_de_decrescimo = aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia >= ? AND licitacao_aditivos.inicio_da_vigencia <= ?', aditivo.inicio_da_vigencia, aditivo.fim_da_vigencia).to_a.sum(&:valor_total).to_f
			aditivo_de_acrescimo = aditivos.confirmados.acrescimo.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', aditivo.inicio_da_vigencia, aditivo.fim_da_vigencia).sum(&:valor_total)
			aditivo_de_decrescimo = aditivos.confirmados.reducao.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', aditivo.inicio_da_vigencia, aditivo.fim_da_vigencia).sum(&:valor_total)

			valor = aditivo.valor_total + (aditivo_de_acrescimo - aditivo_de_decrescimo) + (valor_de_reajuste_de_acrescimo - valor_de_reajuste_de_decrescimo) - valor_reconhecimento_de_divida_do_periodo_vigente(aditivo.inicio_da_vigencia) + valor_anulado_no_periodo_vigente(aditivo.inicio_da_vigencia, aditivo.fim_da_vigencia) + saldo_do_apostilamento

		elsif !vigencia_do_contrato && aditivo.present? && aditivo.itens_do_aditivo.size == 0
			# está na vigencia do aditivo de prazo, porem este não possui itens
			data_inicio = self.inicio_da_vigencia
			data_fim = aditivo.fim_da_vigencia
			valor_de_reajuste_de_acrescimo = 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 = aditivos.confirmados.reajuste_de_valor_decrescimo.where('licitacao_aditivos.inicio_da_vigencia <= ?', data_fim).to_a.sum(&:valor_total).to_f
			aditivo_de_acrescimo = 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 = aditivos.confirmados.reducao.where('licitacao_aditivos.data_do_aditivo >= ? and licitacao_aditivos.data_do_aditivo <= ?', data_inicio, data_fim).sum(&:valor_total)

			valor = valor_do_contrato + (aditivo_de_acrescimo - aditivo_de_decrescimo) + (valor_de_reajuste_de_acrescimo - valor_de_reajuste_de_decrescimo) - valor_reconhecimento_de_divida_do_periodo_vigente(data_fim) + valor_anulado_no_periodo_vigente(data_inicio, data_fim) + saldo_do_apostilamento
		end

		return valor
	end

	def valor_liquidado_total
		empenhos.sum(:valor_liquidado).round(2)
	end

	def saldo_dotacoes
		(valor_do_contrato - valor_total_das_dotacoes).to_f
	end

	def valor_total_das_dotacoes
		dotacoes_ativas.inject(0) do |soma, dotacao_ativa|
			soma + dotacao_ativa.valor.to_f
		end
	end

	def porcentagem_do_saldo_vigencia
		diferenca = (Date.today - self.inicio_da_vigencia).to_i.to_whole
		porcentagem = (( diferenca * 100).to_f / (data_final_de_acordo_com_aditivos - self.inicio_da_vigencia).to_whole).round(2)
		porcentagem.cap_at 100
	end

	def porcentagem_do_saldo_do_contrato
		if valor_total_do_contrato.positive?
			porcentagem = ( (valor_a_empenhar * 100).to_f / valor_total_do_contrato ).round(2)
		else
			0
		end
	end

	def prazo_aditado
		(data_final_de_acordo_com_aditivos - self.fim_da_vigencia)
	end

	def prazo_total
		(data_final_de_acordo_com_aditivos - self.inicio_da_vigencia).to_whole
	end

	def data_final_de_acordo_com_aditivos
		aditivos.confirmados.aditivos_de_prazo.maximum(:fim_da_vigencia) || self.fim_da_vigencia
	end

	def numero_de_meses_contratados
		((self.data_final_de_acordo_com_aditivos - self.inicio_da_vigencia)/30).to_f
	end

	def aditivos_de_prorrogacao_solicitado
		if self.aditivos.last.present?
			if self.aditivos.last.acrescimo?
				return "Solicitado"
			else
				return ""
			end
		else
			return ""
		end
	end

	def tempo_restante
		((data_final_de_acordo_com_aditivos || Date.today) - Date.today).to_whole
	end

	def alertar_dias_para_encerrar_contrato?
		if Configuracao.last.qtd_dias_para_encerrar_o_contrato.present? && !rescindido?
			(tempo_restante > 0 && tempo_restante <= Configuracao.last.try(:qtd_dias_para_encerrar_o_contrato) && Configuracao.last.try(:qtd_dias_para_encerrar_o_contrato) > 0) ? true : false
		end
	end

	def numero_da_solicitacao_do_contrato
		unless numero_da_solicitacao.blank?
			self.numero_da_solicitacao
		else
			self.data_da_solicitacao.strftime("%Y%m%d") if data_da_solicitacao.present?
		end
	end

	def numero_do_projeto_basico_do_contrato
		"#{unidade_orcamentaria_do_exercicio.try(:orgao).try(:codigo)}#{unidade_orcamentaria_do_exercicio.try(:codigo)}#{numero_da_solicitacao_do_contrato}"
	end


	def numero_do_pedido
		projeto.pedido.numero
	end

	def numero_de_contratos_de_dispensa_para_contratado
		if contratado && projeto.dispensa_de_licitacao?
			return pessoa_do_projeto.contratos.count
		end
	end

	def sim_tipo_obra_ou_servico
		codigo = case self.tipo_de_contrato
			when "contrato_de_obras" then "O"
			when "servico_de_engenharia" then "S"
			else ""
		end
	end

	def sim_tipo_de_contrato
		if projeto.parceria_osc?
			if self.termo_de_colaboracao?
				"TC"
			elsif self.termo_de_fomento?
				"TF"
			elsif self.acordo_de_cooperacao?
				"AC"
			end
		else
			obra_ou_servico? ? "E" : "O"
		end
	end

	def unidade_orcamentaria_do_exercicio
		if aditivos.confirmados.nova_unidade_orcamentaria.last.present? && aditivos.confirmados.nova_unidade_orcamentaria.last.unidade_orcamentaria.present?
			aditivos.confirmados.nova_unidade_orcamentaria.last.unidade_orcamentaria
		else
			Loa::UnidadeOrcamentaria.where(id: self.unidade_orcamentaria_do_exercicio_id).first
		end
	end

	def unidade_orcamentaria_atual
		if aditivos.confirmados.nova_unidade_orcamentaria.any?
			aditivos.confirmados.nova_unidade_orcamentaria.last.unidade_orcamentaria_atual
		else
			self.unidade_orcamentaria
		end
	end

	def unidade_orcamentaria_do_ultimo_aditivo_confirmado
		if aditivos.confirmados.any?
			aditivos.confirmados.last.unidade_orcamentaria_atual
		else
			self.unidade_orcamentaria
		end
	end

	def quantidade_dotacoes_ultimo_aditivo
		if aditivos.confirmados.nova_unidade_orcamentaria.any?
			aditivos.confirmados.nova_unidade_orcamentaria.last.orcamentos_da_despesa_do_aditivo.count
		end
	end

	def quantidade_dotacoes_ultimo_apostilamento
		if apostilamentos.present?
			apostilamentos.dotacao.last.orcamentos_da_despesa_do_apostilamento.count
		end
	end

	def orcamentos_ultimo_aditivo
		aditivos.confirmados.nova_unidade_orcamentaria.last.orcamentos_da_despesa
	end

	def orcamentos_ultimo_apostilamento
		apostilamentos.dotacao.last.orcamentos_da_despesa
	end

	def dotacoes_ultimo_aditivo
		aditivos.confirmados.nova_unidade_orcamentaria.last.orcamentos_da_despesa_do_aditivo
	end

	def dotacoes_ultimo_apostilamento
		apostilamentos.dotacao.last.orcamentos_da_despesa_do_apostilamento
	end

	def gera_lote_inicial_simplificado
		projeto.lotes.each do |lote_do_projeto|
			lotes_do_contrato.create(lote_id: lote_do_projeto.id, contrato_id: self.id)
		end
	end

	def update_data_de_envio_pro_sim(data)
		if data.blank?
			errors.add(:data_de_envio_pro_sim, "não pode ficar em branco")
			return false
		else
			lote_gerado = lote_gerado_para_o_mes_de_referencia(data)
			if lote_gerado.present?
				errors.add(:data_de_envio_pro_sim, "Já existe geração do lote do SIM para: #{lote_gerado.exercicio_e_nome_do_mes}")
				return false
			else
				self.update_column(:data_de_envio_pro_sim, data.to_date)
			end
		end
	end

	def update_unidade_orcamentaria_do_exercicio unidade_orcamentaria_do_exercicio_id
		self.update_column(:unidade_orcamentaria_do_exercicio_id, unidade_orcamentaria_do_exercicio_id)
	end

	def nao_envia_pro_sim
		self.update_columns(envia_pro_sim: false, data_de_envio_pro_sim: nil)
	end

	# TCM
	def to_sim
		begin
			valida_unidade_orcamentaria_do_exercicio
			valida_gestor_da_unidade
			gestor_da_unidade = unidade_orcamentaria_do_exercicio.unidade_gestora.gestor_no_periodo(self.data_do_contrato)

			texto = ""
			if projeto.parceria_osc?
				projeto.send(:valida_data_de_autuacao)
				valida_cpf_e_responsavel_dirigente

				texto << "537".to_s.sim_preenche(3) + ","
				texto << Configuracao.first.codigo_do_municipio_no_tcm.to_s.sim_preenche(3) + ","
				texto << self.data_do_contrato.sim_data + ","
				texto << self.numero.sim_limite(15) + ","
				texto << sim_tipo_de_contrato.sim_preenche(2) + ","
				texto << self.inicio_da_vigencia.sim_data + ","
				texto << self.fim_da_vigencia.sim_data + ","
				texto << self.objeto.gsub(/["\r\n]/, "").sim_limite(255) + ","
				texto << self.justificativa.gsub(/["\r\n]/, "").sim_limite(255) + ","
				texto << format("%.2f", valor_do_contrato.round(2)) + ","
				texto << contratado.pessoa_do_projeto.cpf_do_responsavel.sim_limite(11) + ","
				texto << contratado.pessoa_do_projeto.nome_do_responsavel.sim_limite(40) + ","
				texto << gestor_da_unidade.cpf.sim_preenche(11) + ","
				texto << gestor_da_unidade.nome.sim_limite(40) + ","
				texto << projeto.data_de_autuacao.sim_data + ","
				texto << projeto.numero_do_processo.sim_limite(15) + ","
				texto << projeto.sigla_da_modalidade_do_processo.sim_preenche(1) + ","
				texto << (contratado.pessoa.pessoa_juridica? ? contratado.pessoa.cnpj : contratado.pessoa.cpf).sim_limite(14) + ","
			else
				valida_contrato_de_obra
				fiscal = self.fiscais_do_contrato.where(ativo: true).last&.agente_publico_municipal&.pessoa

				texto << "511".to_s.sim_preenche(3) + "," #1
				texto << Configuracao.first.codigo_do_municipio_no_tcm.to_s.sim_preenche(3) + "," #2
				texto << gestor_da_unidade.cpf.sim_preenche(11) + "," #3
				texto << self.numero.sim_limite(15) + "," #4
				texto << self.data_do_contrato.sim_data + "," #5
				texto << sim_tipo_de_contrato.sim_preenche(1) + "," #6
				texto << "OR".sim_limite(2) + "," #7 Contrato Original
				texto << "".sim_limite(1) + "," #8 Informar apenas se for aditivo
				texto << "".sim_limite(1) + "," #9 Informar apenas se for aditivo
				texto << "0" + "," #10 Informar apenas se for aditivo
				texto << self.inicio_da_vigencia.sim_data + ","#11
				texto << self.fim_da_vigencia.sim_data + "," #12
				texto << (self.objeto.blank? ? projeto.pedido.objeto.gsub(/["\r\n]/, "").sim_limite(255) : self.objeto.gsub(/["\r\n]/, "").sim_limite(255)) + "," #13
				texto << format("%.2f", valor_do_contrato.round(2)) + "," #14
				texto << (!obra.nil? ? obra.data_de_inicio.sim_data : "0") + "," #15
				texto << sim_tipo_obra_ou_servico.sim_limite(1) + "," #16
				texto << (obra.nil? ? "" : obra.codigo).sim_limite(4) + "," #17
				texto << (!obra.nil? ? obra.data_prevista_de_termino.sim_data : "0") + "," #18
				texto << self.data_de_envio_pro_sim.sim_data.to_s.first(6) + "," #19
				texto << (self.projeto.arquivo_id.to_i > 0 ? self.projeto.data_de_autuacao.sim_data : '0') + "," #20
				texto << (self.projeto.arquivo_id.to_i > 0 ? self.projeto.numero_do_processo.sim_limite(15) : '""') + "," #21
				texto << (fiscal.cpf.to_s.sim_preenche(11) rescue "") + "," #22
				texto << (fiscal.nome.to_s.sim_descricao.delete('"').sim_limite(40) rescue "") + "," #23
				texto << self.pncp_id.to_s.sim_limite(25) #24

			end
			return texto
		rescue => e
			if e.class.to_s == "NoMethodError"
				atributo_falho = e.message.split(" ")[2]
				coluna = CSV.parse(texto, :headers => false).last.count
				raise e.mensagem_traduzida(self, self.numero, atributo_falho, coluna)
			else
				raise e
			end
		end
	end

	# VALIDAÇÕES
	def valida_unidade_orcamentaria_do_exercicio
		if unidade_orcamentaria_do_exercicio.nil?
			raise "O Contrato #{self.numero} não possui uma Unidade Orçamentária para seu exercício (#{orcamento.exercicio}). Deve ser vinculada uma manualmente."
		end
	end

	def valida_gestor_da_unidade
		unid = self.unidade_orcamentaria.unidade_gestora.data_encerramento.present? && self.data_do_contrato <= self.unidade_orcamentaria.unidade_gestora.data_encerramento ? self.unidade_orcamentaria : self.unidade_orcamentaria_do_exercicio
		if unid.present? && !unid.unidade_gestora.gestor_no_periodo(self.data_do_contrato).present?
			raise "Não existe gestor ativo para a Unidade Gestora: " << "#{unid.unidade_gestora.nome}" << " na data #{self.data_do_contrato}"
		end
	end

	def valida_cpf_e_responsavel_dirigente
		if contratado.pessoa_do_projeto.cpf_do_responsavel.blank? || contratado.pessoa_do_projeto.nome_do_responsavel.blank?
			raise "Não foi informado o CPF ou Nome do Responsável Licitante no Processo Nº: #{projeto.numero_do_processo.to_s}. Deve ser vinculado um manualmente."
		end
	end

	def valida_contrato_de_obra
		if obra_ou_servico? && !obra.present?
			raise "Não existe uma obra para o Contrato Nº: #{self.numero.to_s} do tipo: #{self.tipo_de_contrato.humanize}"
		end
	end

	def lote_gerado_para_o_mes_de_referencia(data_de_referencia)
		mes = data_de_referencia.to_date.month
		ano = data_de_referencia.to_date.year
		orcamento_da_data_referencia = Orcamento.find_by(exercicio: ano)
		#Ultima geracao do SIM para o mes_de_referencia
		geracao_do_lote_pro_sim = orcamento_da_data_referencia.lotes_do_tcm.licitacao.gerado.where(mes_de_referencia: mes).last if orcamento_da_data_referencia.present?
	end

	def data_de_envio_pro_sim_valida?
		if self.data_de_envio_pro_sim.present?
			data_ja_tem_lote_gerado = lote_gerado_para_o_mes_de_referencia(self.data_de_envio_pro_sim).present?
		else
			data_ja_tem_lote_gerado = false
		end

		return !data_ja_tem_lote_gerado
	end

	def numero_e_contratado
		"#{self.numero.to_s + " - " + pessoa.nome}"
	end

	def exclui_lotes_desmarcados_do_contrato
		if self.lotes_marcados_para_excluir.present? && self.lotes_marcados_para_excluir.any?
			lotes_do_contrato_para_excluir = self.lotes_do_contrato.where(lote_id: self.lotes_marcados_para_excluir)
			itens_id = lotes_do_contrato_para_excluir.map { |lote_do_contrato| lote_do_contrato.lote.itens_do_lote.ids }.flatten

			self.itens_do_contrato.where(item_do_lote_id: itens_id).destroy_all
			lotes_do_contrato_para_excluir.destroy_all
		end
	end

	def esta_solicitado?
		status_solicitado = aberto? || enviado_para_licitacao? || ( ( ata_de_registro_de_precos.present? && confirmado? ) )

		status_solicitado && itens_do_contrato.any? && dotacoes_ativas.any?
	end

	def saldo_acresido_apostilamento
		return self.itens_do_contrato.sum(&:saldo_acresido_apostilamento)
	end

	def saldo_reduzido_apostilamento
		return self.itens_do_contrato.sum(&:saldo_reduzido_apostilamento)
	end

	def saldo_a_empenhar_do_item(item_do_lote)
		itens_do_contrato.find_by(item_do_lote_id: item_do_lote.try(:id)).try(:saldo).to_d
	end

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

	def existe_lote_do_sim?
		ultima_data = data_de_envio_pro_sim

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

	def fornecedor
		pessoa_do_projeto.try(:pessoa)
	end

	def saldo_a_liquidar
		empenhos = self.empenhos.where.not(status: :anulado)
		(empenhos.sum(&:valor_total_do_empenho) - empenhos.sum(&:valor_liquidado)) + empenhos.sum(&:valor_liquidado_estornado) + valor_a_empenhar
	end

	def ultimo_responsavel_do_pedido
		responsavel_do_pedido || unidade_orcamentaria_por_pedido.responsavel_do_pedido
	end

	def pode_imprimir_relatorios_do_pedido?
		respeita_parametrizacao_responsavel_do_pedido? && itens_do_contrato.present? && orcamentos_da_despesa_do_contrato.present? &&
		ata_de_registro_de_preco_id.present? && dotacoes_batem_com_valor_do_contrato?
	end

	def respeita_parametrizacao_responsavel_do_pedido?
		Configuracao.last.obriga_responsavel_pelo_pedido? == false ||
		(Configuracao.last.obriga_responsavel_pelo_pedido? && ultimo_responsavel_do_pedido.present?)
	end


	private
	def atribui_numero_da_solicitacao
		if self.data_da_solicitacao_changed? && self.data_da_solicitacao.present?
			gerar_codigo(data_da_solicitacao, :numero_da_solicitacao, :data_da_solicitacao, :orcamento_id, self.orcamento_id)
		end
	end

	def criar_lotes_do_contrato
		lotes_ganhador = self.contratado.pessoa_do_projeto.lotes_ganhos_ativos
		lotes_ganhador.each do |lote_ganhador|
			self.lotes_do_contrato.create(lote_id: lote_ganhador.id, contrato_id: self.id)
		end
	end

	def criar_itens_contrato
		if self.ata_de_registro_de_precos.present?
			itens_da_ata = self.ata_de_registro_de_precos.itens_da_ata
			itens_da_ata.each do |item_da_ata|
				item_do_contrato = self.itens_do_contrato.find_by(item_do_lote_id: item_da_ata.item_do_lote.id)
				if  item_da_ata.item_do_lote.lote.lote_por_preco? &&  item_da_ata.item_do_lote.item_do_pedido.quantidade_por_unidade_orcamentaria(unidade_orcamentaria.id) > 0
					valor_total = (item_da_ata.item_do_lote.item_do_pedido.quantidade_por_unidade_orcamentaria(unidade_orcamentaria.id)) * item_da_ata.item_do_lote.preco_unitario
					self.itens_do_contrato.create!( item_do_lote_id:  item_da_ata.item_do_lote.id, quantidade:  item_da_ata.item_do_lote.item_do_pedido.quantidade_por_unidade_orcamentaria(unidade_orcamentaria.id), total: valor_total) unless item_do_contrato.present?
				elsif  item_da_ata.item_do_lote.lote.lote_por_desconto?
					self.itens_do_contrato.create!( item_do_lote_id:  item_da_ata.item_do_lote.id, quantidade: 1, total: item_da_ata.item_do_lote.preco_unitario) unless item_do_contrato.present?
				end
			end
		else
			itens_do_lote_do_contrato = itens_dos_lotes.ativos
			itens_dos_lotes.ativos.each do |item_do_lote|
				item_do_contrato = self.itens_do_contrato.find_by(item_do_lote_id: item_do_lote.id)
				if item_do_lote.lote.lote_por_preco? && ( item_do_lote.item_do_pedido.quantidade_por_unidade_orcamentaria(unidade_orcamentaria.id) > 0 && item_do_lote.saldo_por_unidade(unidade_orcamentaria.id) > 0 )
					valor_total = (item_do_lote.saldo_por_unidade(unidade_orcamentaria.id)) * item_do_lote.preco_unitario
					self.itens_do_contrato.create!(item_do_lote_id: item_do_lote.id, quantidade: item_do_lote.saldo_por_unidade(unidade_orcamentaria.id), total: valor_total) unless item_do_contrato.present?
				elsif item_do_lote.try(:item_do_pedido).try(:por_valor_previsto?)
					valor_total = item_do_lote.saldo_preenchido_na_unidade(unidade_orcamentaria.id).to_d
					if valor_total > 0
						self.itens_do_contrato.create!(item_do_lote_id: item_do_lote.id, quantidade: 1, total: valor_total) if item_do_contrato.nil?
					end
				elsif item_do_lote.lote.lote_por_desconto?
					self.itens_do_contrato.create!(item_do_lote_id: item_do_lote.id, quantidade: 1, total: item_do_lote.preco_unitario) unless item_do_contrato.present?
				end
			end
		end
	rescue => e
		if (e.record.errors.messages.keys.include? :quantidade)
			errors.add(:base, "O saldo desse lote já foi contratado por completo.")
		end
		raise
	end

	def criar_operacoes_e_acoes_no_contrato
		ActiveRecord::Base.transaction do
			# Cria as operações de créditos no contrato
			self.projeto.operacoes_de_credito_do_projeto.each do |operacao_de_credito_do_projeto|
				operacao_de_credito_do_contrato = Licitacao::OperacaoDeCreditoDoContrato.new(
					contrato: self,
					operacao_de_credito: operacao_de_credito_do_projeto.operacao_de_credito,
				)

				operacao_de_credito_do_contrato.save

				# Cria as ações das operações de créditos no contrato
				if operacao_de_credito_do_projeto.acoes_da_operacao_de_credito_do_projeto.any?
					operacao_de_credito_do_projeto.acoes_da_operacao_de_credito_do_projeto.each do |acao_da_operacao_de_credito_do_projeto|
						acao_da_operacao_de_credito_do_contrato = Licitacao::AcaoDaOperacaoDeCreditoDoContrato.new(
							componente_da_operacao_de_credito: acao_da_operacao_de_credito_do_projeto.componente_da_operacao_de_credito,
							acao_do_componente: acao_da_operacao_de_credito_do_projeto.acao_do_componente,
							operacao_de_credito_do_contrato: operacao_de_credito_do_contrato
						)
						acao_da_operacao_de_credito_do_contrato.save(validate: false)
					end
				end
			end
		end
	end

	def seta_pessoa_do_projeto
		pessoa_do_projeto = Licitacao::PessoaDoProjeto.find_by(projeto_id: projeto.id, pessoa_id: fornecedor_id)
		if pessoa_do_projeto.nil?
			pessoa_do_projeto = Licitacao::PessoaDoProjeto.create(projeto_id: projeto.id, pessoa_id: fornecedor_id, nome_do_responsavel: nome_do_responsavel, cpf_do_responsavel: cpf_do_responsavel)
		end
		self.pessoa_do_projeto_id = pessoa_do_projeto.id
		seta_contratado
	end

	def seta_contratado
		if !self.pessoa_do_projeto_id.blank?
			contratado = Licitacao::Contratado.create(pessoa_do_projeto_id: pessoa_do_projeto_id)
			self.contratado = contratado
		else
			errors.add(:contratado_id, "Informe o ganhador")
		end
	end

	def seta_unidade_orcamentaria_do_exercicio_atual
		if unidade_orcamentaria_por_pedido.present?
			if unidade_orcamentaria_por_pedido.unidade_orcamentaria.orgao.orcamento.exercicio == orcamento.try(:exercicio)
				self.unidade_orcamentaria_do_exercicio_id = self.unidade_orcamentaria_por_pedido.unidade_orcamentaria.id
			else
				cod_orgao = unidade_orcamentaria_por_pedido.unidade_orcamentaria.orgao.codigo
				cod_unidade = unidade_orcamentaria_por_pedido.unidade_orcamentaria.codigo
				unidade_orcamentaria_do_exercicio = Loa::UnidadeOrcamentaria.joins(:orgao).find_by(codigo: cod_unidade, loa_orgaos: {codigo: cod_orgao, orcamento_id: orcamento.try(:id)})
				if unidade_orcamentaria_do_exercicio.blank? && orcamento.present?
					unidade_orcamentaria_do_exercicio = orcamento.unidades_orcamentarias.joins(:unidades_orcamentaria_vinculada)
						.find_by('loa_unidades_orcamentaria_vinculada.unidade_orcamentaria_vinculada_id = ?', self.unidade_orcamentaria.id)
				end
				self.unidade_orcamentaria_do_exercicio_id = unidade_orcamentaria_do_exercicio.id unless unidade_orcamentaria_do_exercicio.nil?
				errors.add(:unidade_orcamentaria_por_pedido_id, "Esta Unidade é de outro exercício e não possui equivalente no atual") if unidade_orcamentaria_do_exercicio.nil?
			end
		end
	end

	def exclui_lotes_do_contrato
		self.lotes_do_contrato.select(&:persisted?).each{|lote_do_contrato| lote_do_contrato.delete} if lotes_do_contrato.select(&:persisted?).size > 0 && self.persisted? && !tem_itens?
	end

	def verifica_unicidade_do_numero_do_contrato
		if self.contratado && self.contratado.pessoa_do_projeto != nil && self.numero.present?
			qtd_de_contratos = self.projeto.contratos.where(numero: self.numero).where.not(id: self.try(:id)).count rescue 0
			errors.add(:numero, "Número do contrato deve ser único") if qtd_de_contratos.to_i > 0
		end
	end

	def data_do_contrato_dentro_do_exercicio
		return if data_do_contrato.blank? || importado_do_tcm? || tem_lote_de_servico?
		return if data_do_contrato.year == orcamento.try(:exercicio)

		msg = "Deve estar contida no exercício do Orçamento logado (#{orcamento.try(:exercicio)})"
		errors.add(:data_do_contrato, msg)
	end

	def data_da_solicitacao_contrato_dentro_do_exercicio
		return if data_da_solicitacao.blank?
		return if data_da_solicitacao.year == orcamento.exercicio

		msg = "Deve ser no mesmo exercício do Orçamento logado (#{orcamento.exercicio})"
		errors.add(:data_da_solicitacao, msg)
	end


	def data_do_contrato_apos_data_do_projeto
		return if data_do_contrato.blank? || contratado.blank?
		data_do_projeto = contratado.pessoa_do_projeto.projeto.data_do_projeto
		return if data_do_contrato >= data_do_projeto

		msg = "Deve ser maior ou igual à data do projeto (#{data_do_projeto})"
		errors.add(:data_do_contrato, msg)
	end

	def data_do_contrato_apos_o_inicio_da_vigencia
		if self.data_do_contrato.present? && self.inicio_da_vigencia.present?
			msg = "Não deve ser posterior à data do início da vigência: (#{self.inicio_da_vigencia})"
			errors.add(:data_do_contrato, msg) if self.data_do_contrato > self.inicio_da_vigencia
		end
	end

	def inicio_da_vigencia_apos_data_do_projeto
		return if inicio_da_vigencia.blank? || contratado.blank?
		data_do_projeto = contratado.pessoa_do_projeto.projeto.data_do_projeto
		return if inicio_da_vigencia >= data_do_projeto

		msg = "Deve ser maior ou igual à data do projeto (#{data_do_projeto})"
		errors.add(:inicio_da_vigencia, msg)
	end

	def inicio_da_vigencia_dentro_da_vigencia_da_ata(arp = ata_de_registro_de_precos)
		return if inicio_da_vigencia.blank?
		return if (inicio_da_vigencia >= arp.data_inicio_de_vigencia && inicio_da_vigencia <= arp.data_final_de_vigencia)

		msg = "Deve estar dentro do período de vigência da ARP (#{arp.data_inicio_de_vigencia} - #{arp.data_final_de_vigencia})"
		errors.add(:inicio_da_vigencia, msg)
	end

	def valor_total_nao_pode_ser_maior_que_a_origem
		if de_ata?
			errors.add(:valor, "Deve ser menor ou igual o saldo da ata") if ata_de_registro_de_precos.valor_a_contratar.to_f + valor_was.to_f < valor.to_f
		else
			errors.add(:valor, "Deve ser menor ou igual o saldo do processo") if valor.to_f > projeto.valor_a_contratar + valor_was.to_f
		end
	end

	def valor_dentro_do_disponivel_para_unidade_gestora
		if ata_de_registro_de_precos.valor_total_por_unidade(unidade_orcamentaria_por_pedido.unidade_orcamentaria).to_f < self.valor.to_f
			errors.add(:valor, "Deve ser menor ou igual ao saldo disponível em #{unidade_orcamentaria_por_pedido.unidade_orcamentaria.nome}.")
		end
	end

	def fim_da_vigencia_apos_inicio_da_vigencia
		return if inicio_da_vigencia.blank? || fim_da_vigencia.blank? || fim_da_vigencia > inicio_da_vigencia

		errors.add(:fim_da_vigencia, "Deve ser no mínimo um dia após o início da vigência")
	end

	def data_da_solicitacao_dentro_da_vigencia_da_ata(arp = ata_de_registro_de_precos)
		return if data_da_solicitacao.blank?
		return if (data_da_solicitacao >= arp.data_inicio_de_vigencia && data_da_solicitacao <= arp.data_final_de_vigencia)

		msg = "Deve estar dentro da vigência da ARP (#{arp.data_inicio_de_vigencia} - #{arp.data_final_de_vigencia})"
		errors.add(:data_da_solicitacao, msg)
	end

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

	#foi pedido a retirada da validação abaixo
	def verifica_existencia_de_contrato_vigente_com_mesmo_item
		if tem_itens? && contratos_vigentes = self.projeto.contratos_vigentes.where.not(id: self).joins(itens_do_contrato: :item_do_lote).where(licitacao_itens_do_lote: {id: self.itens_do_lote_do_contrato_ids}).joins(
				:unidade_orcamentaria_por_pedido).where(licitacao_unidades_orcamentarias_por_pedido: {id: self.unidade_orcamentaria_por_pedido.id})
			contratos_vigentes_no_mesmo_periodo = contratos_vigentes.select {|contrato|
				self.inicio_da_vigencia.between?(contrato.inicio_da_vigencia, contrato.fim_da_vigencia) ||
					self.fim_da_vigencia.between?(contrato.inicio_da_vigencia, contrato.fim_da_vigencia)
				}
			[:inicio_da_vigencia, :fim_da_vigencia].each do |vigencia|
				errors.add(vigencia, "Existe contrato vigente para o período de vigência informado com o mesmo item")
			end if contratos_vigentes_no_mesmo_periodo.any?
		end
	end

	# Validação retirada
	def valida_quantidade_de_contratos
		if numero_de_contratos_de_dispensa_para_contratado != nil && numero_de_contratos_de_dispensa_para_contratado > 0
			errors.add(:base, "Processos de dispensa só podem possuir um contrato para cada ganhador")
		elsif self.contratado && self.contratado.pessoa_do_projeto && self.projeto.processo_licitatorio? && !self.contratado.pessoa_do_projeto.projeto.registro_de_preco? && self.contratado.pessoa_do_projeto.projeto.contratos.count > 0
			errors.add(:base, "Processos Licitatórios que não são registro de preço só podem possuir um contrato")
		end
	end

	def data_da_solicitacao_menor_ou_igual_a_data_do_contrato
		errors.add(:data_da_solicitacao, "Não pode ser maior que #{data_do_contrato}") if data_da_solicitacao > data_do_contrato
	end
end
