476 lines
16 KiB
PHP
476 lines
16 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Mobile\ConectaCidadao\Farmacia;
|
|
|
|
use App\Enums\Geral\MedidaTempo;
|
|
use App\Enums\Mobile\ConectaCidadao\Farmacia\MonitoramentoPosologia;
|
|
use App\Models\Farmacia\AppCidadaoLog;
|
|
use App\Models\Farmacia\ParametrizacaoAppCidadao;
|
|
use App\Models\Farmacia\ReceitaItem;
|
|
use App\Models\Farmacia\ReceitaMonitoramentoPosologia;
|
|
use App\Models\Farmacia\ReceitaTratamentoInicio;
|
|
use App\Services\Service;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class MonitoramentoPosologiaService extends Service
|
|
{
|
|
public static function medicamentos(): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$rows = DB::table('farmacia_receita_item as fri')
|
|
->select(
|
|
'fri.id as item_id',
|
|
'fr.id as receita_id',
|
|
'fr.data_receita',
|
|
'cm.descricao as material_descricao',
|
|
'um.nome as unidade_medida_nome',
|
|
'fri.quantidade',
|
|
'fri.intervalo_tempo',
|
|
'fri.intervalo_medida_tempo_id',
|
|
'mt.nome as intervalo_medida_tempo_nome',
|
|
'fri.durante_tempo',
|
|
'ti.inicio_em',
|
|
'ti.interrompido_em',
|
|
DB::raw("(SELECT COUNT(*) FROM farmacia_receita_monitoramento_posologia WHERE receita_item_id = fri.id AND paciente_id = {$pacienteId}) as total_confirmadas")
|
|
)
|
|
->join('farmacia_receita as fr', 'fr.id', 'fri.receita_id')
|
|
->join('cadastro_material as cm', 'cm.id', 'fri.material_id')
|
|
->leftJoin('cadastro_unidade_medida as um', 'um.id', 'cm.apresentacao_unidade_medida_id')
|
|
->leftJoin('geral_medida_tempo as mt', 'mt.id', 'fri.intervalo_medida_tempo_id')
|
|
->leftJoin('farmacia_receita_tratamento_inicio as ti', function ($join) use ($pacienteId) {
|
|
$join->on('ti.receita_item_id', '=', 'fri.id')
|
|
->where('ti.paciente_id', '=', $pacienteId);
|
|
})
|
|
->where('fr.paciente_id', $pacienteId)
|
|
->where(function ($q) {
|
|
$q->whereDate('fri.proxima_retirada', '>=', now()->toDateString())
|
|
->orWhereNotNull('ti.inicio_em');
|
|
})
|
|
->orderBy('fr.data_receita', 'desc')
|
|
->orderBy('fri.id', 'asc')
|
|
->get();
|
|
|
|
$receitas = [];
|
|
|
|
foreach ($rows as $row) {
|
|
|
|
$receitaId = $row->receita_id;
|
|
|
|
if (!isset($receitas[$receitaId])) {
|
|
|
|
$receitas[$receitaId] = [
|
|
'id' => $receitaId,
|
|
'data_receita' => $row->data_receita,
|
|
'itens' => [],
|
|
];
|
|
}
|
|
|
|
$inicioEm = $row->inicio_em ? Carbon::parse($row->inicio_em) : null;
|
|
$interrompidoEm = $row->interrompido_em ? Carbon::parse($row->interrompido_em) : null;
|
|
|
|
$receitas[$receitaId]['itens'][] = [
|
|
'id' => $row->item_id,
|
|
'medicamento' => $row->material_descricao,
|
|
'posologia_texto' => self::montarPosologiaTexto($row),
|
|
'posologia_incompleta' => is_null($row->intervalo_tempo) || is_null($row->durante_tempo),
|
|
'status' => self::calcularStatus(
|
|
$row->durante_tempo,
|
|
$row->intervalo_tempo,
|
|
$row->intervalo_medida_tempo_id,
|
|
$inicioEm,
|
|
$interrompidoEm,
|
|
(int) $row->total_confirmadas
|
|
),
|
|
];
|
|
}
|
|
|
|
return [
|
|
'habilitado' => true,
|
|
'data' => array_values($receitas),
|
|
];
|
|
}
|
|
|
|
public static function iniciar(int $receitaItemId): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$item = ReceitaItem::findOrFail($receitaItemId);
|
|
abort_if($item->receita->paciente_id !== $pacienteId, Response::HTTP_FORBIDDEN);
|
|
|
|
request()->validate([
|
|
'inicio_em' => ['required', 'date'],
|
|
'aderiu_tratamento' => ['nullable', 'boolean'],
|
|
]);
|
|
|
|
$inicioEm = Carbon::parse(request()->input('inicio_em'));
|
|
|
|
ReceitaTratamentoInicio::updateOrCreate(
|
|
['receita_item_id' => $receitaItemId, 'paciente_id' => $pacienteId],
|
|
[
|
|
'inicio_em' => $inicioEm,
|
|
'interrompido_em' => null,
|
|
'aderiu_tratamento' => request()->boolean('aderiu_tratamento'),
|
|
]
|
|
);
|
|
|
|
if ($inicioEm->isPast()) {
|
|
|
|
ReceitaMonitoramentoPosologia::firstOrCreate(
|
|
['receita_item_id' => $receitaItemId, 'paciente_id' => $pacienteId, 'dose_numero' => 1],
|
|
['confirmado_em' => $inicioEm, 'observacao' => null]
|
|
);
|
|
}
|
|
|
|
self::log($pacienteId, 'INICIO_TRATAMENTO', $item->receita_id, $receitaItemId);
|
|
|
|
return ['registrado' => true];
|
|
}
|
|
|
|
public static function index(int $receitaItemId): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$item = ReceitaItem::findOrFail($receitaItemId);
|
|
abort_if($item->receita->paciente_id !== $pacienteId, Response::HTTP_FORBIDDEN);
|
|
|
|
$inicio = ReceitaTratamentoInicio::where('receita_item_id', $receitaItemId)
|
|
->where('paciente_id', $pacienteId)
|
|
->first();
|
|
|
|
$confirmacoes = ReceitaMonitoramentoPosologia::where('receita_item_id', $receitaItemId)
|
|
->where('paciente_id', $pacienteId)
|
|
->orderBy('dose_numero')
|
|
->get();
|
|
|
|
$inicioEm = $inicio ? $inicio->inicio_em : null;
|
|
$interrompidoEm = $inicio ? $inicio->interrompido_em : null;
|
|
|
|
$status = self::calcularStatus(
|
|
$item->durante_tempo,
|
|
$item->intervalo_tempo,
|
|
$item->intervalo_medida_tempo_id,
|
|
$inicioEm,
|
|
$interrompidoEm,
|
|
$confirmacoes->count()
|
|
);
|
|
|
|
$cronograma = self::calcularCronograma($item, $inicio, $confirmacoes);
|
|
$adesao = self::calcularAdesao($item, $inicioEm, $confirmacoes->count());
|
|
|
|
self::log($pacienteId, 'CONSULTA_MONITORAMENTO', $item->receita_id, $receitaItemId);
|
|
|
|
return [
|
|
'receita_item_id' => $receitaItemId,
|
|
'medicamento' => $item->material->descricao,
|
|
'posologia_incompleta' => is_null($item->intervalo_tempo) || is_null($item->durante_tempo),
|
|
'status' => $status,
|
|
'inicio_em' => $inicioEm,
|
|
'interrompido_em' => $interrompidoEm,
|
|
'adesao' => $adesao,
|
|
'cronograma' => $cronograma,
|
|
];
|
|
}
|
|
|
|
public static function store(int $receitaItemId): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$item = ReceitaItem::findOrFail($receitaItemId);
|
|
abort_if($item->receita->paciente_id !== $pacienteId, Response::HTTP_FORBIDDEN);
|
|
|
|
$inicio = ReceitaTratamentoInicio::where('receita_item_id', $receitaItemId)
|
|
->where('paciente_id', $pacienteId)
|
|
->first();
|
|
|
|
abort_if(is_null($inicio), Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
abort_if(!is_null($inicio->interrompido_em), Response::HTTP_FORBIDDEN);
|
|
|
|
request()->validate([
|
|
'confirmado_em' => ['required', 'date'],
|
|
'dose_numero' => ['required', 'integer', 'min:1'],
|
|
'observacao' => ['nullable', 'string', 'max:500'],
|
|
]);
|
|
|
|
$monitoramento = ReceitaMonitoramentoPosologia::create([
|
|
'receita_item_id' => $receitaItemId,
|
|
'paciente_id' => $pacienteId,
|
|
'confirmado_em' => request()->input('confirmado_em'),
|
|
'dose_numero' => request()->input('dose_numero'),
|
|
'observacao' => request()->input('observacao'),
|
|
]);
|
|
|
|
self::log($pacienteId, 'CONFIRMAR_DOSE', $item->receita_id, $receitaItemId);
|
|
|
|
return ['id' => $monitoramento->id];
|
|
}
|
|
|
|
public static function destroy(int $id): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$monitoramento = ReceitaMonitoramentoPosologia::findOrFail($id);
|
|
abort_if($monitoramento->paciente_id !== $pacienteId, Response::HTTP_FORBIDDEN);
|
|
|
|
$receitaId = $monitoramento->receitaItem->receita_id;
|
|
$receitaItemId = $monitoramento->receita_item_id;
|
|
|
|
$monitoramento->delete();
|
|
|
|
self::log($pacienteId, 'CANCELAR_DOSE', $receitaId, $receitaItemId);
|
|
|
|
return ['removido' => true];
|
|
}
|
|
|
|
public static function interromper(int $receitaItemId): array
|
|
{
|
|
self::verificarParametrizacao();
|
|
|
|
$pacienteId = auth('mobile')->user()->id;
|
|
|
|
$item = ReceitaItem::findOrFail($receitaItemId);
|
|
abort_if($item->receita->paciente_id !== $pacienteId, Response::HTTP_FORBIDDEN);
|
|
|
|
$inicio = ReceitaTratamentoInicio::where('receita_item_id', $receitaItemId)
|
|
->where('paciente_id', $pacienteId)
|
|
->whereNull('interrompido_em')
|
|
->firstOrFail();
|
|
|
|
$inicio->update(['interrompido_em' => Carbon::now()]);
|
|
|
|
self::log($pacienteId, 'INTERROMPER_MONITORAMENTO', $item->receita_id, $receitaItemId);
|
|
|
|
return ['interrompido' => true];
|
|
}
|
|
|
|
private static function calcularStatus(
|
|
?int $duranteTempo,
|
|
?int $intervaloTempo,
|
|
?int $intervaloMedidaTempoId,
|
|
?Carbon $inicioEm,
|
|
?Carbon $interrompidoEm,
|
|
int $totalConfirmadas
|
|
): string {
|
|
|
|
if (is_null($inicioEm)) {
|
|
|
|
return MonitoramentoPosologia::STATUS_NAO_INICIADO;
|
|
}
|
|
|
|
if (!is_null($interrompidoEm)) {
|
|
|
|
return MonitoramentoPosologia::STATUS_INTERROMPIDO;
|
|
}
|
|
|
|
if (is_null($duranteTempo) || is_null($intervaloTempo)) {
|
|
|
|
return MonitoramentoPosologia::STATUS_EM_ANDAMENTO;
|
|
}
|
|
|
|
$intervaloMinutos = self::calcularIntervaloEmMinutos($intervaloTempo, $intervaloMedidaTempoId);
|
|
|
|
if ($intervaloMinutos > 0) {
|
|
|
|
$totalDosesPrevistas = (int) ceil(($duranteTempo * 24 * 60) / $intervaloMinutos);
|
|
|
|
if ($totalConfirmadas >= $totalDosesPrevistas) {
|
|
|
|
return MonitoramentoPosologia::STATUS_FINALIZADO;
|
|
}
|
|
}
|
|
|
|
$fimTratamento = $inicioEm->copy()->addDays($duranteTempo);
|
|
|
|
if (Carbon::now()->lessThanOrEqualTo($fimTratamento)) {
|
|
|
|
return MonitoramentoPosologia::STATUS_EM_ANDAMENTO;
|
|
}
|
|
|
|
return $totalConfirmadas > 0 ? MonitoramentoPosologia::STATUS_FINALIZADO : MonitoramentoPosologia::STATUS_EXPIRADO;
|
|
}
|
|
|
|
private static function calcularCronograma(ReceitaItem $item, ?ReceitaTratamentoInicio $inicio, Collection $confirmacoes): array
|
|
{
|
|
if (is_null($inicio) || is_null($item->intervalo_tempo) || is_null($item->durante_tempo)) {
|
|
|
|
return [];
|
|
}
|
|
|
|
$intervaloMinutos = self::calcularIntervaloEmMinutos($item->intervalo_tempo, $item->intervalo_medida_tempo_id);
|
|
|
|
if ($intervaloMinutos <= 0) {
|
|
|
|
return [];
|
|
}
|
|
|
|
$duracaoMinutos = $item->durante_tempo * 24 * 60;
|
|
$totalDoses = (int) ceil($duracaoMinutos / $intervaloMinutos);
|
|
|
|
$confirmacoesPorNumero = $confirmacoes->keyBy('dose_numero');
|
|
|
|
$cronograma = [];
|
|
|
|
for ($i = 0; $i < $totalDoses; $i++) {
|
|
|
|
$doseNumero = $i + 1;
|
|
$esperadoEm = $inicio->inicio_em->copy()->addMinutes($i * $intervaloMinutos);
|
|
$confirmacao = $confirmacoesPorNumero->get($doseNumero);
|
|
|
|
if ($confirmacao) {
|
|
|
|
$statusDose = MonitoramentoPosologia::STATUS_DOSE_CONFIRMADA;
|
|
} elseif ($esperadoEm->copy()->addMinutes(MonitoramentoPosologia::TOLERANCIA_ATRASO_MINUTOS)->isPast()) {
|
|
|
|
$statusDose = MonitoramentoPosologia::STATUS_DOSE_ATRASADA;
|
|
} else {
|
|
|
|
$statusDose = MonitoramentoPosologia::STATUS_DOSE_PENDENTE;
|
|
}
|
|
|
|
$cronograma[] = [
|
|
'id' => $confirmacao ? $confirmacao->id : null,
|
|
'numero' => $doseNumero,
|
|
'esperado_em' => $esperadoEm->toDateTimeString(),
|
|
'confirmado_em' => $confirmacao ? $confirmacao->confirmado_em : null,
|
|
'status' => $statusDose,
|
|
'observacao' => $confirmacao ? $confirmacao->observacao : null,
|
|
];
|
|
}
|
|
|
|
return $cronograma;
|
|
}
|
|
|
|
private static function calcularIntervaloEmMinutos(int $intervalo, ?int $medidaTempoId): int
|
|
{
|
|
if ($medidaTempoId === MedidaTempo::MINUTOS) {
|
|
|
|
return $intervalo;
|
|
}
|
|
|
|
if ($medidaTempoId === MedidaTempo::DIAS) {
|
|
|
|
return $intervalo * 24 * 60;
|
|
}
|
|
|
|
if ($medidaTempoId === MedidaTempo::SEMANAS) {
|
|
|
|
return $intervalo * 7 * 24 * 60;
|
|
}
|
|
|
|
return $intervalo * 60;
|
|
}
|
|
|
|
private static function calcularAdesao(ReceitaItem $item, ?Carbon $inicioEm, int $confirmadas): array
|
|
{
|
|
if (is_null($inicioEm) || is_null($item->intervalo_tempo) || is_null($item->durante_tempo)) {
|
|
|
|
return [
|
|
'doses_previstas' => null,
|
|
'doses_confirmadas' => $confirmadas,
|
|
'percentual' => null,
|
|
];
|
|
}
|
|
|
|
$intervaloMinutos = self::calcularIntervaloEmMinutos($item->intervalo_tempo, $item->intervalo_medida_tempo_id);
|
|
$duracaoMinutos = $item->durante_tempo * 24 * 60;
|
|
$decorridoMinutos = min($inicioEm->diffInMinutes(Carbon::now()), $duracaoMinutos);
|
|
|
|
$previstas = $intervaloMinutos > 0 ? (int) ceil($decorridoMinutos / $intervaloMinutos) : 0;
|
|
$percentual = $previstas > 0 ? round(($confirmadas / $previstas) * 100, 1) : null;
|
|
|
|
return [
|
|
'doses_previstas' => $previstas,
|
|
'doses_confirmadas' => $confirmadas,
|
|
'percentual' => $percentual,
|
|
];
|
|
}
|
|
|
|
private static function montarPosologiaTexto(object $row): ?string
|
|
{
|
|
$texto = '';
|
|
|
|
if (!is_null($row->quantidade)) {
|
|
|
|
$quantidade = (float) $row->quantidade;
|
|
$texto .= fmod($quantidade, 1) == 0 ? (int) $quantidade : number_format($quantidade, 2, ',', '.');
|
|
|
|
if ($row->unidade_medida_nome) {
|
|
|
|
$texto .= ' ' . strtolower($row->unidade_medida_nome);
|
|
}
|
|
}
|
|
|
|
if (!is_null($row->intervalo_tempo)) {
|
|
|
|
$intervalo = (int) $row->intervalo_tempo;
|
|
|
|
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->durante_tempo)) {
|
|
|
|
$dias = (int) $row->durante_tempo;
|
|
$texto .= $dias === 1 ? ' durante 1 dia' : " durante {$dias} dias";
|
|
}
|
|
|
|
return empty($texto) ? null : $texto;
|
|
}
|
|
|
|
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 verificarParametrizacao(): void
|
|
{
|
|
$parametrizacao = ParametrizacaoAppCidadao::first();
|
|
abort_if(!($parametrizacao->permite_envio_receitas_medicas ?? false), Response::HTTP_FORBIDDEN);
|
|
}
|
|
|
|
private static function log(int $pacienteId, string $tipoAcao, ?int $receitaId = null, ?int $receitaItemId = null): void
|
|
{
|
|
AppCidadaoLog::create([
|
|
'paciente_id' => $pacienteId,
|
|
'receita_id' => $receitaId,
|
|
'receita_item_id' => $receitaItemId,
|
|
'tipo_acao' => $tipoAcao,
|
|
]);
|
|
}
|
|
}
|