Files
Antonio Lopes dos Santos afec302c3e
All checks were successful
build-api-image / build (push) Successful in 51s
init commit
2026-08-04 16:52:02 -03:00

300 lines
14 KiB
PHP

<?php
namespace App\Services\AtencaoBasica\RelatorioInconsistencia;
use App\Enums\AtencaoBasica\CadastroDomiciliar\ImovelTipo;
use App\Enums\AtencaoBasica\Exportacao\Inconsistencia;
use App\Enums\AtencaoBasica\Parametrizacao\Permissao;
use App\Rules\AtencaoBasica\Exportacao\BairroIsRequired;
use App\Rules\AtencaoBasica\Exportacao\CepIsRequired;
use App\Rules\AtencaoBasica\Exportacao\CnesIsValid;
use App\Rules\AtencaoBasica\Exportacao\DataAtendimentoIsValid;
use App\Rules\AtencaoBasica\Exportacao\IbgeIsRequired;
use App\Rules\AtencaoBasica\Exportacao\IbgeIsValid;
use App\Rules\AtencaoBasica\Exportacao\LogradouroIsRequired;
use App\Rules\AtencaoBasica\Exportacao\LogradouroTipoIsRequired;
use App\Rules\AtencaoBasica\Exportacao\MicroAreaIsRequired;
use App\Rules\AtencaoBasica\Exportacao\OcupacaoIsAllowed;
use App\Rules\AtencaoBasica\Exportacao\ResponsavelTecnicoIsRequired;
use App\Rules\AtencaoBasica\Exportacao\UfIsRequired;
use App\Rules\AtencaoBasica\Exportacao\ZonaIsRequired;
use App\Rules\Cns;
use App\Rules\Cpf;
use App\Services\Service;
use App\Utils\MaskUtil;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class FichaCadastroDomiciliarService extends Service
{
private const ERROR_MAP = [
CnesIsValid::class => Inconsistencia::CNES_DA_UNIDADE_COM_TAMANHO_DIFERENTE_DE_7_CARACTERES,
IbgeIsValid::class => Inconsistencia::IBGE_DO_MUNICIPIO_SEM_PREENCHIMENTO_OU_INVALIDO,
IbgeIsRequired::class => Inconsistencia::IBGE_DO_MUNICIPIO_SEM_PREENCHIMENTO_OU_INVALIDO,
Cns::class => Inconsistencia::CNS_DO_PROFISSIONAL_INVALIDO,
OcupacaoIsAllowed::class => Inconsistencia::OCUPACAO_DO_USUARIO_SEM_PERMISSAO_PARA_REGISTRAR_A_FICHA,
DataAtendimentoIsValid::class => Inconsistencia::DATA_ATENDIMENTO_INVALIDO,
BairroIsRequired::class => Inconsistencia::BAIRRO_SEM_PREENCHIMENTO,
CepIsRequired::class => Inconsistencia::CEP_SEM_PREENCHIMENTO,
LogradouroIsRequired::class => Inconsistencia::NOME_LOGRADOURO_SEM_PREENCHIMENTO,
UfIsRequired::class => Inconsistencia::UF_SEM_PREENCHIMENTO,
LogradouroTipoIsRequired::class => Inconsistencia::TIPO_DE_LOGRADOURO_SEM_PREENCHIMENTO,
MicroAreaIsRequired::class => Inconsistencia::MICROAREA_DO_PACIENTE_SEM_PREENCHIMENTO,
ZonaIsRequired::class => Inconsistencia::ZONA_SEM_PREENCHIMENTO,
ResponsavelTecnicoIsRequired::class => Inconsistencia::NOME_RESPONSAVEL_TECNICO_SEM_PREENCHIMENTO,
];
public static function index()
{
$mes_ano = request()->mes_ano;
$date = Carbon::createFromFormat('mY', $mes_ano);
$start = $date->copy()->startOfMonth()->toDateString();
$end = $date->copy()->endOfMonth()->toDateString();
$inconsistencias = DB::table('atencao_basica_inconsistencia')
->select('id', 'descricao')
->get()
->pluck('descricao', 'id');
$fichasCadastroDomiciliar = DB::table('atencao_basica_cadastro_domiciliar')
->select([
'atencao_basica_cadastro_domiciliar.id as id',
'atencao_basica_cadastro_domiciliar.usuario_id as usuario_id',
'atencao_basica_cadastro_domiciliar.data_usuario_responsavel as data_atendimento',
'cadastro_unidade.cnes as unidade_cnes',
'cadastro_municipio.ibge as municipio_ibge',
'sigtap.ocupacao.codigo as ocupacao_codigo',
'cadastro_cidadao.cns AS usuario_cns',
'cadastro_cidadao.nome AS profissional_nome',
'logradouro.bairro_id as logradouro_bairro_id',
'logradouro.cep as logradouro_cep',
'logradouro.nome AS logradouro_nome',
'endereco.numero as endereco_numero',
'municipio.ibge as logradouro_municipio_ibge',
'estado.codigo as uf_codigo',
'logradouro_tipo.codigo as logradouro_tipo_codigo',
'atencao_basica_cadastro_domiciliar.domicilio_id',
'atencao_basica_cadastro_domiciliar.fora_area',
'atencao_basica_cadastro_domiciliar.microarea_id as logradouro_microarea_id',
'atencao_basica_cadastro_domiciliar.domicilio_zona_id',
'atencao_basica_cadastro_domiciliar.situacao_domicilio_id',
'atencao_basica_cadastro_domiciliar.instituicao_nome_responsavel_tecnico',
'atencao_basica_cadastro_imovel_tipo.codigo_esus as imovel_tipo_codigo_esus',
])
->join('atencao_basica_parametrizacao_equipe', 'atencao_basica_parametrizacao_equipe.id', 'atencao_basica_cadastro_domiciliar.equipe_id')
->join('cadastro_unidade', 'cadastro_unidade.id', 'atencao_basica_parametrizacao_equipe.unidade_id')
->join('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'atencao_basica_parametrizacao_equipe.infraestrutura_id')
->leftJoin('cadastro_endereco', 'cadastro_endereco.id', 'cadastro_infraestrutura.endereco_id')
->leftJoin('cadastro_logradouro', 'cadastro_logradouro.id', 'cadastro_endereco.logradouro_id')
->leftJoin('intranet.cadastro_municipio', 'cadastro_municipio.id', 'cadastro_logradouro.municipio_id')
->join('cadastro_usuario', 'cadastro_usuario.id', 'atencao_basica_cadastro_domiciliar.usuario_id')
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_usuario.cidadao_id')
->join('sigtap.ocupacao', 'sigtap.ocupacao.id', 'atencao_basica_cadastro_domiciliar.usuario_ocupacao_id')
->join('cadastro_domicilio', 'cadastro_domicilio.id', 'atencao_basica_cadastro_domiciliar.domicilio_id')
->join('atencao_basica_cadastro_imovel_tipo', 'atencao_basica_cadastro_imovel_tipo.id', 'atencao_basica_cadastro_domiciliar.imovel_tipo_id')
->leftJoin('cadastro_endereco as endereco', 'endereco.id', 'cadastro_domicilio.endereco_id')
->leftJoin('cadastro_logradouro as logradouro', 'logradouro.id', 'endereco.logradouro_id')
->leftJoin('cadastro_logradouro_tipo as logradouro_tipo', 'logradouro_tipo.id', 'logradouro.tipo_id')
->leftJoin('intranet.cadastro_municipio as municipio', 'municipio.id', 'logradouro.municipio_id')
->leftJoin('intranet.cadastro_estado as estado', 'estado.id', 'municipio.estado_id')
->whereBetween('atencao_basica_cadastro_domiciliar.data_usuario_responsavel', [$start, $end])
->when(request()->unidade_id, fn ($query) => $query->where('atencao_basica_parametrizacao_equipe.unidade_id', request()->unidade_id))
->when(request()->infraestrutura_id, fn ($query) => $query->where('atencao_basica_parametrizacao_equipe.infraestrutura_id', request()->infraestrutura_id))
->when(request()->usuario_id, fn ($query) => $query->where('atencao_basica_cadastro_domiciliar.usuario_id', request()->usuario_id))
->get();
if ($fichasCadastroDomiciliar->isEmpty()) {
return [];
}
$residentesPorDomicilio = self::loadResidentes(
$fichasCadastroDomiciliar->pluck('domicilio_id')->filter()->unique()->all()
);
$groupedList = [];
foreach ($fichasCadastroDomiciliar as $ficha) {
$errosHeader = RelatorioInconsistenciaService::validHeader($ficha, Permissao::CADASTRO_DOMICILIAR);
$errosAtendimento = self::validAtendimento($ficha);
$errors = $errosHeader->merge($errosAtendimento);
$baseDescriptions = self::mapErrorsToDescriptions($errors, $inconsistencias);
foreach ($residentesPorDomicilio[$ficha->domicilio_id] ?? [] as $residente) {
$errorDescriptions = collect($baseDescriptions->all());
if (
$errosAtendimento->isNotEmpty()
&& !Cns::isValid($residente->cns)
&& !Cpf::isValid($residente->cpf)
) {
$descricao = $inconsistencias[Inconsistencia::CNS_DO_RESPONSAVEL_FAMILIAR_INVALIDO] ?? null;
if ($descricao !== null) {
$errorDescriptions->push($descricao);
}
}
if ($errorDescriptions->isEmpty()) {
continue;
}
$key = $ficha->data_atendimento . '|' . $residente->paciente_id . '|' . $ficha->usuario_id;
if (!isset($groupedList[$key])) {
$groupedList[$key] = [
'data' => (new Carbon($ficha->data_atendimento))->format('d/m/Y'),
'ficha' => 'Cadastro domiciliar',
'paciente_nome' => $residente->paciente_nome,
'paciente_nome_social' => $residente->paciente_nome_social,
'paciente_preferencia_nome_id' => $residente->paciente_preferencia_nome_id,
'paciente_prontuario' => $residente->paciente_prontuario,
'paciente_cns' => $residente->cns ? MaskUtil::getCnsMasked($residente->cns) : '-',
'paciente_cpf' => $residente->cpf ? MaskUtil::getCpfMasked($residente->cpf) : '-',
'profissional' => $ficha->profissional_nome,
'erros' => $errorDescriptions,
];
} else {
$groupedList[$key]['erros'] = $groupedList[$key]['erros']->merge($errorDescriptions);
}
}
}
$result = [];
foreach ($groupedList as $group) {
$unique = $group['erros']->unique();
$group['erros'] = $unique->implode('<br />');
$group['total_erros'] = $unique->count();
$result[] = $group;
}
return $result;
}
private static function mapErrorsToDescriptions(Collection $errors, Collection $inconsistencias): Collection
{
$descriptions = collect();
foreach ($errors as $error) {
$inconsistenciaId = self::ERROR_MAP[$error] ?? null;
if ($inconsistenciaId === null) {
continue;
}
$descricao = $inconsistencias[$inconsistenciaId] ?? null;
if ($descricao !== null) {
$descriptions->push($descricao);
}
}
return $descriptions;
}
private static function validAtendimento($cadastro): Collection
{
$errors = collect();
if (!BairroIsRequired::isValid($cadastro->logradouro_bairro_id)) {
$errors->push(BairroIsRequired::class);
}
if (!CepIsRequired::isValid($cadastro->logradouro_cep)) {
$errors->push(CepIsRequired::class);
}
if (!IbgeIsRequired::isValid($cadastro->logradouro_municipio_ibge)) {
$errors->push(IbgeIsRequired::class);
}
if (!IbgeIsValid::isValid($cadastro->logradouro_municipio_ibge)) {
$errors->push(IbgeIsValid::class);
}
if (!LogradouroIsRequired::isValid($cadastro->logradouro_nome)) {
$errors->push(LogradouroIsRequired::class);
}
if (!UfIsRequired::isValid($cadastro->uf_codigo)) {
$errors->push(UfIsRequired::class);
}
if (!LogradouroTipoIsRequired::isValid($cadastro->logradouro_tipo_codigo)) {
$errors->push(LogradouroTipoIsRequired::class);
}
if (!$cadastro->fora_area && !MicroAreaIsRequired::isValid($cadastro->logradouro_microarea_id)) {
$errors->push(MicroAreaIsRequired::class);
}
if (!ZonaIsRequired::isValid($cadastro->domicilio_zona_id)) {
$errors->push(ZonaIsRequired::class);
}
if (self::handleTipoImovelPermanencia($cadastro->imovel_tipo_codigo_esus)
&& !ResponsavelTecnicoIsRequired::isValid($cadastro->instituicao_nome_responsavel_tecnico)) {
$errors->push(ResponsavelTecnicoIsRequired::class);
}
return $errors;
}
private static function loadResidentes(array $domicilioIds): array
{
if (empty($domicilioIds)) {
return [];
}
$rows = DB::table('cadastro_cidadao')
->select([
'cadastro_cidadao.domicilio_id',
'atencao_basica_cadastro_individual.responsavel AS responsavel',
'atencao_basica_cadastro_individual.responsavel_cidadao_id AS responsavel_cidadao_id',
'cadastro_cidadao.data_nascimento',
'cadastro_cidadao.cns',
'cadastro_cidadao.cpf',
'cadastro_cidadao.nome as paciente_nome',
'cadastro_cidadao.nome_social as paciente_nome_social',
'cadastro_cidadao.preferencia_nome_id as paciente_preferencia_nome_id',
'atencao_basica_cadastro_individual.renda_mensal as renda_responsavel',
'cadastro_paciente.id as paciente_id',
DB::raw('LPAD(cadastro_paciente.prontuario,7,0) AS paciente_prontuario'),
])
->join('cadastro_paciente', 'cadastro_paciente.cidadao_id', 'cadastro_cidadao.id')
->join('atencao_basica_cadastro_individual', 'atencao_basica_cadastro_individual.paciente_id', 'cadastro_paciente.id')
->whereIn('cadastro_cidadao.domicilio_id', $domicilioIds)
->where('atencao_basica_cadastro_individual.responsavel', true)
->whereNotExists(function ($query) {
$query->select(DB::raw(1))
->from('cadastro_obito')
->whereColumn('cadastro_obito.cidadao_id', 'cadastro_cidadao.id');
})
->get();
$porDomicilio = [];
foreach ($rows as $row) {
$porDomicilio[$row->domicilio_id][] = $row;
}
return $porDomicilio;
}
private static function handleTipoImovelPermanencia($tipoImovel): bool
{
return $tipoImovel == ImovelTipo::ABRIGO
|| $tipoImovel == ImovelTipo::INSTITUICAO_LONGA_PERMANENCIA_IDOSOS
|| $tipoImovel == ImovelTipo::UNIDADE_PRISIONAL
|| $tipoImovel == ImovelTipo::UNIDADE_MEDIDA_SOCIO_EDUCATIVA
|| $tipoImovel == ImovelTipo::DELEGACIA;
}
}