class GestaoDeEstoque::RecebimentoDeMaterial < ApplicationRecord
	has_paper_trail

	include GeradorDeEventosContabeis
	include AASM
	include TradutorConcern
	include IncrementadorDeCodigoConcern
	include EnumModalidadeDeLicitacaoConcern

	#gerador_de_eventos_contabeis codigo: 10, atributo_data: 'data_do_recebimento', atributo_codigo_movimentacao: 'codigo'

	attr_default :classificacao, :compra
	
	attr_accessor :itens_do_recebimento_de_materiais_hidden
	attr_accessor :converte_unidades

	belongs_to :transferencia, class_name: "GestaoDeEstoque::Transferencia"
	belongs_to :orcamento, class_name: "Orcamento"
	belongs_to :ordem_de_compra, class_name: "Licitacao::OrdemDeCompra"
	belongs_to :fornecedor, class_name: "Base::Pessoa", foreign_key: "fornecedor_id"
	belongs_to :doador, class_name: "Base::Pessoa", foreign_key: "doador_id"
	belongs_to :unidade_orcamentaria, class_name: "Loa::UnidadeOrcamentaria"
	belongs_to :almoxarifado, class_name: "GestaoDeEstoque::Almoxarifado"
	belongs_to :almoxarifado_de_destino, class_name: "GestaoDeEstoque::Almoxarifado", foreign_key: :almoxarifado_de_destino_id
	belongs_to :unidade_orcamentaria_de_destino, class_name: "Loa::UnidadeOrcamentaria", foreign_key: :unidade_orcamentaria_de_destino_id
	belongs_to :devolucao_de_material, class_name: "GestaoDeEstoque::DevolucaoDeMaterial"
	belongs_to :sub_elemento_de_despesa, class_name: "Contabilidade::SubElementoDeDespesa", foreign_key: :sub_elemento_de_despesa_id
	belongs_to :classificacao_do_detalhamento, class_name: "Contabilidade::SubElementoDeDespesa", foreign_key: :classificacao_do_detalhamento_id

	delegate :empenho, :elemento_de_despesa, to: :ordem_de_compra, :allow_nil => true

	has_one :recebimento_de_bem, class_name: 'Patrimonio::RecebimentoDeBem'
	has_many :itens_do_recebimento_de_materiais, class_name: "GestaoDeEstoque::ItemDoRecebimentoDeMaterial", dependent: :destroy
	has_many :itens, through: :itens_do_recebimento_de_materiais
	has_many :movimentacoes_do_estoque, as: :origem
	has_many :informacoes_extras, through: :itens_do_recebimento_de_materiais
	has_many :ocorrencias_dos_recebimentos_de_materiais, class_name: "GestaoDeEstoque::OcorrenciaDoRecebimentoDeMaterial"

	accepts_nested_attributes_for :itens_do_recebimento_de_materiais, allow_destroy: true
	accepts_nested_attributes_for :informacoes_extras, allow_destroy: true

	# sempre obrigatório
	# validate :valida_obrigatoriedade_itens_do_recebimento_de_materiais
	validate :valida_se_data_da_nota_fiscal_eh_maior_que_data_do_recebimento, if: Proc.new { self.data_de_emissao.present? && self.data_do_recebimento.present?}
	validate :valida_data_de_emissao_da_nota_fiscal_maior_que_data_do_empenho, unless: Proc.new { self.classificacao.present? }
	validate :valida_quantidades_recebimento_parcial, if: Proc.new{ self.recebimento_parcial? }
	# validate :valida_se_existe_quantidade_recebida, if: Proc.new{ self.recebimento_parcial? && self.itens_do_recebimento_de_materiais.any? } Evitando recebimento parcial de passar tela
	validate :nao_pode_criar_recebimento_com_mes_encerrado, on: :create

	# validações
	validates_presence_of :codigo, :data_do_recebimento, :tipo_de_material, :orcamento_id, :almoxarifado_id, :unidade_orcamentaria_id, :status, :tipo_de_entrada
	validates_presence_of :almoxarifado_de_destino_id, :unidade_orcamentaria_de_destino_id, if: Proc.new { self.remota? }
	validates_presence_of :doador_id, if: Proc.new { self.classificacao.present? && self.eh_doacao? }
	# validates_presence_of :fornecedor_id, if: Proc.new { self.entrada_por_outros? } Deve ser usado quando for ajustar o patrimonio, pois o fornecedor está vazio e poderá quebrar a tela
	validates_presence_of :sub_elemento_de_despesa_id, if: Proc.new { self.classificacao.present? && self.permanente? }
	validates_presence_of :tipo_de_entrada, unless: Proc.new { self.classificacao.present? }
	# validates_absence_of :ordem_de_compra_id, if: Proc.new { self.classificacao.present? }
	validates_associated :itens_do_recebimento_de_materiais, on: :create_or_update
	validates_length_of :codigo, maximum: 8
	validates_length_of :numero_da_nota, maximum: 15
	validates_length_of :serie, maximum: 5
	validates_length_of :observacao, maximum: 600

	# informações adicionais

	# itens do recebimento de materiais
	validates :itens_do_recebimento_de_materiais, uniq_nested_attributes: { atributo: :item_id, mensagem: "item deve ser único dentro de um recebimento" }
	validates :data_do_recebimento, sabado_ou_domingo_ou_feriado: { flexivel: false }

	before_validation :atribui_codigo_disponivel
	before_validation :preenche_sub_elemento_pela_ordem_de_compra, if: Proc.new { self.ordem_de_compra.present? }

	after_save :altera_status_da_ordem_de_compra, if: Proc.new { recebimento_foi_concluido? }
	after_save :altera_status_da_devolucao_de_material, if: Proc.new { self.devolucao_estorno? }
	after_save :tornar_definitivo, if: Proc.new { self.tipo_de_entrada_was == 'provisorio' && self.tipo_de_entrada == 'definitivo' }
	before_create :atribui_elemento_de_despesa, if: Proc.new { self.ordem_de_compra_id.present? }

	before_destroy :altera_status_da_ordem_de_compra_para, if: Proc.new{ self.possui_ordem_de_compra? }
	before_save :lancar_ocorrencia

	enum status: {
		aberto: 0,
		recebido_parcialmente: 2,
		recebido: 3,
		confirmado: 4,
		devolvido_ao_fornecedor: 5,
		enviado_ao_patrimonio: 6
	}

	enum classificacao: {
		doacao: 0,
		devolucao_estorno: 1,
		ajuste_de_inventario: 2,
		transferencia: 3 ,
		remoto: 4,
		requisicao: 5,
		confeccao: 6,
		compra: 7,
		cessao: 8,
		comodato: 9,
		implantacao: 10,
		locacao: 11,
		permuta: 12,
		reintegracao: 13,
		dacao: 14
	}

	enum tipo_de_material: {
		consumo: 0,
		permanente: 1,
		consumo_distribuicao_gratuita: 2
	}

	enum tipo_de_entrada: {
		definitivo: 0,
		provisorio: 1,
		remota: 2
	}

	enum tipo_de_recebimento: {
		recebimento_total: 0,
		recebimento_parcial: 1
	}

	enum odor: {
		ruim: 0,
		regular: 1,
		bom: 2
	}

	enum textura: {
		textura_ruim: 0,
		textura_regular: 1,
		textura_bom: 2
	}

	enum cor: {
		cor_ruim: 0,
		cor_regular: 1,
		cor_bom: 2
	}

	enum aspecto_geral: {
		aspecto_geral_ruim: 0,
		aspecto_geral_regular: 1,
		aspecto_geral_bom: 2
	}

	enum condicao_da_embalagem: {
		rasgada_furada: 0,
		amassada: 1,
		bom_estado: 2
	}

	#retirar esse Enum
	enum classificacao_tipo_de_material: {
		material_de_expediente: 0,
		material_de_consumo: 1,
		generos_alimenticios: 2,
		materiais_de_construcao: 3,
		autopecas: 4,
		medicamentos_e_materiais_hospitalares: 5,
		materiais_graficos: 6
	}

	enum status_de_reconhecimento:{
		aguardando_reconhecimento: 1,
		reconhecido: 2
	}

	aasm column: :status, enum: true, whiny_transitions: false do
		state :aberto, :initial => true
		state :recebido_parcialmente
		state :recebido
		state :confirmado
		state :devolvido_ao_fornecedor
		state :enviado_ao_patrimonio

		event :receber do
			transitions from: :aberto, to: :recebido do
				guard do
					self.itens_do_recebimento_de_materiais.any? && self.recebimento_total? || self.itens_do_recebimento_de_materiais.any? && self.tipo_de_recebimento.blank?
				end
				after do
					if self.definitivo?
						self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
							item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
							item_do_recebimento_de_material.corrige_estoque_duplicados
						end
					elsif self.remota?
						self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
							item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
						end
						cria_transferencia
						cria_consumo
					end
				end
			end
		end

		event :receber_parcialmente do
			transitions from: :aberto, to: :recebido_parcialmente do
				guard do
					self.itens_do_recebimento_de_materiais.any? && self.recebimento_parcial?
				end
				after do
					if self.definitivo?
						self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
							item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
						end
					elsif self.remota?
						self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
							item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
						end
						cria_transferencia
						cria_consumo
					end
				end
			end
		end

		event :devolver_ao_fornecedor do
			transitions from: :recebido, to: :devolvido_ao_fornecedor do
				guard do
					self.provisorio? && !movimentacoes_do_plano_de_contas.any?
				end
				after do
					self.remove_movimentacao_do_estoque
				end
			end
		end

		event :reabrir do
			transitions from: [:recebido, :recebido_parcialmente], to: :aberto do
				guard do
					self.recebimento_foi_concluido?
				end
				after do
					self.remove_movimentacao_do_estoque
					self.altera_status_da_ordem_de_compra_para
				end
			end
		end

		event :enviar_ao_patrimonio do
			before do
				cria_recebimento_de_bem_no_patrimonio
			end
			transitions from: [:recebido, :recebido_parcialmente], to: :enviado_ao_patrimonio do
				guard do
					self.permanente?
				end
			end
		end
	end

	def existe_encerramento?
		encerramento = GestaoDeEstoque::ControleDoAlmoxarifado.all.select{ |control| control.data_de_encerramento.month == self.data_do_recebimento.month && control.data_de_encerramento.year == self.data_do_recebimento.year }.sort_by(&:data_de_encerramento).last rescue nil if GestaoDeEstoque::ControleDoAlmoxarifado.any? && self.data_do_recebimento.present?
		if encerramento.present? && self.data_do_recebimento.present?
			false
		else
			true
		end
	end

	def recebimento_foi_concluido?
		self.recebido? || self.recebido_parcialmente?
	end

	def entrada_por_outros?
		self.doacao? || self.implantacao? || self.ajuste_de_inventario?
	end

	def eh_perecivel?
		self.perecivel?
	end

	def eh_transferencia?
		self.transferencia?
	end

	def eh_doacao?
		self.doacao?
	end

	def possui_classificacao?
		self.classificacao.present?
	end

	def nao_possui_classificacao?
		!self.classificacao.present?
	end

	def possui_data_de_emissao?
		self.data_de_emissao.present?
	end

	def possui_ordem_de_compra?
		self.ordem_de_compra.present?
	end

	def possui_informacoes_adicionais?
		if eh_farmaceutico?
			lote.present? && registro_no_ministerio_da_saude.present? && validade.present? && condicao_da_embalagem.present?
		elsif eh_alimenticio?
			if eh_perecivel?
				lote.present? && validade.present? && odor.present? && textura.present? && cor.present? && aspecto_geral.present? && condicao_da_embalagem.present?
			else
				condicao_da_embalagem.present? && lote.present?
			end
		elsif eh_limpeza?
			condicao_da_embalagem.present? && lote.present? && validade.present?
		else
			return true
		end
	end

	def possui_codigo?
		self.codigo.present?
	end

	def valida_quantidades_recebimento_parcial
		if self.itens_do_recebimento_de_materiais.present?
			quantidade_disponivel = self.ordem_de_compra.itens_da_ordem_de_compra.to_a.sum(&:quantidade).to_f
			quantidade_total = self.itens_do_recebimento_de_materiais.to_a.sum(&:quantidade).to_f
			errors.add(:base, "Não pode receber todos os itens disponíveis em um recebimento parcial.") if quantidade_disponivel == quantidade_total
		end
	end

	def valida_se_existe_quantidade_recebida
		if self.itens_do_recebimento_de_materiais.to_a.sum(&:quantidade).to_f == 0
			errors.add(:base, "É necessário receber pelo menos 1 item")
		end
	end

	def possui_tipo_de_recebimento?
		self.tipo_de_recebimento.present?
	end

	def enviado_para_almoxarifado?
		self.ordem_de_compra.enviado_para_almoxarifado?
	end

	def recebido_pelo_almoxarifado?
		self.ordem_de_compra.recebido_pelo_almoxarifado? || (self.ordem_de_compra.recebido_parcialmente_pelo_almoxarifado? && self.ordem_de_compra.recebimento_de_materiais.count == 1)
	end

	def altera_status_da_ordem_de_compra
		if possui_ordem_de_compra?
			if self.recebimento_total? || !self.ordem_de_compra.possui_itens_a_receber?
				self.ordem_de_compra.confirmar_recebimento_almoxarifado!
			else
				self.ordem_de_compra.confirmar_recebimento_parcial_almoxarifado!
			end
		end
	end

	def retorna_unidade_orcamentaria
		if unidade_orcamentaria.present?
			unidade_orcamentaria
		else
			possui_ordem_de_compra? ? ordem_de_compra.unidade_orcamentaria : nil
		end
	end

	def retorna_almoxarifado
		if almoxarifado.present?
			almoxarifado
		else
			possui_ordem_de_compra? ? ordem_de_compra.try(:almoxarifado) : nil
		end
	end

	def detalhamento_do_plano_de_contas conta_por_evento_contabil
		detalhamento = ""
		if possui_ordem_de_compra?
			#1.1.5.0.0.00.00 – ESTOQUES – PO/FP/NF/DENF/NE/CPF OU CNPJ
			#2.1.3.1.1.01.01 – FORNECEDORES NÃO PARCELADOS A PAGAR – PO/FP/FR/NF/DENF/NE/CPF OU CNPJ.
			#2.1.3.1.1.01.02 – FORNECEDORES PARCELADOS A PAGAR - PO/FP/DC/FR/NF/DENF/NE/CPF OU CNPJ.
			#6.2.2.1.3.00.00 – CRÉDITO UTILIZADO - PO/FS/FR/CF/ND/ES/NF/DENF/NE/CPF OU CNPJ.
			#6.2.2.9.2.00.00 – EMISSÃO DE EMPENHO - PO/NF/DENF/NE/CPF OU CNPJ.
			#6.3.1.1.0.00.00 – RP NÃO PROCESSADO A LIQUIDAR - PO/FS/FR/CF/ND/ES/AI/NF/DENF/NE/CPF OU CNPJ.
			#6.3.1.2.0.00.00 – RP NÃO PROCESSADO EM LIQUIDAÇÃO - PO/FS/FR/CF/ND/ES/AI/NF/DENF/NE/CPF OU CNPJ

			#PO (Poder e Órgão): 5 dígitos
			detalhamento << "10131 " if ordem_de_compra.unidade_orcamentaria.tipo_de_unidade_administrativa.executivo? && !ordem_de_compra.unidade_orcamentaria.rpps?
			detalhamento << "10132 " if ordem_de_compra.unidade_orcamentaria.tipo_de_unidade_administrativa.executivo? && ordem_de_compra.unidade_orcamentaria.rpps?
			detalhamento << "20231 " if ordem_de_compra.unidade_orcamentaria.tipo_de_unidade_administrativa.legislativo?

			if conta_por_evento_contabil.conta.codigo[0..2] == "115" || ["213110101", "213110102"].include?(conta_por_evento_contabil.conta.codigo)
				#FP (Atributo do Superávit Financeiro): 1 dígito
				detalhamento << (conta_por_evento_contabil.conta.permanente? ? "P " : "F ").to_s
			end

			if conta_por_evento_contabil.conta.codigo == "213110102"
				#DC (DÍVIDA CONSOLIDADA): 1 dígito
				detalhamento << "1 "
			end

			if conta_por_evento_contabil.conta.codigo[0..4] == "62213" || ["631100000", "631200000"].include?(conta_por_evento_contabil.conta.codigo)
				#FS (Classificação Funcional (função e subfunção)): 5 dígitos = Função 2 dígitos + Subfunção 3 dígitos
				detalhamento << (ordem_de_compra.empenho.subacao.funcao.codigo.to_s + ordem_de_compra.empenho.subacao.subfuncao.codigo.to_s + " ").to_s

				#CF (Complemento da Fonte ou Destinação de Recursos): 4 dígitos
				detalhamento << Contabilidade::Empenho.complementacao_da_fonte_de_recursos[ordem_de_compra.empenho.complementacao_da_fonte_de_recurso].to_s + " " if ordem_de_compra.empenho.complementacao_da_fonte_de_recurso.present?

				#ND (Natureza da Despesa): 8 dígitos
				detalhamento << ordem_de_compra.sub_elemento_de_despesa.codigo_formatado + " "

				#ES (Despesa com MDE e ASPS): 1 dígito
				detalhamento << "2 " if ordem_de_compra.empenho.subacao.funcao.eh_da_saude?
				detalhamento << "1 " if ordem_de_compra.empenho.subacao.funcao.eh_da_educacao?
			end

			if conta_por_evento_contabil.conta.codigo[0..2] == "115" || conta_por_evento_contabil.conta.codigo[0..4] == "62213" || ["213110101", "213110102", "631100000", "631200000"].include?(conta_por_evento_contabil.conta.codigo)
				#FR (Fonte ou Destinação de Recursos): 8 dígitos
				detalhamento << ordem_de_compra.empenho.fonte_de_recursos.codigo_completo + " "
			end

			if ["631100000", "631200000"].include?(conta_por_evento_contabil.conta.codigo)
				#AI (Ano de inscrição de Restos a Pagar): 4 dígitos
				detalhamento << (ordem_de_compra.empenho.orcamento.exercicio + " ").to_s if ordem_de_compra.empenho.restos_a_pagar?(orcamento)
			end

			#NF (Número da Nota Fiscal): 8 dígitos
			detalhamento << self.numero_da_nota + " " if !numero_da_nota.blank?
			#DENF (Data da emissão da Nota Fiscal): 8 dígitos
			detalhamento << self.data_de_emissao.to_date.strftime("%Y%m%d") + " " if self.data_de_emissao.present?
			#NE (Nota de Empenho): 8 dígitos
			detalhamento << ordem_de_compra.empenho.numero_do_empenho + " "
			#CPF/CNPJ fornecedor do empenho
			detalhamento << ordem_de_compra.empenho.try(:pessoa).try(:cpf_ou_cnpj)
		end
		return detalhamento
	end

	def altera_status_da_ordem_de_compra_para
		recebimentos = self.ordem_de_compra.recebimento_de_materiais.where.not(id: self.id).order(data_do_recebimento: :desc)
		if recebimentos.present?
			if recebimentos.last.recebido?
				self.ordem_de_compra.confirmar_recebimento_almoxarifado!
			else
				self.ordem_de_compra.confirmar_recebimento_parcial_almoxarifado!
			end
		else
			self.ordem_de_compra.enviar_para_almoxarifado!
		end
	end

	def altera_status_da_devolucao_de_material
		self.devolucao_de_material.confirmar_recebimento!
	end

	def atribui_codigo_disponivel
		if self.data_do_recebimento.present? && self.codigo.blank?
			gerar_codigo(self.data_do_recebimento, :codigo, :data_do_recebimento, :orcamento_id, self.orcamento_id)
		end
	end

	def atribui_tipo_de_material
		if self.ordem_de_compra.empenho.elemento_de_despesa.material_de_consumo?
			self.tipo_de_material = :consumo
		elsif self.ordem_de_compra.empenho.elemento_de_despesa.material_de_consumo_com_distribuicao_gratuita?
			self.tipo_de_material = :consumo_distribuicao_gratuita
		elsif self.ordem_de_compra.empenho.elemento_de_despesa.material_permanente?
			self.tipo_de_material = :permanente
		end
	end

	def atribui_almoxarifado_e_unidade
		if ordem_de_compra.present?
			self.almoxarifado_id = self.ordem_de_compra.almoxarifado.id rescue nil
			self.unidade_orcamentaria_id = self.ordem_de_compra.empenho.unidade_orcamentaria.id rescue nil
		elsif devolucao_de_material.present?
			self.almoxarifado_id = self.devolucao_de_material.requisicao_de_material.almoxarifado_id
			self.unidade_orcamentaria_id = self.devolucao_de_material.requisicao_de_material.unidade_orcamentaria_id
		end
	end

	def valor_total_do_recebimento
		total = 0
		self.itens_do_recebimento_de_materiais.each do |item|
			total += (item.quantidade * item.valor_unitario) rescue 0.0
		end
		return total
	end

	def valida_data_de_emissao_da_nota_fiscal_maior_que_data_do_empenho
		if self.possui_ordem_de_compra?
			if self.data_de_emissao.present? && self.ordem_de_compra.empenho.data_do_empenho.present?
				errors.add(:data_de_emissao, "Data de emissão inferior a data do empenho") if self.data_de_emissao < self.ordem_de_compra.empenho.data_do_empenho
			end
		else
			if self.data_de_emissao.present? && self.data_do_empenho.present?
				errors.add(:data_de_emissao, "Data de emissão inferior a data do empenho") if self.data_de_emissao < self.data_do_empenho
			end
		end
	end

	def valida_se_data_da_nota_fiscal_eh_maior_que_data_do_recebimento
		errors.add(:data_de_emissao, "Data de emissão superior a data do recebimento") if self.data_de_emissao.to_date > self.data_do_recebimento.to_date
	end

	def existe_requisicao_ou_saida_para_esse_recebimento?
		Administrativo::RequisicaoDeMaterial.where(recebimento_de_material_id: self.id).present? rescue false
	end

	def numero_da_ordem_de_compra_e_fornecedor
		if possui_ordem_de_compra?
			"#{self.ordem_de_compra.numero} - #{ordem_de_compra.empenho.pessoa.nome}"
		else
			if self.fornecedor.present?
				"#{self.numero_da_ordem_de_compra} - #{self.fornecedor.try(:nome)}"
			elsif self.doador.present?
				"#{self.fornecedor.try(:cpf_ou_cnpj_e_nome)}"
			end
		end
	end

	def retorna_categoria_de_consumo
		::Base::Categoria.find_by_codigo(30) rescue false
	end

	def eh_alimenticio?
		if retorna_categoria_de_consumo.present?
			self.itens_do_recebimento_de_materiais.includes(item: :categoria)
				.where(
					base_categorias: {
						categoria_superior_id: retorna_categoria_de_consumo.id,
						codigo: ["07"]
					}
				).any?
			else
				return false
			end
	end

	def eh_farmaceutico?
		if retorna_categoria_de_consumo.present?
			self.itens_do_recebimento_de_materiais.includes(item: :categoria)
				.where(
					base_categorias: {
						categoria_superior_id: retorna_categoria_de_consumo.id,
						codigo: ["09", "10"]
					}
				).any?
		else
			return false
		end
	end

	def eh_limpeza?
		if retorna_categoria_de_consumo.present?
			self.itens_do_recebimento_de_materiais.includes(item: :categoria)
				.where(
					base_categorias: {
						categoria_superior_id: retorna_categoria_de_consumo.id,
						codigo: ["21", "35", "36"]
					}
				).any?
		else
			return false
		end
	end

	def preenche_sub_elemento_pela_ordem_de_compra
		self.sub_elemento_de_despesa_id = self.ordem_de_compra.empenho.sub_elemento_de_despesa_id
	end

	def cria_requisicao_do_remoto(eh_destino)
		unidade_orcamentaria = eh_destino == true ? self.unidade_orcamentaria_de_destino_id : self.unidade_orcamentaria_id
		almoxarifado = eh_destino == true ? self.almoxarifado_de_destino_id : self.almoxarifado_id
		return false unless almoxarifado.present? || unidade_orcamentaria.present?

		requisicao_de_material = Administrativo::RequisicaoDeMaterial.new(
			data_da_requisicao: self.data_do_recebimento ,
			unidade_orcamentaria_id: self.unidade_orcamentaria_id ,
			unidade_orcamentaria_destino_id: self.unidade_orcamentaria_de_destino_id,
			almoxarifado_id: self.almoxarifado_id ,
			almoxarifado_destino_id: self.almoxarifado_de_destino_id,
			tipo_de_material: self.tipo_de_material ,
			status: 7 ,
			orcamento_id: self.orcamento_id ,
			classificacao_tipo_de_material: self.classificacao_tipo_de_material ,
			classificacao: Administrativo::RequisicaoDeMaterial.classificacoes[:remoto],
			recebimento_de_material_id: self.id,
			avulsa: false
		)
		if requisicao_de_material.save!
			self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
				estoque = GestaoDeEstoque::Estoque.find_by(item_id: item_do_recebimento_de_material.item_id, unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id, almoxarifado_id: almoxarifado, unidade_orcamentaria_id: unidade_orcamentaria)
				item_da_requisicao_de_material = Administrativo::ItemDaRequisicaoDeMaterial.create!(
						item_id: item_do_recebimento_de_material.item_id,
						estoque_id: estoque.id,
						quantidade_requisitada: item_do_recebimento_de_material.retorna_quantidade_ou_quantidade_de_conversao,
						requisicao_de_material_id: requisicao_de_material.id,
						unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id,
						quantidade_atendida: item_do_recebimento_de_material.retorna_quantidade_ou_quantidade_de_conversao
					)
					item_da_requisicao_de_material.adiciona_ou_atualiza_saldo_no_estoque
			end
		else
			return false
		end
	end

	def descricao_itens
		self.itens_do_recebimento_de_materiais.map { |i| i.item.descricao}.join(", ") rescue ""
	end

	def cria_recebimento_de_destino
		recebimento_de_material = GestaoDeEstoque::RecebimentoDeMaterial.new(
			data_do_recebimento: self.data_do_recebimento ,
			unidade_orcamentaria_id: self.unidade_orcamentaria_de_destino_id ,
			almoxarifado_id: self.almoxarifado_id ,
			tipo_de_material: self.tipo_de_material ,
			status: 3 ,
			orcamento_id: self.orcamento_id ,
			classificacao_tipo_de_material: self.classificacao_tipo_de_material ,
			classificacao: 4 ,
			tipo_de_entrada: self.tipo_de_entrada ,
			avulso: false,
			sub_elemento_de_despesa_id: self.sub_elemento_de_despesa_id
		)
		if recebimento_de_material.save
			self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
				item_do_recebimento_de_material = GestaoDeEstoque::ItemDoRecebimentoDeMaterial.create!(
					item_id: item_do_recebimento_de_material.item_id ,
					quantidade: item_do_recebimento_de_material.retorna_quantidade_ou_quantidade_de_conversao ,
					recebimento_de_material_id: recebimento_de_material.id ,
					unidade_de_medida_de_conversao_id: item_do_recebimento_de_material.possui_conversao_de_unidade_de_medida? ? item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id : nil,
					valor_unitario: item_do_recebimento_de_material.valor_unitario ,
					total: item_do_recebimento_de_material.total
				)
				item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
			end
		else
			return false
		end
	end

	def cria_transferencia
		transferencia = GestaoDeEstoque::Transferencia.new(
			data_de_transferencia: self.data_do_recebimento,
			almoxarifado_id: self.almoxarifado_id,
			unidade_orcamentaria_id: self.unidade_orcamentaria_id,
			almoxarifado_de_destino_id: self.almoxarifado_de_destino_id,
			unidade_orcamentaria_de_destino_id: self.unidade_orcamentaria_de_destino_id,
			orcamento_id: self.orcamento_id ,
			status: 3,
			tipo_de_material: self.tipo_de_material,
			classificacao_tipo_de_material: self.classificacao_tipo_de_material,
			transferir_todos_os_itens: false
		)
		if transferencia.save!
			self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
				estoque = GestaoDeEstoque::Estoque.find_by(
					item_id: item_do_recebimento_de_material.item_id,
					unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id,
					almoxarifado_id: self.almoxarifado_id,
					unidade_orcamentaria_id: self.unidade_orcamentaria_id
				)
				item_da_transferencia = GestaoDeEstoque::ItemDaTransferencia.create!(
					transferencia_id: transferencia.id ,
					item_id: estoque.item.id,
					quantidade: item_do_recebimento_de_material.quantidade,
					valor_unitario: estoque.calcular_valor_medio_por_data_final(self.data_do_recebimento),
					total: item_do_recebimento_de_material.total,
					estoque_id: estoque.id,
					quantidade_disponivel: estoque.quantidade_total_saldo
				)
				item_da_transferencia.adiciona_ou_atualiza_saldo_no_estoque
			end
		else
			return false
		end
	end

	def cria_consumo
		consumo = GestaoDeEstoque::Consumo.new(
			data_de_consumo: self.data_do_recebimento,
			status: 3,
			almoxarifado_id: self.almoxarifado_de_destino_id,
			unidade_orcamentaria_id: self.unidade_orcamentaria_de_destino_id,
			responsavel_id: self.try(:ordem_de_compra).try(:empenho).try(:pessoa).id ,
			orcamento_id: self.orcamento_id
		)
		if consumo.save!
			self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
				estoque = GestaoDeEstoque::Estoque.find_by(
					item_id: item_do_recebimento_de_material.item_id,
					unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id,
					almoxarifado_id: self.almoxarifado_de_destino_id,
					unidade_orcamentaria_id: self.unidade_orcamentaria_de_destino_id
				)
				item_do_consumo = GestaoDeEstoque::ItemDoConsumo.create!(
					consumo_id: consumo.id ,
					estoque_id: estoque.id,
					item_id: estoque.item.id,
					unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id,
					quantidade_consumida: item_do_recebimento_de_material.quantidade,
					valor_unitario: estoque.calcular_valor_medio_por_data_final(self.data_do_recebimento),
					total: estoque.valor_total_saldo
				)
				item_do_consumo.adiciona_ou_atualiza_saldo_no_estoque
			end
		else
			return false
		end
	end

	def remove_movimentacao_do_estoque
		estoques_id = []
		GestaoDeEstoque::MovimentacaoDoEstoque.where(origem_id: self.id, origem_type: self.class.name).each do |movimentacao_do_estoque|
			estoques_id << movimentacao_do_estoque.estoque_id
			movimentacao_do_estoque.destroy
		end

		GestaoDeEstoque::Estoque.where(id: estoques_id).each do |estoque|
			if GestaoDeEstoque::MovimentacaoDoEstoque.where(estoque_id: estoque.id).blank?
				estoque.destroy
			else
				estoque.calcular_valor_medio_por_data_final(self.data_do_recebimento)
			end
		end
	end

	def requisicao_de_material_do_recebimento
		Administrativo::RequisicaoDeMaterial.find_by(recebimento_de_material_id: self.id)
	end

	def todos_os_itens_tem_informacoes_extras?
		if self.itens_do_recebimento_de_materiais.any? && self.informacoes_extras.any?
			self.informacoes_extras.sum(&:quantidade) == self.itens_do_recebimento_de_materiais.sum(&:quantidade)
		else
			return false
		end
	end

	def todos_os_itens_tem_saldo_no_estoque?
		if self.itens_do_recebimento_de_materiais.any?
			self.itens_do_recebimento_de_materiais.map{ |item| item.saldo_atual_do_recebimento_de_material >= item.quantidade }.any?
		else
			return false
		end
	end

	def materiais_sao_venciveis?
		(self.eh_farmaceutico? || self.eh_alimenticio? || self.eh_limpeza?) && self.tipo_de_material != "permanente"
	end

	def atribui_elemento_de_despesa
		self.sub_elemento_de_despesa_id = self.ordem_de_compra.empenho.sub_elemento_de_despesa_id
	end

	def classificacao_doacao_ou_ajuste_de_inventario?
		self.doacao? || self.ajuste_de_inventario?
	end

	def cria_recebimento_de_bem_no_patrimonio
		if ordem_de_compra.try(:empenho).try(:pessoa_id).present?
			fornecedor_id = ordem_de_compra.empenho.pessoa_id
		else
			fornecedor_id = self.fornecedor_id || self.doador_id
		end

		recebimento_de_bem = Patrimonio::RecebimentoDeBem.new(
			recebimento_de_material_id: self.id,
			unidade_orcamentaria_id: self.unidade_orcamentaria_id,
			orcamento_id: self.orcamento_id ,
			classificacao: self.classificacao.present? ? self.classificacao : 'compra' ,
			sub_elemento_de_despesa_id: self.sub_elemento_de_despesa_id,
			numero_da_nota: self.numero_da_nota,
			serie: self.serie,
			data_de_emissao: self.data_de_emissao,
			doador_id: self.doador_id,
			fornecedor_id: fornecedor_id
		)
		if recebimento_de_bem.save(validate: false)
			self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
				item_do_recebimento_de_material.total = item_do_recebimento_de_material.calcular_valor_total if item_do_recebimento_de_material.total.blank?
				item_do_recebimento_de_bem = Patrimonio::ItemDoRecebimentoDeBem.create!(
					item_id: item_do_recebimento_de_material.item_id ,
					recebimento_de_bem_id: recebimento_de_bem.id ,
					marca: item_do_recebimento_de_material.marca,
					quantidade: item_do_recebimento_de_material.retorna_quantidade_ou_quantidade_de_conversao ,
					unidade_de_medida_id: item_do_recebimento_de_material.retorna_unidade_de_medida_ou_conversao.id,
					valor_unitario: item_do_recebimento_de_material.valor_unitario ,
					valor_total: item_do_recebimento_de_material.total
				)
			end
		else
			return nil
		end
	end

	def patrimonial?
		recebimento_de_bem.present? && permanente?
	end

	def tornar_definitivo
		self.itens_do_recebimento_de_materiais.each do |item_do_recebimento_de_material|
			item_do_recebimento_de_material.adiciona_ou_atualiza_saldo_no_estoque
		end
	end

	def define_data_provisoria
		self.update_column(:data_provisoria, self.data_do_recebimento)
	end

	def nao_pode_criar_recebimento_com_mes_encerrado
		if !self.existe_encerramento?
			errors.add(:base, "Não é possível criar um recebimento, pois o almoxarifado já foi encerrado no mês de #{Date::MONTHNAMES[self.data_do_recebimento.month]}")
		end
	end

	def lancar_ocorrencia
		if self.status_changed? && self.status != "aberto"
			GestaoDeEstoque::OcorrenciaDoRecebimentoDeMaterial.create(
				recebimento_de_material_id: self.id,
				tipo_de_ocorrencia: self.status,
				observacao: "-"
			).save(validate: false)
		end
	end

end
