join( 'cadastro_livro_registro as livro_registro', 'livro_registro.id', 'livro.livro_registro_id' ) ->join( 'farmacia_livro_status as status', 'status.id', 'livro.status_id' ) ->leftJoin( 'cadastro_livro_registro_tipo as livro_registro_tipo', 'livro_registro_tipo.id', 'livro.livro_registro_tipo_id' ) ->where('livro.created_centro_custo_id', self::getCurrentCentroCusto()->id) ->whereIn('livro.livro_registro_id', $livroRegistroIds) ->where(fn ($q) => $q ->whereIn('livro.livro_registro_tipo_id', $livroRegistroTipoIds) ->when($allowLivroRegistroTipoNull, fn ($q) => $q->orWhereNull('livro.livro_registro_tipo_id')) ) ->when(request()->livro_registro_id, fn ($q, $id) => $q->where('livro.livro_registro_id', $id)) ->when(request()->livro_registro_tipo_id, fn ($q, $id) => $q->where('livro.livro_registro_tipo_id', $id)) ->when(request()->status_id, fn ($q, $id) => $q->where('livro.status_id', $id)) ->select(DB::raw(" livro.id, livro.numero, livro.created_centro_custo_id, livro.aberto_em, livro.livro_registro_id, livro.livro_registro_tipo_id, UPPER(livro_registro.nome) as livro, livro_registro_tipo.nome as tipo, status.id as status_id, status.nome as status, ( SELECT IF(MIN(COALESCE(( SELECT count(linha.id) FROM farmacia_livro_pagina_linha as linha WHERE linha.pagina_id = pagina.id ), 0)) = ( CASE livro.livro_registro_tipo_id WHEN " . LivroRegistroTipoEnum::A_BASE . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_A_BASE . " WHEN " . LivroRegistroTipoEnum::ESPECIFICO . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_ESPECIFICO . " ELSE " . self::QUANTIDADE_LINHAS_POR_PAGINA_PADRAO . " END ), 1, 0) FROM farmacia_livro_pagina as pagina WHERE pagina.livro_id = livro.id ) as totalmente_preenchido ")); return datatables() ->of($livros) ->filterColumn('livro.aberto_em', function ($query, $keyword) { $query->whereRaw("DATE_FORMAT(livro.aberto_em, '%d/%m/%Y') like ?", ["%{$keyword}%"]) ->orWhereRaw( "CONCAT( SUBSTR(livro.aberto_em,9,2), SUBSTR(livro.aberto_em,6,2), SUBSTR(livro.aberto_em,1,4) ) like ?", ["%{$keyword}%"] ); }) ->addColumn('has_available_update', function ($livro) { return self::getMovimentacoesAptasParaVincular($livro)->isNotEmpty(); }) ->skipTotalRecords() ->toJson(); } public static function list($livroRegistroIds, $livroRegistroTipoIds, $allowLivroRegistroTipoNull = false) { return [ 'form' => [ 'materiais_com_movimentacoes_sem_livro' => self::getMateriaisComMovimentacoesSemLivro( $livroRegistroIds, $livroRegistroTipoIds, $allowLivroRegistroTipoNull ), 'livros_registro' => LivroRegistro::whereIn('id', $livroRegistroIds) ->orderBy('nome') ->get(['id', 'nome']) ->each(fn ($l) => $l->nome = Str::upper($l->nome)), 'tipos_livro_registro' => LivroRegistroTipo::whereIn('id', $livroRegistroTipoIds) ->orderBy('nome') ->get(['id', 'nome']), 'status' => LivroStatus::orderBy('nome')->get(['id', 'nome']), ], 'model' => [ 'livro_registro_id' => null, 'livro_registro_tipo_id' => null, 'status_id' => null, ], ]; } public static function create($livroRegistroIds, $livroRegistroTipoIds) { return [ 'form' => self::getFormData($livroRegistroIds, $livroRegistroTipoIds), 'model' => [ 'numero' => null, 'status_id' => null, 'aberto_em' => null, 'livro_registro_id' => null, 'livro_registro_tipo_id' => null, 'quantidade_paginas' => null, 'registro' => null, 'usuario_farmaceutico' => null, 'inscricao_estadual' => null, 'autoridade_sanitaria' => null, ], ]; } public static function edit($livro, $livroRegistroIds, $livroRegistroTipoIds) { return [ 'form' => self::getFormData($livroRegistroIds, $livroRegistroTipoIds), 'model' => [ 'numero' => $livro->numero, 'status_id' => $livro->status_id, 'aberto_em' => $livro->aberto_em->format('d/m/Y'), 'livro_registro_id' => $livro->livro_registro_id, 'livro_registro_tipo_id' => $livro->livro_registro_tipo_id, 'quantidade_paginas' => $livro->quantidade_paginas, 'registro' => $livro->registro, 'usuario_farmaceutico' => [ 'id' => $livro->usuarioFarmaceutico->id, 'cidadao_nome' => $livro->usuarioFarmaceutico->cidadao->nome, ], 'inscricao_estadual' => $livro->inscricao_estadual, 'autoridade_sanitaria' => $livro->autoridade_sanitaria, 'paginas' => self::getPaginasEmUso($livro->id), ], ]; } private static function getFormData($livroRegistroIds, $livroRegistroTipoIds) { $municipio = Cliente::where('link', app('config')->get('database.default'))->first()->municipio->nome; $infraestruturaLogada = self::getCurrentCentroCusto()->infraestrutura; return [ 'livros_registro' => LivroRegistro::whereIn('id', $livroRegistroIds) ->orderBy('nome') ->get(['id', 'nome']) ->each(fn ($l) => $l->nome = Str::upper($l->nome)), 'tipos_livro_registro' => LivroRegistroTipo::whereIn('id', $livroRegistroTipoIds) ->orderBy('nome') ->get(['id', 'nome']), 'firma' => "PREFEITURA MUNICIPAL DE {$municipio}", 'farmacia' => $infraestruturaLogada->nome, 'endereco' => $infraestruturaLogada->endereco->completo, ]; } public static function store($data) { $data['numero'] = self::getNextNumero( $data['livro_registro_id'], $data['livro_registro_tipo_id'] ); $data['status_id'] = LivroStatusEnum::ABERTO; $livro = Livro::create($data); for ($numeroPagina = 1; $numeroPagina <= $data['quantidade_paginas']; $numeroPagina++) { $livro->paginas()->create(['numero' => $numeroPagina]); } self::updateMovimentacoes($livro); return $livro->fresh(); } private static function getNextNumero($livroRegistroId, $livroRegistroTipoId) { return Livro::where('livro_registro_id', $livroRegistroId) ->where('livro_registro_tipo_id', $livroRegistroTipoId) ->max('numero') + 1; } public static function updateMovimentacoes($livro) { self::getMovimentacoesAptasParaVincular($livro) ->each(function ($movimentacao) use ($livro) { $pagina = self::getPaginaDisponivel($livro, $movimentacao->material_id); if (!is_null($pagina)) { if (is_null($pagina->material_id)) { LivroPagina::where('id', $pagina->id) ->update(['material_id' => $movimentacao->material_id]); } LivroPaginaLinha::create([ 'pagina_id' => $pagina->id, 'entrada_item_id' => $movimentacao->movimento == 'entrada' ? $movimentacao->id : null, 'saida_item_id' => $movimentacao->movimento == 'saida' ? $movimentacao->id : null, ]); } }); } private static function getMovimentacoesAptasParaVincular($livro) { return self::getMovimentacoes((object) [ 'centro_custo_id' => $livro->created_centro_custo_id, 'data' => $livro->aberto_em, 'livro_registro_id' => $livro->livro_registro_id, 'livro_registro_tipo_id' => $livro->livro_registro_tipo_id, ]) ->reject(fn ($m) => self::hasEspacoDisponivelEmLivroAnterior($livro, $m->material_id)) ->reject(fn ($m) => is_null(self::getPaginaDisponivel($livro, $m->material_id))); } private static function getMovimentacoes($params) { $isTalidomida = $params->livro_registro_id == LivroRegistroEnum::TALIDOMIDA; return DB::table('almoxarifado_entrada_item as entrada_item') ->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id') ->join('cadastro_material as material', 'material.id', 'entrada_item.material_id') ->where('entrada.finalizada', true) ->where('entrada.tipo_id', '<>', EntradaTipoEnum::ESTORNO) ->where('entrada.centro_custo_id', $params->centro_custo_id) ->when(isset($params->data), fn ($q) => $q->whereDate('entrada.created_at', '>=', $params->data)) ->where('material.livro_registro_id', $params->livro_registro_id) ->when(!$isTalidomida, function ($query) use ($params) { $query->where('material.livro_registro_tipo_id', $params->livro_registro_tipo_id); }) ->whereNotExists(function ($query) use ($isTalidomida, $params) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina_linha as linha') ->when($isTalidomida, function ($query) use ($params) { $query->join('farmacia_livro_pagina as pagina', 'pagina.id', 'linha.pagina_id') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->where('livro.livro_registro_tipo_id', $params->livro_registro_tipo_id); }) ->whereColumn('linha.entrada_item_id', 'entrada_item.id'); }) ->select( DB::raw("'entrada' as movimento"), 'entrada_item.id', 'entrada_item.material_id', DB::raw("entrada.created_at as data_movimentacao") ) ->union(DB::table('almoxarifado_saida_item as saida_item') ->join('almoxarifado_saida as saida', 'saida.id', 'saida_item.saida_id') ->join('cadastro_material as material', 'material.id', 'saida_item.material_id') ->leftJoin('almoxarifado_saida_baixa as baixa', 'baixa.saida_id', 'saida.id') ->leftJoin('almoxarifado_motivo_baixa as motivo', 'motivo.id', 'baixa.motivo_id') ->where('saida.finalizada', true) ->where('saida.tipo_id', '<>', SaidaTipoEnum::ESTORNO) ->where('saida.centro_custo_id', $params->centro_custo_id) ->when(isset($params->data), fn ($q) => $q->whereDate('saida.created_at', '>=', $params->data)) ->where('material.livro_registro_id', $params->livro_registro_id) ->when(!$isTalidomida, function ($query) use ($params) { $query->where('material.livro_registro_tipo_id', $params->livro_registro_tipo_id); }) ->whereNotExists(function ($query) use ($isTalidomida, $params) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina_linha as linha') ->when($isTalidomida, function ($query) use ($params) { $query->join('farmacia_livro_pagina as pagina', 'pagina.id', 'linha.pagina_id') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->where('livro.livro_registro_tipo_id', $params->livro_registro_tipo_id); }) ->whereColumn('linha.saida_item_id', 'saida_item.id'); }) ->select( DB::raw("'saida' as movimento"), 'saida_item.id', 'saida_item.material_id', DB::raw("saida.created_at as data_movimentacao") ) ) ->orderBy('data_movimentacao') ->get(); } private static function hasEspacoDisponivelEmLivroAnterior($livro, $materialId) { return DB::table('farmacia_livro_pagina as pagina') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->where('livro.id', '<', $livro->id) ->where('livro.created_centro_custo_id', $livro->created_centro_custo_id) ->where('livro.status_id', LivroStatusEnum::ABERTO) ->where('livro.livro_registro_id', $livro->livro_registro_id) ->where('livro.livro_registro_tipo_id', $livro->livro_registro_tipo_id) ->whereDate('livro.aberto_em', '<=', $livro->aberto_em) ->where(function ($query) use ($materialId) { $query->where(function ($query) use ($materialId) { $query->where('pagina.material_id', $materialId) ->whereRaw("( SELECT count(linha.id) FROM farmacia_livro_pagina_linha as linha WHERE linha.pagina_id = pagina.id ) < ( CASE livro.livro_registro_tipo_id WHEN " . LivroRegistroTipoEnum::A_BASE . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_A_BASE . " WHEN " . LivroRegistroTipoEnum::ESPECIFICO . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_ESPECIFICO . " ELSE " . self::QUANTIDADE_LINHAS_POR_PAGINA_PADRAO . " END )"); })->orWhereNull('pagina.material_id'); }) ->exists(); } private static function getPaginaDisponivel($livro, $materialId) { $quantidadeLinhasPorPagina = self::QUANTIDADE_LINHAS_POR_PAGINA_PADRAO; if ($livro->livro_registro_tipo_id == LivroRegistroTipoEnum::A_BASE) { $quantidadeLinhasPorPagina = self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_A_BASE; } else if ($livro->livro_registro_tipo_id == LivroRegistroTipoEnum::ESPECIFICO) { $quantidadeLinhasPorPagina = self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_ESPECIFICO; } return DB::table('farmacia_livro_pagina as pagina') ->where('pagina.livro_id', $livro->id) ->where(function ($query) use ($materialId, $quantidadeLinhasPorPagina) { $query->where(function ($query) use ($materialId, $quantidadeLinhasPorPagina) { $query->where('pagina.material_id', $materialId) ->whereRaw("( SELECT count(linha.id) FROM farmacia_livro_pagina_linha as linha WHERE linha.pagina_id = pagina.id ) < {$quantidadeLinhasPorPagina}"); })->orWhereNull('pagina.material_id'); }) ->orderBy('pagina.numero') ->limit(1) ->select( 'pagina.id', 'pagina.material_id' ) ->first(); } public static function fecharLivro($livro) { if ($livro->status_id === LivroStatusEnum::ABERTO) { $livro->update([ 'status_id' => LivroStatusEnum::FECHADO, 'fechado_em' => Carbon::now(), 'lotacao_fechamento_id' => self::getCurrentLotacao()->id, ]); } } public static function getDataAbertura($livroRegistroId, $livroRegistroTipoId = null) { $dataMinimaAbertura = null; $dataMaximaAbertura = Carbon::now()->setTime(0, 0, 0); $abertoEm = Livro::where('livro_registro_id', $livroRegistroId) ->where('livro_registro_tipo_id', $livroRegistroTipoId) ->where('created_centro_custo_id', self::getCurrentCentroCusto()->id) ->max('aberto_em'); if (!is_null($abertoEm)) { $dataMinimaAbertura = (new Carbon($abertoEm))->setTime(0, 0, 0); } $dataPrimeiraMovimentacao = self::getMovimentacoes((object) [ 'centro_custo_id' => self::getCurrentCentroCusto()->id, 'data' => $dataMinimaAbertura ? $dataMinimaAbertura->format('Y-m-d') : null, 'livro_registro_id' => $livroRegistroId, 'livro_registro_tipo_id' => $livroRegistroTipoId, ])->first()->data_movimentacao ?? null; if (!is_null($dataPrimeiraMovimentacao)) { $dataPrimeiraMovimentacao = (new Carbon($dataPrimeiraMovimentacao))->setTime(0, 0, 0); if ($dataPrimeiraMovimentacao < $dataMaximaAbertura) { $dataMaximaAbertura = $dataPrimeiraMovimentacao; } } return [ 'data_minima' => $dataMinimaAbertura ? $dataMinimaAbertura->format('d/m/Y') : null, 'data_maxima' => $dataMaximaAbertura ? $dataMaximaAbertura->format('d/m/Y') : null, ]; } private static function getMateriaisComMovimentacoesSemLivro( $livroRegistroIds = [], $livroRegistroTipoIds = [], $allowLivroRegistroTipoNull ) { $centroCustoLogadoId = self::getCurrentCentroCusto()->id; $materiais = collect(); $setMateriais = function ($livroRegistroId, $livroRegistroTipoId) use ($centroCustoLogadoId, $materiais) { $isTalidomida = $livroRegistroId === LivroRegistroEnum::TALIDOMIDA; DB::table('cadastro_material as material') ->join( 'cadastro_apresentacao as apresentacao', 'apresentacao.id', 'material.apresentacao_id' ) ->join( 'cadastro_livro_registro as livro_registro', 'livro_registro.id', 'material.livro_registro_id' ) ->leftJoin( 'cadastro_unidade_medida as apresentacao_unidade_medida', 'apresentacao_unidade_medida.id', 'material.apresentacao_unidade_medida_id' ) ->where('material.livro_registro_id', $livroRegistroId) ->when(!$isTalidomida, fn ($q) => $q->where('material.livro_registro_tipo_id', $livroRegistroTipoId)) ->where(function ($query) use ($centroCustoLogadoId, $isTalidomida, $livroRegistroTipoId) { $query->whereExists(function ($query) use ($centroCustoLogadoId, $isTalidomida, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('almoxarifado_entrada_item as entrada_item') ->join('almoxarifado_entrada as entrada', 'entrada.id', 'entrada_item.entrada_id') ->whereColumn('entrada_item.material_id', 'material.id') ->where('entrada.finalizada', true) ->where('entrada.tipo_id', '<>', EntradaTipoEnum::ESTORNO) ->where('entrada.centro_custo_id', $centroCustoLogadoId) ->whereNotExists(function ($query) use ($isTalidomida, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina_linha as linha') ->when($isTalidomida, function ($query) use ($livroRegistroTipoId) { $query->join('farmacia_livro_pagina as pagina', 'pagina.id', 'linha.pagina_id') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->where('livro.livro_registro_tipo_id', $livroRegistroTipoId); }) ->whereColumn('linha.entrada_item_id', 'entrada_item.id'); }) ->whereNotExists(function ($query) use ($centroCustoLogadoId, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina as pagina') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->whereColumn('livro.livro_registro_id', 'material.livro_registro_id') ->whereColumn('livro.aberto_em', '<=', 'entrada.created_at') ->where('livro.livro_registro_tipo_id', $livroRegistroTipoId) ->where('livro.created_centro_custo_id', $centroCustoLogadoId) ->where('livro.status_id', LivroStatusEnum::ABERTO) ->where(function ($query) { $query->where(function ($query) { $query->whereColumn('pagina.material_id', 'material.id') ->whereRaw("( SELECT count(linha.id) FROM farmacia_livro_pagina_linha as linha WHERE linha.pagina_id = pagina.id ) < ( CASE livro.livro_registro_tipo_id WHEN " . LivroRegistroTipoEnum::A_BASE . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_A_BASE . " WHEN " . LivroRegistroTipoEnum::ESPECIFICO . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_ESPECIFICO . " ELSE " . self::QUANTIDADE_LINHAS_POR_PAGINA_PADRAO . " END )"); })->orWhereNull('pagina.material_id'); }); }); })->orWhereExists(function ($query) use ($centroCustoLogadoId, $isTalidomida, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('almoxarifado_saida_item as saida_item') ->join('almoxarifado_saida as saida', 'saida.id', 'saida_item.saida_id') ->whereColumn('saida_item.material_id', 'material.id') ->where('saida.finalizada', true) ->where('saida.tipo_id', '<>', SaidaTipoEnum::ESTORNO) ->where('saida.centro_custo_id', $centroCustoLogadoId) ->whereNotExists(function ($query) use ($isTalidomida, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina_linha as linha') ->when($isTalidomida, function ($query) use ($livroRegistroTipoId) { $query->join('farmacia_livro_pagina as pagina', 'pagina.id', 'linha.pagina_id') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->where('livro.livro_registro_tipo_id', $livroRegistroTipoId); }) ->whereColumn('linha.saida_item_id', 'saida_item.id'); }) ->whereNotExists(function ($query) use ($centroCustoLogadoId, $livroRegistroTipoId) { $query->select(DB::raw(1)) ->from('farmacia_livro_pagina as pagina') ->join('farmacia_livro as livro', 'livro.id', 'pagina.livro_id') ->whereColumn('livro.livro_registro_id', 'material.livro_registro_id') ->whereColumn('livro.aberto_em', '<=', 'saida.created_at') ->where('livro.livro_registro_tipo_id', $livroRegistroTipoId) ->where('livro.created_centro_custo_id', $centroCustoLogadoId) ->where('livro.status_id', LivroStatusEnum::ABERTO) ->where(function ($query) { $query->where(function ($query) { $query->whereColumn('pagina.material_id', 'material.id') ->whereRaw("( SELECT count(linha.id) FROM farmacia_livro_pagina_linha as linha WHERE linha.pagina_id = pagina.id ) < ( CASE livro.livro_registro_tipo_id WHEN " . LivroRegistroTipoEnum::A_BASE . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_A_BASE . " WHEN " . LivroRegistroTipoEnum::ESPECIFICO . " THEN " . self::QUANTIDADE_LINHAS_POR_PAGINA_TALIDOMIDA_ESPECIFICO . " ELSE " . self::QUANTIDADE_LINHAS_POR_PAGINA_PADRAO . " END )"); })->orWhereNull('pagina.material_id'); }); }); }); }) ->select(DB::raw(" " . MaterialService::getDescricaoCompletaRaw( 'material', 'apresentacao', 'apresentacao_unidade_medida' ) . " AS descricao, UPPER(livro_registro.nome) as livro, " . (is_null($livroRegistroTipoId) ? 'NULL' : "( SELECT tipo.nome FROM cadastro_livro_registro_tipo as tipo WHERE tipo.id = {$livroRegistroTipoId} )" ) . " as tipo ")) ->get() ->each(function ($material) use ($materiais) { $agrupado = $materiais ->where('livro', $material->livro) ->where('tipo', $material->tipo) ->first(); if (is_null($agrupado)) { $agrupado = (object) [ 'livro' => $material->livro, 'tipo' => $material->tipo, 'materiais' => collect(), ]; $materiais->push($agrupado); } $agrupado->materiais->push((object) [ 'descricao' => $material->descricao ]); }); }; if ($allowLivroRegistroTipoNull) { $livroRegistroTipoIds[] = null; } collect($livroRegistroIds)->each(fn ($livroRegistroId) => collect($livroRegistroTipoIds) ->each(fn ($livroRegistroTipoId) => $setMateriais($livroRegistroId, $livroRegistroTipoId))); return $materiais; } public static function getLivroCompletoImpressao($livroId) { $paginas = self::getPaginasEmUso($livroId); $paginas->each(function ($paginaEmUso) { $pagina = LivroPagina::findOrFail($paginaEmUso->id); $paginaData = self::getLinhas($pagina); $paginaEmUso->estorno_message = $paginaData['estorno_message']; $paginaEmUso->transferido_de = $paginaData['transferido_de']; $paginaEmUso->transferido_para = $paginaData['transferido_para']; $paginaEmUso->linhas = $paginaData['linhas']->map(fn ($linha) => (object) [ 'data_movimentacao' => (new Carbon($linha->data_movimentacao))->format('d/m/Y'), 'entrada' => $linha->entrada, 'saida' => $linha->saida, 'perda' => $linha->perda, 'estoque' => $linha->estoque, 'numero_registro' => $linha->numero_registro ?? null, 'numero_documento' => $linha->numero_documento ?? null, 'numero_notificacao' => $linha->numero_notificacao ?? null, 'paciente_data_nascimento' => isset($linha->paciente_data_nascimento) ? (new Carbon($linha->paciente_data_nascimento))->format('d/m/Y') : null, 'paciente_sexo' => $linha->paciente_sexo ?? null, 'medico_nome' => $linha->medico_nome ?? null, 'medico_crm' => $linha->medico_crm ?? null, 'cid_nome' => $linha->cid_nome ?? null, 'cid_codigo' => $linha->cid_codigo ?? null, 'historico' => $linha->historico ?? null, 'observacoes' => $linha->observacoes ?? null, ]); }); return $paginas; } private static function getPaginasEmUso($livroId) { return DB::table('farmacia_livro_pagina as pagina') ->join('cadastro_material as material', 'material.id', 'pagina.material_id') ->join('cadastro_apresentacao as apresentacao', 'apresentacao.id', 'material.apresentacao_id') ->leftJoin( 'cadastro_unidade_medida as apresentacao_unidade_medida', 'apresentacao_unidade_medida.id', 'material.apresentacao_unidade_medida_id' ) ->where('pagina.livro_id', $livroId) ->select(DB::raw(" pagina.id, pagina.numero, " . MaterialService::getDescricaoCompletaRaw( 'material', 'apresentacao', 'apresentacao_unidade_medida' ) . " as material ")) ->orderBy('pagina.numero') ->get(); } public static function getLinhas($pagina) { $linhas = self::getQueryLinhas($pagina)->get(); $linhas->each(function ($linha) { $linha->entrada = null; $linha->saida = null; $linha->perda = null; $linha->{$linha->movimento} = $linha->quantidade; unset($linha->movimento, $linha->quantidade); }); $hasEstorno = DB::table('farmacia_livro_pagina_linha as linha') ->leftJoin('almoxarifado_entrada_item as entrada_item', 'linha.entrada_item_id', 'entrada_item.id') ->leftJoin('almoxarifado_saida_item as saida_item', 'linha.saida_item_id', 'saida_item.id') ->where('linha.pagina_id', $pagina->id) ->where(function ($query) { $query->whereNotNull('entrada_item.estornado_em') ->orWhereNotNull('saida_item.estornado_em'); }) ->select('linha.id') ->limit(1) ->get() ->isNotEmpty(); $transferenciasData = self::getTransferenciasData($pagina); return [ 'estorno_message' => $hasEstorno ? "A página contém menos registros, pois uma ou mais movimentações foram estornadas." : null, 'transferido_de' => $transferenciasData->de, 'transferido_para' => $transferenciasData->para, 'linhas' => $linhas, ]; } private static function getQueryLinhas($pagina) { $isTalidomida = $pagina->livro->livro_registro_id === LivroRegistroEnum::TALIDOMIDA; $isTalidomidaABase = $isTalidomida && $pagina->livro->livro_registro_tipo_id === LivroRegistroTipoEnum::A_BASE; $isTalidomidaEspecifico = $isTalidomida && $pagina->livro->livro_registro_tipo_id === LivroRegistroTipoEnum::ESPECIFICO; $historicoEntrada = "( CASE entrada.tipo_id WHEN " . EntradaTipoEnum::REQUISICAO . " THEN ( SELECT CONCAT( 'ENTRADA - ', u.nome_fantasia, ' (Local de atendimento: ', COALESCE(i.nome, u.nome_fantasia), ' - ', 'Setor: ', s.nome, ')' ) FROM almoxarifado_requisicao_resposta_item_entrada_item riei JOIN almoxarifado_requisicao_resposta_item ri ON ri.id = riei.requisicao_resposta_item_id JOIN cadastro_centro_custo as cc ON cc.id = ri.created_centro_custo_id JOIN cadastro_setor s ON s.id = cc.setor_id JOIN cadastro_infraestrutura as i ON i.id = cc.infraestrutura_id JOIN cadastro_unidade as u ON u.id = i.unidade_id WHERE riei.entrada_item_id = entrada_item.id ) WHEN " . EntradaTipoEnum::TRANSFERENCIA . " THEN ( SELECT CONCAT( 'ENTRADA - ', u.nome_fantasia, ' (Local de atendimento: ', COALESCE(i.nome, u.nome_fantasia), ' - ', 'Setor: ', s.nome, ')' ) FROM cadastro_centro_custo as cc JOIN cadastro_setor s ON s.id = cc.setor_id JOIN cadastro_infraestrutura as i ON i.id = cc.infraestrutura_id JOIN cadastro_unidade as u ON u.id = i.unidade_id WHERE cc.id = entrada.created_centro_custo_id ) WHEN " . EntradaTipoEnum::INVENTARIO . " THEN 'ENTRADA - AJUSTE DE ESTOQUE' ELSE CONCAT( 'ENTRADA', IF(fabricante.nome IS NULL, '', CONCAT(' - ', fabricante.nome)), IF(documento.numero IS NULL, '', CONCAT(' - ', documento_tipo.nome, ': ', documento.numero)), IF(entrada_item.lote IS NULL, '', CONCAT(' - Lote: ', entrada_item.lote)), IF(entrada_item.validade_lote IS NULL, '', CONCAT(' - Validade: ', DATE_FORMAT(entrada_item.validade_lote, '%d/%m/%Y'))) ) END )"; $historicoSaida = "( CASE saida.tipo_id WHEN " . SaidaTipoEnum::BAIXA . " THEN IF(motivo_baixa.tipo_id IN ( " . MotivoBaixaTipoEnum::QUEBRADO . ", " . MotivoBaixaTipoEnum::VENCIDO . " ), 'BAIXA POR PERDA', 'BAIXA') WHEN " . SaidaTipoEnum::DISPENSACAO_FARMACIA . " THEN ( SELECT CONCAT(c.nome, ' - ', LPAD(COALESCE(p.prontuario, 0), 6, '0')) FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_paciente p ON p.id = r.paciente_id JOIN cadastro_cidadao c ON c.id = p.cidadao_id WHERE rie.saida_item_id = saida_item.id ) WHEN " . SaidaTipoEnum::INVENTARIO . " THEN 'SAÍDA - AJUSTE DE ESTOQUE' ELSE 'SAÍDA' END )"; return DB::table('farmacia_livro_pagina_linha as linha') ->join('almoxarifado_entrada_item as entrada_item', 'linha.entrada_item_id', 'entrada_item.id') ->join('almoxarifado_entrada as entrada', 'entrada_item.entrada_id', 'entrada.id') ->leftJoin('almoxarifado_entrada_documento as documento', 'entrada.id', 'documento.entrada_id') ->leftJoin('almoxarifado_documento_tipo as documento_tipo', 'documento.tipo_id', 'documento_tipo.id') ->leftJoin('cadastro_fabricante as fabricante', 'entrada_item.fabricante_id', 'fabricante.id') ->where('linha.pagina_id', $pagina->id) ->whereNull('entrada_item.estornado_em') ->select(DB::raw(" 'entrada' as movimento, entrada.created_at as data_movimentacao, " . ($isTalidomidaABase ? '' : "{$historicoEntrada} as historico,") . " entrada_item.quantidade, ( SELECT SUM( almoxarifado_entrada_item.quantidade - COALESCE(( SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida) FROM almoxarifado_saida_item_entrada_item JOIN almoxarifado_saida_item ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id JOIN almoxarifado_saida ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id AND almoxarifado_saida.finalizada = 1 AND almoxarifado_saida.centro_custo_id = {$pagina->livro->created_centro_custo_id} AND almoxarifado_saida_item.estornado_em IS NULL AND ( almoxarifado_saida.created_at <= entrada.created_at OR almoxarifado_saida_item.id = COALESCE(almoxarifado_entrada_item.saida_item_estornado_id, 0) ) ), 0) ) FROM almoxarifado_entrada_item JOIN almoxarifado_entrada ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id WHERE almoxarifado_entrada.finalizada = 1 AND almoxarifado_entrada.centro_custo_id = {$pagina->livro->created_centro_custo_id} AND almoxarifado_entrada_item.material_id = {$pagina->material_id} AND almoxarifado_entrada.created_at <= entrada.created_at ) as estoque " . ( $isTalidomidaEspecifico ? ", NULL as numero_registro, documento.numero as numero_documento, NULL as observacoes" : "" ) . " " . ( $isTalidomidaABase ? ", documento.numero as numero_documento, NULL as numero_notificacao, NULL as paciente_data_nascimento, NULL as paciente_sexo, NULL as medico_nome, NULL as medico_crm, NULL as cid_nome, NULL as cid_codigo, NULL as numero_registro" : "" ) . " ")) ->unionAll(DB::table('farmacia_livro_pagina_linha as linha') ->join('almoxarifado_saida_item as saida_item', 'linha.saida_item_id', 'saida_item.id') ->join('almoxarifado_saida as saida', 'saida_item.saida_id', 'saida.id') ->leftJoin('almoxarifado_saida_baixa as baixa', 'baixa.saida_id', 'saida.id') ->leftJoin('almoxarifado_motivo_baixa as motivo_baixa', 'motivo_baixa.id', 'baixa.motivo_id') ->where('linha.pagina_id', $pagina->id) ->whereNull('saida_item.estornado_em') ->select(DB::raw(" IF(saida.tipo_id = " . SaidaTipoEnum::BAIXA . " AND motivo_baixa.tipo_id IN ( " . MotivoBaixaTipoEnum::QUEBRADO . ", " . MotivoBaixaTipoEnum::VENCIDO . " ), 'perda', 'saida') as movimento, saida.created_at as data_movimentacao, " . ($isTalidomidaABase ? '' : "{$historicoSaida} as historico,") . " ( SELECT SUM(siei.quantidade_saida) FROM almoxarifado_saida_item_entrada_item as siei WHERE siei.saida_item_id = saida_item.id ) as quantidade, ( SELECT SUM( almoxarifado_entrada_item.quantidade - COALESCE(( SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida) FROM almoxarifado_saida_item_entrada_item JOIN almoxarifado_saida_item ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id JOIN almoxarifado_saida ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id AND almoxarifado_saida.finalizada = 1 AND almoxarifado_saida.centro_custo_id = {$pagina->livro->created_centro_custo_id} AND ( almoxarifado_saida.created_at <= saida.created_at OR almoxarifado_saida_item.id = COALESCE(almoxarifado_entrada_item.saida_item_estornado_id, 0) ) ), 0) ) FROM almoxarifado_entrada_item JOIN almoxarifado_entrada ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id WHERE almoxarifado_entrada.finalizada = 1 AND almoxarifado_entrada.centro_custo_id = {$pagina->livro->created_centro_custo_id} AND almoxarifado_entrada_item.material_id = {$pagina->material_id} AND almoxarifado_entrada.created_at <= saida.created_at ) as estoque " . ( $isTalidomidaEspecifico ? ", ( SELECT u.registro_numero FROM farmacia_receita_item_entrega rie JOIN cadastro_lotacao l ON l.id = rie.updated_lotacao_id JOIN cadastro_usuario u ON u.id = l.usuario_id WHERE rie.saida_item_id = saida_item.id AND u.registro_tipo_id = " . TipoRegistroUsuario::FARMACIA . " ) as numero_registro, NULL as numero_documento, ( SELECT c.nome FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_usuario u ON u.id = r.usuario_id JOIN cadastro_cidadao c ON c.id = u.cidadao_id WHERE rie.saida_item_id = saida_item.id ) as observacoes" : "" ) . " " . ( $isTalidomidaABase ? ", NULL as numero_documento, ( SELECT r.numero_notificacao FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id WHERE rie.saida_item_id = saida_item.id ) as numero_notificacao, ( SELECT c.data_nascimento FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_paciente p ON p.id = r.paciente_id JOIN cadastro_cidadao c ON c.id = p.cidadao_id WHERE rie.saida_item_id = saida_item.id ) as paciente_data_nascimento, ( SELECT s.descricao FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_paciente p ON p.id = r.paciente_id JOIN cadastro_cidadao c ON c.id = p.cidadao_id JOIN cadastro_sexo s ON s.id = c.sexo_id WHERE rie.saida_item_id = saida_item.id ) as paciente_sexo, ( SELECT c.nome FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_usuario u ON u.id = r.usuario_id JOIN cadastro_cidadao c ON c.id = u.cidadao_id WHERE rie.saida_item_id = saida_item.id ) as medico_nome, ( SELECT u.registro_numero FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN cadastro_usuario u ON u.id = r.usuario_id WHERE rie.saida_item_id = saida_item.id AND u.registro_tipo_id = " . TipoRegistroUsuario::MEDICINA . " ) as medico_crm, ( SELECT c.nome FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN sigtap.cid c ON c.id = r.cid_id WHERE rie.saida_item_id = saida_item.id ) as cid_nome, ( SELECT c.codigo FROM farmacia_receita_item_entrega rie JOIN farmacia_receita_item ri ON ri.id = rie.receita_item_id JOIN farmacia_receita r ON r.id = ri.receita_id JOIN sigtap.cid c ON c.id = r.cid_id WHERE rie.saida_item_id = saida_item.id ) as cid_codigo, ( SELECT u.registro_numero FROM farmacia_receita_item_entrega rie JOIN cadastro_lotacao l ON l.id = rie.updated_lotacao_id JOIN cadastro_usuario u ON u.id = l.usuario_id WHERE rie.saida_item_id = saida_item.id AND u.registro_tipo_id = " . TipoRegistroUsuario::FARMACIA . " ) as numero_registro" : "" ) . " ")) ) ->orderBy('data_movimentacao'); } private static function getTransferenciasData($pagina) { $de = null; $para = null; if (self::isPrimeraPaginaMaterial($pagina)) { $de = self::getMessageUltimaPaginaLivroAnterior($pagina); } if (self::isUltimaPaginaMaterial($pagina)) { $para = self::getMessagePrimeiraPaginaLivroPosterior($pagina); } return (object) compact('de', 'para'); } private static function isPrimeraPaginaMaterial($pagina) { $primeiraPaginaLivro = $pagina->livro()->first(['id'])->paginas() ->where('material_id', $pagina->material_id) ->orderBy('numero') ->first(['numero']); return $pagina->numero === $primeiraPaginaLivro->numero; } private static function getMessageUltimaPaginaLivroAnterior($pagina) { $livro = $pagina->livro()->first(['livro_registro_id', 'livro_registro_tipo_id']); $isTalidomida = $livro->livro_registro_id === LivroRegistroEnum::TALIDOMIDA; $ultimaPaginaLivroAnterior = LivroPagina::where('created_centro_custo_id', $pagina->created_centro_custo_id) ->where('livro_id', '<', $pagina->livro_id) ->where('material_id', $pagina->material_id) ->when($isTalidomida, function ($query) use ($livro) { $query->whereHas('livro', function ($query) use ($livro) { $query->where('livro_registro_tipo_id', $livro->livro_registro_tipo_id); }); }) ->orderByDesc('livro_id') ->orderByDesc('numero') ->first(['id', 'livro_id', 'material_id', 'numero']); if (!is_null($ultimaPaginaLivroAnterior)) { $getEstoque = function () use ($ultimaPaginaLivroAnterior) { $centroCustoId = $ultimaPaginaLivroAnterior->livro() ->first(['created_centro_custo_id']) ->created_centro_custo_id; return DB::table('farmacia_livro_pagina_linha as linha') ->leftJoin('almoxarifado_entrada_item as entrada_item', 'linha.entrada_item_id', 'entrada_item.id') ->leftJoin('almoxarifado_entrada as entrada', 'entrada_item.entrada_id', 'entrada.id') ->leftJoin('almoxarifado_saida_item as saida_item', 'linha.saida_item_id', 'saida_item.id') ->leftJoin('almoxarifado_saida as saida', 'saida_item.saida_id', 'saida.id') ->where('linha.pagina_id', $ultimaPaginaLivroAnterior->id) ->select(DB::raw("( SELECT SUM( almoxarifado_entrada_item.quantidade - COALESCE(( SELECT SUM(almoxarifado_saida_item_entrada_item.quantidade_saida) FROM almoxarifado_saida_item_entrada_item JOIN almoxarifado_saida_item ON almoxarifado_saida_item.id = almoxarifado_saida_item_entrada_item.saida_item_id JOIN almoxarifado_saida ON almoxarifado_saida.id = almoxarifado_saida_item.saida_id WHERE almoxarifado_saida_item_entrada_item.entrada_item_id = almoxarifado_entrada_item.id AND almoxarifado_saida.finalizada = 1 AND almoxarifado_saida.centro_custo_id = {$centroCustoId} AND almoxarifado_saida_item.estornado_em IS NULL AND ( almoxarifado_saida.created_at <= COALESCE(entrada.created_at, saida.created_at) OR almoxarifado_saida_item.id = COALESCE(almoxarifado_entrada_item.saida_item_estornado_id, 0) ) ), 0) ) FROM almoxarifado_entrada_item JOIN almoxarifado_entrada ON almoxarifado_entrada.id = almoxarifado_entrada_item.entrada_id WHERE almoxarifado_entrada.finalizada = 1 AND almoxarifado_entrada.centro_custo_id = {$centroCustoId} AND almoxarifado_entrada_item.material_id = {$ultimaPaginaLivroAnterior->material_id} AND almoxarifado_entrada.created_at <= COALESCE(entrada.created_at, saida.created_at) ) as estoque")) ->orderByDesc('linha.id') ->limit(1) ->first() ->estoque; }; $primeiraLinhaLivroNovo = $pagina->linhas()->orderBy('id')->first(['created_at']); $data = [ 'data' => (new Carbon($primeiraLinhaLivroNovo->created_at))->format('d/m/Y'), 'livro' => $ultimaPaginaLivroAnterior->livro()->first(['numero'])->numero, 'pagina' => $ultimaPaginaLivroAnterior->numero, 'estoque' => $getEstoque(), ]; return "Transferido do livro nº {$data['livro']}, página {$data['pagina']}, " . "na data {$data['data']}. Estoque {$data['estoque']}."; } return null; } private static function isUltimaPaginaMaterial($pagina) { $ultimaPaginaLivro = $pagina->livro()->first(['id'])->paginas() ->where('material_id', $pagina->material_id) ->orderByDesc('numero') ->first(['numero']); return $pagina->numero === $ultimaPaginaLivro->numero; } private static function getMessagePrimeiraPaginaLivroPosterior($pagina) { $livro = $pagina->livro()->first(['livro_registro_id', 'livro_registro_tipo_id']); $isTalidomida = $livro->livro_registro_id === LivroRegistroEnum::TALIDOMIDA; $primeiraPaginaLivroPosterior = LivroPagina::where('created_centro_custo_id', $pagina->created_centro_custo_id) ->where('livro_id', '>', $pagina->livro_id) ->where('material_id', $pagina->material_id) ->when($isTalidomida, function ($query) use ($livro) { $query->whereHas('livro', function ($query) use ($livro) { $query->where('livro_registro_tipo_id', $livro->livro_registro_tipo_id); }); }) ->orderBy('livro_id') ->orderBy('numero') ->first(['id', 'livro_id', 'numero']); if (!is_null($primeiraPaginaLivroPosterior)) { $primeiraLinhaLivroNovo = $primeiraPaginaLivroPosterior->linhas()->orderBy('id')->first(['created_at']); $data = [ 'data' => (new Carbon($primeiraLinhaLivroNovo->created_at))->format('d/m/Y'), 'livro' => $primeiraPaginaLivroPosterior->livro()->first(['numero'])->numero, 'pagina' => $primeiraPaginaLivroPosterior->numero, ]; return "Transferido para o livro nº {$data['livro']}, página {$data['pagina']}, " . "na data {$data['data']}."; } return null; } }