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

327 lines
13 KiB
PHP

<?php
namespace App\Services\Mobile\ConectaCidadao\Farmacia;
use App\Enums\Geral\MedidaTempo;
use App\Models\Farmacia\AppCidadaoLog;
use App\Models\Farmacia\ParametrizacaoAppCidadao;
use App\Services\Service;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
class ReceitaService extends Service
{
public static function index(): array
{
$parametrizacao = ParametrizacaoAppCidadao::first();
if (!($parametrizacao->permite_envio_receitas_medicas ?? false)) {
return ['habilitado' => false];
}
$pacienteId = auth('mobile')->user()->id;
$perPage = (int) request()->input('per_page', 15);
$page = (int) request()->input('page', 1);
$todos = self::queryAmbulatorioIds($pacienteId)->get()->map(
function ($r) {
return (array) $r;
}
);
$total = $todos->count();
$lastPage = max(1, (int) ceil($total / $perPage));
$page = max(1, min($page, $lastPage));
$slice = $todos->sortByDesc('data')->slice(($page - 1) * $perPage, $perPage)->values();
$ids = $slice->pluck('id')->toArray();
$receitas = collect();
if (!empty($ids)) {
$rows = self::queryAmbulatorioDetalhes($ids)->get();
foreach ($rows as $row) {
$receitas->push(
[
'id' => $row->prescricao_id,
'data_emissao' => $row->data_receita,
'validade' => null,
'situacao' => 'ativa',
'unidade' => $row->unidade_nome,
'prescritor' => $row->prescritor_nome,
'total_itens' => $row->total_itens,
]
);
}
}
self::log($pacienteId, 'LISTA_RECEITAS');
return [
'habilitado' => true,
'data' => $receitas->sortByDesc('data_emissao')->values(),
'current_page' => $page,
'last_page' => $lastPage,
'total' => $total,
'per_page' => $perPage,
];
}
public static function show(int $id): array
{
$parametrizacao = ParametrizacaoAppCidadao::first();
if (!($parametrizacao->permite_envio_receitas_medicas ?? false)) {
return ['habilitado' => false];
}
$pacienteId = auth('mobile')->user()->id;
$pacienteNome = DB::table('cadastro_paciente')
->join('cadastro_cidadao', 'cadastro_cidadao.id', 'cadastro_paciente.cidadao_id')
->where('cadastro_paciente.id', $pacienteId)
->value('cadastro_cidadao.nome');
$header = DB::table('ambulatorio_atendimento_soap_prescricao_medicamento as prescricao')
->select(
'prescricao.id',
'prescricao.created_at as data_receita',
'prescritor_cidadao.nome as prescritor_nome',
'cadastro_unidade.nome_fantasia as unidade_nome',
'cid.codigo as cid_codigo',
'cid.nome as cid_nome'
)
->join('ambulatorio_atendimento_soap as soap', 'soap.id', 'prescricao.soap_id')
->join('ambulatorio_atendimento as atendimento', 'atendimento.id', 'soap.atendimento_id')
->leftJoin('cadastro_lotacao', 'cadastro_lotacao.id', 'prescricao.created_lotacao_id')
->leftJoin('cadastro_usuario', 'cadastro_usuario.id', 'cadastro_lotacao.usuario_id')
->leftJoin('cadastro_cidadao as prescritor_cidadao', 'prescritor_cidadao.id', 'cadastro_usuario.cidadao_id')
->leftJoin('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_lotacao.infraestrutura_id')
->leftJoin('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->leftJoin(
DB::raw('(SELECT soap_id, MIN(cid_id) as cid_id FROM ambulatorio_atendimento_soap_problema_condicao WHERE cid_id IS NOT NULL GROUP BY soap_id) as cond'),
'cond.soap_id',
'=',
'soap.id'
)
->leftJoin('sigtap.cid as cid', 'cid.id', 'cond.cid_id')
->where('prescricao.id', $id)
->where(function ($q) use ($pacienteId) {
$q->whereExists(function ($q2) use ($pacienteId) {
$q2->select(DB::raw(1))
->from('ambulatorio_agendamento as ag')
->whereColumn('ag.id', 'atendimento.agendamento_id')
->where('ag.paciente_id', $pacienteId);
})->orWhereExists(function ($q2) use ($pacienteId) {
$q2->select(DB::raw(1))
->from('ambulatorio_demanda_espontanea as de')
->whereColumn('de.id', 'atendimento.demanda_espontanea_id')
->where('de.paciente_id', $pacienteId);
});
})
->first();
abort_if(!$header, Response::HTTP_NOT_FOUND);
$itens = DB::table('ambulatorio_atendimento_soap_prescricao_medicamento_item as item')
->select(
'item.id',
'item.material_id',
'item.descricao as item_descricao',
'item.justificativa',
'item.dose',
'item.intervalo',
'item.duracao',
'item.duracao_medida_tempo_id',
'item.recomendacoes',
'medida_tempo.nome as intervalo_medida_tempo_nome',
'unidade_medida.nome as apresentacao_unidade_medida',
'cadastro_via_administracao.nome as via_administracao',
DB::raw("CASE WHEN item.material_id IS NOT NULL THEN cadastro_material.descricao ELSE item.descricao END AS material_descricao")
)
->leftJoin('cadastro_material', 'cadastro_material.id', 'item.material_id')
->leftJoin('cadastro_unidade_medida AS unidade_medida', 'unidade_medida.id', 'item.unidade_medida_id')
->leftJoin('geral_medida_tempo as medida_tempo', 'medida_tempo.id', 'item.intervalo_medida_tempo_id')
->leftJoin('cadastro_via_administracao', 'cadastro_via_administracao.id', 'cadastro_material.via_administracao_id')
->where('item.prescricao_medicamento_id', $id)
->get()
->map(
function ($item) {
return [
'id' => $item->id,
'tipo' => is_null($item->material_id) ? 'nao_padronizado' : 'padronizado',
'medicamento' => $item->material_descricao,
'justificativa' => is_null($item->material_id) ? $item->justificativa : null,
'posologia_texto' => self::montarPosologiaTexto($item),
'posologia_incompleta' => is_null($item->intervalo),
'unidade_medida' => $item->apresentacao_unidade_medida,
'intervalo_tempo' => $item->intervalo,
'intervalo_medida_tempo' => $item->intervalo_medida_tempo_nome,
'durante_tempo' => self::calcularDuracaoEmDias($item->duracao, $item->duracao_medida_tempo_id),
'via_administracao' => $item->via_administracao,
'recomendacoes' => $item->recomendacoes,
];
}
);
self::log($pacienteId, 'DETALHE_RECEITA', $id);
return [
'id' => $header->id,
'paciente' => $pacienteNome,
'data_emissao' => $header->data_receita,
'validade' => null,
'situacao' => 'ativa',
'cid' => [
'codigo' => $header->cid_codigo,
'descricao' => $header->cid_nome,
],
'prescritor' => $header->prescritor_nome,
'unidade' => $header->unidade_nome,
'itens' => $itens,
];
}
private static function queryAmbulatorioIds(int $pacienteId)
{
return DB::table('ambulatorio_atendimento_soap_prescricao_medicamento as prescricao')
->select('prescricao.id', 'prescricao.created_at as data')
->join('ambulatorio_atendimento_soap as soap', 'soap.id', 'prescricao.soap_id')
->join('ambulatorio_atendimento as atendimento', 'atendimento.id', 'soap.atendimento_id')
->where('prescricao.solicitacao_fechada', false)
->where(function ($q) use ($pacienteId) {
$q->whereExists(function ($q2) use ($pacienteId) {
$q2->select(DB::raw(1))
->from('ambulatorio_agendamento as ag')
->whereColumn('ag.id', 'atendimento.agendamento_id')
->where('ag.paciente_id', $pacienteId);
})->orWhereExists(function ($q2) use ($pacienteId) {
$q2->select(DB::raw(1))
->from('ambulatorio_demanda_espontanea as de')
->whereColumn('de.id', 'atendimento.demanda_espontanea_id')
->where('de.paciente_id', $pacienteId);
});
});
}
private static function queryAmbulatorioDetalhes(array $ids)
{
return DB::table('ambulatorio_atendimento_soap_prescricao_medicamento as prescricao')
->select(
'prescricao.id as prescricao_id',
'prescricao.created_at as data_receita',
'prescritor_cidadao.nome as prescritor_nome',
'cadastro_unidade.nome_fantasia as unidade_nome',
DB::raw('(SELECT COUNT(*) FROM ambulatorio_atendimento_soap_prescricao_medicamento_item WHERE prescricao_medicamento_id = prescricao.id) as total_itens')
)
->leftJoin('cadastro_lotacao', 'cadastro_lotacao.id', 'prescricao.created_lotacao_id')
->leftJoin('cadastro_usuario', 'cadastro_usuario.id', 'cadastro_lotacao.usuario_id')
->leftJoin('cadastro_cidadao as prescritor_cidadao', 'prescritor_cidadao.id', 'cadastro_usuario.cidadao_id')
->leftJoin('cadastro_infraestrutura', 'cadastro_infraestrutura.id', 'cadastro_lotacao.infraestrutura_id')
->leftJoin('cadastro_unidade', 'cadastro_unidade.id', 'cadastro_infraestrutura.unidade_id')
->whereIn('prescricao.id', $ids);
}
private static function calcularDuracaoEmDias(?int $duracao, ?int $medidaTempoId): ?int
{
if (is_null($duracao)) {
return null;
}
if ($medidaTempoId === MedidaTempo::HORAS) {
return max(1, (int) ceil($duracao / 24));
}
if ($medidaTempoId === MedidaTempo::SEMANAS) {
return $duracao * 7;
}
if ($medidaTempoId === MedidaTempo::MESES) {
return $duracao * 30;
}
return $duracao;
}
private static function pluralizar(string $nome, int $valor): string
{
if (strpos($nome, '(es)') !== false) {
return $valor === 1
? str_replace('(es)', '', $nome)
: str_replace('(es)', 'es', $nome);
}
if (strpos($nome, '(s)') !== false) {
return $valor === 1
? str_replace('(s)', '', $nome)
: str_replace('(s)', 's', $nome);
}
return $nome;
}
private static function montarPosologiaTexto($row): ?string
{
$texto = '';
if (!is_null($row->dose)) {
$dose = (float) trim($row->dose);
$texto .= fmod($dose, 1) == 0 ? (int) $dose : number_format($dose, 2, ',', '.');
if ($row->apresentacao_unidade_medida) {
$texto .= ' ' . strtolower($row->apresentacao_unidade_medida);
}
}
if (!is_null($row->intervalo)) {
$intervalo = (int) $row->intervalo;
if ($row->intervalo_medida_tempo_nome) {
$unidade = strtolower(self::pluralizar($row->intervalo_medida_tempo_nome, $intervalo));
$texto .= $intervalo === 1
? " a cada {$unidade}"
: " a cada {$intervalo} {$unidade}";
} else {
$texto .= " a cada {$intervalo}";
}
}
if (!is_null($row->duracao)) {
$dias = self::calcularDuracaoEmDias((int) $row->duracao, $row->duracao_medida_tempo_id);
if (!is_null($dias)) {
$texto .= $dias === 1 ? ' durante 1 dia' : " durante {$dias} dias";
}
}
return empty($texto) ? null : $texto;
}
private static function log(int $pacienteId, string $tipoAcao, ?int $receitaId = null): void
{
AppCidadaoLog::create(
[
'paciente_id' => $pacienteId,
'receita_id' => $receitaId,
'tipo_acao' => $tipoAcao,
]
);
}
}