1041 lines
35 KiB
PHP
1041 lines
35 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\ProntoAtendimento\Plantao;
|
|
|
|
use App\Enums\ProntoAtendimento\Plantao\Status as PlantaoStatus;
|
|
use App\Enums\ProntoAtendimento\Plantao\TipoEscala;
|
|
use App\Exceptions\ProntoAtendimento\Plantao\ConflictingPlantaoException;
|
|
use App\Exceptions\ProntoAtendimento\Plantao\PlantaoComTempoAdicionalConflitanteException;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\ProntoAtendimento\Plantao\PlantaoRequest;
|
|
use App\Models\Cadastro\Estabelecimento\Servico;
|
|
use App\Models\Cadastro\Estabelecimento\Unidade;
|
|
use App\Models\Cadastro\SujeitoAtencao\Lotacao;
|
|
use App\Models\Geral\FaixaEtaria;
|
|
use App\Models\ProntoAtendimento\Parametrizacao\Parametrizacao;
|
|
use App\Models\ProntoAtendimento\Plantao\Plantao;
|
|
use App\Models\ProntoAtendimento\Plantao\Status;
|
|
use App\Utils\Calculations\Week as WeekCalc;
|
|
use App\Utils\DataUtil;
|
|
use App\Utils\DateTimeUtil;
|
|
use Carbon\Carbon;
|
|
use Exception;
|
|
use Illuminate\Http\Response;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class PlantaoController extends Controller
|
|
{
|
|
protected $modulo = 'pronto-atendimento';
|
|
protected $funcionalidade = 'plantao';
|
|
|
|
private $businessRulesErrors = [];
|
|
|
|
public function datatable()
|
|
{
|
|
$plantoes = DB::table('pronto_atendimento_plantao')
|
|
->join(
|
|
'pronto_atendimento_plantao_status',
|
|
'pronto_atendimento_plantao.status_id',
|
|
'=',
|
|
'pronto_atendimento_plantao_status.id'
|
|
)
|
|
->join(
|
|
"cadastro_lotacao",
|
|
"pronto_atendimento_plantao.lotacao_id",
|
|
'=',
|
|
"cadastro_lotacao.id"
|
|
)
|
|
->join(
|
|
"cadastro_servico",
|
|
"pronto_atendimento_plantao.servico_id",
|
|
'=',
|
|
"cadastro_servico.id"
|
|
)
|
|
->join(
|
|
"cadastro_infraestrutura",
|
|
"cadastro_lotacao.infraestrutura_id",
|
|
'=',
|
|
"cadastro_infraestrutura.id"
|
|
)
|
|
->join(
|
|
'cadastro_unidade',
|
|
"cadastro_infraestrutura.unidade_id",
|
|
'=',
|
|
'cadastro_unidade.id'
|
|
)
|
|
->join(
|
|
"sigtap.ocupacao",
|
|
"cadastro_lotacao.ocupacao_id",
|
|
'=',
|
|
"sigtap.ocupacao.id"
|
|
)
|
|
->join(
|
|
"cadastro_usuario",
|
|
"cadastro_lotacao.usuario_id",
|
|
'=',
|
|
"cadastro_usuario.id"
|
|
)
|
|
->join(
|
|
"cadastro_cidadao",
|
|
"cadastro_usuario.cidadao_id",
|
|
'=',
|
|
"cadastro_cidadao.id"
|
|
)
|
|
->leftJoin(
|
|
"geral_faixa_etaria",
|
|
"pronto_atendimento_plantao.faixa_etaria_id",
|
|
'=',
|
|
"geral_faixa_etaria.id"
|
|
)
|
|
->select(
|
|
'pronto_atendimento_plantao.id',
|
|
DB::raw("DATE_FORMAT(pronto_atendimento_plantao.inicio, '%d/%m/%Y %H:%i') as inicio"),
|
|
DB::raw("DATE_FORMAT(pronto_atendimento_plantao.fim, '%d/%m/%Y %H:%i') as fim"),
|
|
'pronto_atendimento_plantao.quantidade_atendimentos',
|
|
'pronto_atendimento_plantao.status_id',
|
|
'cadastro_unidade.nome_fantasia as unidade_nome_fantasia',
|
|
'cadastro_servico.nome as nome_servico',
|
|
DB::raw('IF(cadastro_infraestrutura.nome IS NULL, '
|
|
. 'cadastro_unidade.nome_fantasia, cadastro_infraestrutura.nome) as infraestrutura_nome'),
|
|
'cadastro_cidadao.nome as cidadao_nome',
|
|
DB::raw("IF(geral_faixa_etaria.nome IS NULL, "
|
|
. "'TODOS', geral_faixa_etaria.nome) as faixa_etaria_nome"),
|
|
DB::raw("CONCAT(sigtap.ocupacao.codigo, ' - ', sigtap.ocupacao.nome) as ocupacao_codigo_nome")
|
|
)
|
|
->whereNull('pronto_atendimento_plantao.deleted_at');
|
|
|
|
if (DataUtil::isStringTrue(request()->query('current_date'))) {
|
|
|
|
$currentTimestamp = Carbon::now();
|
|
|
|
if (DataUtil::isStringTrue(request()->query('one_hour_before_start'))) {
|
|
|
|
$plantoes->whereRaw("DATE_SUB(pronto_atendimento_plantao.inicio, INTERVAL 60 MINUTE) "
|
|
. "<= '{$currentTimestamp->format('Y-m-d H:i:s')}'");
|
|
}
|
|
else {
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.inicio', '<=', $currentTimestamp->format('Y-m-d H:i:s'));
|
|
}
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.fim', '>=', $currentTimestamp->format('Y-m-d H:i:s'));
|
|
}
|
|
else {
|
|
|
|
if (DateTimeUtil::isFormattedCorrectly(request()->query('inicio'), 'Y-m-d H:i')) {
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.inicio', '>=', request()->query('inicio'));
|
|
}
|
|
|
|
if (DateTimeUtil::isFormattedCorrectly(request()->query('fim'), 'Y-m-d H:i')) {
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.fim', '<=', request()->query('fim'));
|
|
}
|
|
}
|
|
|
|
if (is_numeric(request()->query('unidade_id'))) {
|
|
|
|
$plantoes->where('cadastro_unidade.id', request()->query('unidade_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('infraestrutura_id'))) {
|
|
|
|
$plantoes->where("cadastro_lotacao.infraestrutura_id", request()->query('infraestrutura_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('usuario_id'))) {
|
|
|
|
$plantoes->where('cadastro_lotacao.usuario_id', request()->query('usuario_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('servico_id'))) {
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.servico_id', request()->query('servico_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('ocupacao_id'))) {
|
|
|
|
$plantoes->where('cadastro_lotacao.ocupacao_id', request()->query('ocupacao_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('status_id'))) {
|
|
|
|
$plantoes->where('pronto_atendimento_plantao.status_id', request()->query('status_id'));
|
|
}
|
|
else if (is_array(request()->query('status_id'))) {
|
|
|
|
$plantoes->whereIn('pronto_atendimento_plantao.status_id', request()->query('status_id'));
|
|
}
|
|
|
|
if (is_string(request()->query('order_by'))) {
|
|
|
|
switch (request()->query('order_by')) {
|
|
|
|
case 'inicio': {
|
|
|
|
$plantoes->orderBy('pronto_atendimento_plantao.inicio');
|
|
|
|
break;
|
|
}
|
|
case 'fim': {
|
|
|
|
$plantoes->orderBy('pronto_atendimento_plantao.fim');
|
|
|
|
break;
|
|
}
|
|
case 'unidade': {
|
|
|
|
$plantoes->orderBy("cadastro_unidade.nome_fantasia");
|
|
|
|
break;
|
|
}
|
|
case 'infraestrutura': {
|
|
|
|
$plantoes->orderByRaw("IF (cadastro_infraestrutura.nome IS NULL,
|
|
cadastro_unidade.nome_fantasia,
|
|
cadastro_infraestrutura.nome
|
|
)");
|
|
|
|
break;
|
|
}
|
|
case 'servico': {
|
|
|
|
$plantoes->orderBy("cadastro_servico.nome");
|
|
|
|
break;
|
|
}
|
|
case 'usuario': {
|
|
|
|
$plantoes->orderBy("cadastro_cidadao.nome");
|
|
|
|
break;
|
|
}
|
|
case 'ocupacao': {
|
|
|
|
$plantoes->orderBy("sigtap.ocupacao.codigo");
|
|
|
|
break;
|
|
}
|
|
case 'status': {
|
|
|
|
$plantoes->orderBy('pronto_atendimento_plantao_status.nome');
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return response()->json($plantoes->get(), Response::HTTP_OK);
|
|
}
|
|
|
|
public function list()
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
return response()->json(
|
|
[
|
|
'data_atual' => Carbon::now()->format('d/m/Y'),
|
|
'form' => [
|
|
'unidades' => $this->getUnidadesComLotacaoCentroCusto(),
|
|
'status' => Status::orderBy('nome')->get()->map(fn ($status) => [
|
|
'id' => $status->id,
|
|
'nome' => $status->nome,
|
|
'cor' => $status->cor,
|
|
'cor_hover' => $status->cor_hover,
|
|
]),
|
|
'servicos' => Servico::orderBy('nome')->get()->map(fn ($servicos) => [
|
|
'id' => $servicos->id,
|
|
'nome' => $servicos->nome,
|
|
]),
|
|
'ordenacao' => [
|
|
['value' => 'ocupacao', 'text' => 'CBO'],
|
|
['value' => 'inicio', 'text' => 'DATA DE ENTRADA'],
|
|
['value' => 'fim', 'text' => 'DATA DE SAÍDA'],
|
|
['value' => 'infraestrutura', 'text' => 'LOCAL DE ATENDIMENTO'],
|
|
['value' => 'usuario', 'text' => 'PROFISSIONAL'],
|
|
['value' => 'servico', 'text' => 'SERVIÇO'],
|
|
['value' => 'status', 'text' => 'STATUS'],
|
|
],
|
|
]
|
|
],
|
|
Response::HTTP_OK
|
|
);
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$plantoes = $this->get(Plantao::class);
|
|
|
|
if (is_numeric(request()->query('not_id'))) {
|
|
|
|
$plantoes->where('id', '<>', request()->query('not_id'));
|
|
}
|
|
|
|
if (is_numeric(request()->query('usuario_id'))) {
|
|
|
|
$plantoes->whereHas('lotacao', function ($lotacao) {
|
|
|
|
$lotacao->where('usuario_id', request()->query('usuario_id'));
|
|
});
|
|
}
|
|
|
|
$plantoes = $plantoes->get();
|
|
$restParams = $this->getRestParams();
|
|
|
|
if (!empty($restParams)) {
|
|
|
|
$inicioDescanso = $restParams['inicio'];
|
|
$fimDescanso = $restParams['fim'];
|
|
|
|
$between = fn ($value, $start, $end) => !is_null($value) && $value >= $start && $value <= $end;
|
|
|
|
$plantoes = $plantoes
|
|
->filter(function ($plantao) use ($between, $inicioDescanso, $fimDescanso) {
|
|
|
|
$periodoDescanso = $plantao->periodo_descanso;
|
|
|
|
if (empty($periodoDescanso)) {
|
|
|
|
return false;
|
|
}
|
|
|
|
return $between($inicioDescanso, $periodoDescanso['inicio'], $periodoDescanso['fim'])
|
|
|| $between($fimDescanso, $periodoDescanso['inicio'], $periodoDescanso['fim']);
|
|
})
|
|
->values();
|
|
}
|
|
|
|
return response()->json($plantoes, Response::HTTP_OK);
|
|
}
|
|
|
|
private function getRestParams()
|
|
{
|
|
if (is_array(request()->query('resting'))) {
|
|
|
|
$restParams = request()->query('resting');
|
|
$inicio = null;
|
|
$fim = null;
|
|
|
|
if (DateTimeUtil::isFormattedCorrectly($restParams['inicio'] ?? '', 'Y-m-d H:i:s')) {
|
|
|
|
$inicio = new Carbon(request()->query('resting')['inicio']);
|
|
}
|
|
|
|
if (DateTimeUtil::isFormattedCorrectly($restParams['fim'] ?? '', 'Y-m-d H:i:s')) {
|
|
|
|
$fim = new Carbon(request()->query('resting')['fim']);
|
|
}
|
|
|
|
return compact('inicio', 'fim');
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
public function create()
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
return response()->json(
|
|
[
|
|
'min_date' => Carbon::now()->subYear()->format('d/m/Y'),
|
|
'max_date' => Carbon::now()->addYear()->format('d/m/Y'),
|
|
'form' => $this->getFormData(),
|
|
'additionals' => [
|
|
'status_id' => null
|
|
]
|
|
],
|
|
Response::HTTP_OK
|
|
);
|
|
}
|
|
|
|
public function store(PlantaoRequest $request)
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$this->validateBusinessRules();
|
|
|
|
if ($this->hasBusinessRulesErrors()) {
|
|
|
|
return response()->json($this->businessRulesErrors, Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
$plantoes = null;
|
|
|
|
DB::transaction(function () use (&$plantoes, $request) {
|
|
|
|
$data = [
|
|
'lotacao_id' => $request->lotacao_id,
|
|
'servico_id' => $request->servico_id,
|
|
'faixa_etaria_id' => $request->faixa_etaria_id,
|
|
'escala_tipo_id' => $request->escala['tipo_id'],
|
|
'status_id' => $request->status_id,
|
|
];
|
|
|
|
if ($request->escala['tipo_id'] === TipoEscala::FIXA) {
|
|
|
|
$plantoes = $this->createPlantoesWithEscalasFixasTo($data);
|
|
}
|
|
else if ($request->escala['tipo_id'] === TipoEscala::DINAMICA) {
|
|
|
|
$plantoes = $this->createPlantoesWithEscalasDinamicasTo($data);
|
|
}
|
|
else if ($request->escala['tipo_id'] === TipoEscala::UNICA) {
|
|
|
|
$plantoes = $this->createPlantaoWithEscalaUnicaTo($data);
|
|
}
|
|
});
|
|
|
|
return response()->json($plantoes, Response::HTTP_CREATED);
|
|
}
|
|
|
|
private function createPlantoesWithEscalasFixasTo($data)
|
|
{
|
|
$plantoes = collect();
|
|
|
|
$inicioOfInterval = new Carbon(request()->escala['inicio']);
|
|
$fimOfInterval = new Carbon(request()->escala['fim'] . " {$inicioOfInterval->format('H:i:s')}");
|
|
$jornadaEmHoras = request()->escala['jornada_em_horas'];
|
|
$diasSemana = request()->escala['dias_semana'];
|
|
$currentDate = $inicioOfInterval->copy();
|
|
|
|
while ($currentDate <= $fimOfInterval) {
|
|
if (in_array($currentDate->format('w') + 1, $diasSemana)) {
|
|
|
|
$fim = $currentDate->copy()->modify("+{$jornadaEmHoras} hours");
|
|
|
|
$this->validateTimeEscala($data['lotacao_id'], $currentDate, $fim);
|
|
|
|
$this->verificaConflitoTempoAdicionalPlantao($data['lotacao_id'], $currentDate);
|
|
|
|
$plantao = Plantao::create([
|
|
'lotacao_id' => $data['lotacao_id'],
|
|
'servico_id' => $data['servico_id'],
|
|
'faixa_etaria_id' => $data['faixa_etaria_id'],
|
|
'escala_tipo_id' => $data['escala_tipo_id'],
|
|
'inicio' => $currentDate->format('Y-m-d H:i'),
|
|
'fim' => $fim->format('Y-m-d H:i'),
|
|
'quantidade_atendimentos' => request()->escala['quantidade_atendimentos'],
|
|
'status_id' => $data['status_id'] ?? PlantaoStatus::CADASTRADO,
|
|
]);
|
|
|
|
$plantoes->push($plantao);
|
|
}
|
|
|
|
$currentDate->addDay();
|
|
}
|
|
}
|
|
|
|
private function createPlantoesWithEscalasDinamicasTo($data)
|
|
{
|
|
$plantoes = collect();
|
|
|
|
$inicioOfInterval = new Carbon(request()->escala['inicio']);
|
|
$fimOfInterval = new Carbon(request()->escala['fim'] . " {$inicioOfInterval->format('H:i:s')}");
|
|
$jornadaEmHoras = request()->escala['jornada_em_horas'];
|
|
$restHours = $this->getRestHours();
|
|
$inicio = $inicioOfInterval->copy();
|
|
|
|
while ($inicio <= $fimOfInterval) {
|
|
|
|
$fim = $inicio->copy()->modify("+{$jornadaEmHoras} hours");
|
|
|
|
$this->validateTimeEscala($data['lotacao_id'], $inicio, $fim);
|
|
|
|
$this->verificaConflitoTempoAdicionalPlantao($data['lotacao_id'], $inicio);
|
|
|
|
$plantao = Plantao::create([
|
|
'lotacao_id' => $data['lotacao_id'],
|
|
'servico_id' => $data['servico_id'],
|
|
'faixa_etaria_id' => $data['faixa_etaria_id'],
|
|
'escala_tipo_id' => $data['escala_tipo_id'],
|
|
'inicio' => $inicio->format('Y-m-d H:i'),
|
|
'fim' => $fim->format('Y-m-d H:i'),
|
|
'quantidade_atendimentos' => request()->escala['quantidade_atendimentos'],
|
|
'status_id' => $data['status_id'] ?? PlantaoStatus::CADASTRADO,
|
|
]);
|
|
|
|
$plantoes->push($plantao);
|
|
|
|
$inicio = $fim->modify("+{$restHours} hours");
|
|
}
|
|
}
|
|
|
|
private function getRestHours()
|
|
{
|
|
switch (request()->escala['jornada_em_horas']) {
|
|
|
|
case 6: {
|
|
|
|
return 18;
|
|
}
|
|
case 8: {
|
|
|
|
return 16;
|
|
}
|
|
case 12: {
|
|
|
|
return 36;
|
|
}
|
|
case 24: {
|
|
|
|
return 48;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function createPlantaoWithEscalaUnicaTo($data)
|
|
{
|
|
$inicio = new Carbon(request()->escala['inicio']);
|
|
$fim = new Carbon(request()->escala['fim']);
|
|
|
|
$this->validateTimeEscala($data['lotacao_id'], $inicio, $fim);
|
|
|
|
$this->verificaConflitoTempoAdicionalPlantao($data['lotacao_id'], $inicio);
|
|
|
|
return Plantao::create([
|
|
'lotacao_id' => $data['lotacao_id'],
|
|
'servico_id' => $data['servico_id'],
|
|
'faixa_etaria_id' => $data['faixa_etaria_id'],
|
|
'escala_tipo_id' => $data['escala_tipo_id'],
|
|
'inicio' => $inicio->format('Y-m-d H:i'),
|
|
'fim' => $fim->format('Y-m-d H:i'),
|
|
'quantidade_atendimentos' => request()->escala['quantidade_atendimentos'],
|
|
'status_id' => $data['status_id'] ?? PlantaoStatus::CADASTRADO,
|
|
]);
|
|
}
|
|
|
|
public function show($id)
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$plantao = $this->get(Plantao::class, $id);
|
|
|
|
return response()->json($plantao, Response::HTTP_OK);
|
|
}
|
|
|
|
public function edit($id)
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$plantao = Plantao::findOrFail($id);
|
|
|
|
return response()->json(
|
|
[
|
|
'min_date' => Carbon::now()->subYear()->format('d/m/Y'),
|
|
'max_date' => Carbon::now()->addYear()->format('d/m/Y'),
|
|
'form' => array_merge($this->getFormData(), [
|
|
'unidade_id' => $plantao->lotacao->unidade_id,
|
|
'infraestrutura_id' => $plantao->lotacao->infraestrutura_id,
|
|
'servico_id' => $plantao->servico_id,
|
|
'usuario_id' => $plantao->lotacao->usuario_id,
|
|
'ocupacao_id' => $plantao->lotacao->ocupacao_id,
|
|
]),
|
|
'model' => [
|
|
'faixa_etaria_id' => $plantao->faixa_etaria_id,
|
|
'escala' => [
|
|
'periodo' => [
|
|
'start' => $plantao->inicio->format('d/m/Y'),
|
|
'end' => $plantao->fim->format('d/m/Y'),
|
|
],
|
|
'hora_entrada' => $plantao->inicio->format('H:i:s'),
|
|
'hora_saida' => $plantao->fim->format('H:i:s'),
|
|
'quantidade_atendimentos' => $plantao->quantidade_atendimentos,
|
|
]
|
|
],
|
|
'additionals' => [
|
|
'status_id' => $plantao->status_id
|
|
]
|
|
],
|
|
Response::HTTP_OK
|
|
);
|
|
}
|
|
|
|
private function getFormData()
|
|
{
|
|
return [
|
|
'servicos' => Servico::orderBy('nome')->get()->map(fn ($servicos) => [
|
|
'id' => $servicos->id,
|
|
'nome' => $servicos->nome,
|
|
]),
|
|
'unidades' => $this->getUnidadesComLotacaoCentroCusto(),
|
|
'faixas_etarias' => FaixaEtaria::orderBy('nome')->get(),
|
|
'dias_semana' => [
|
|
['value' => 1, 'text' => 'Domingo', 'disabled' => true],
|
|
['value' => 2, 'text' => 'Segunda', 'disabled' => true],
|
|
['value' => 3, 'text' => 'Terça', 'disabled' => true],
|
|
['value' => 4, 'text' => 'Quarta', 'disabled' => true],
|
|
['value' => 5, 'text' => 'Quinta', 'disabled' => true],
|
|
['value' => 6, 'text' => 'Sexta', 'disabled' => true],
|
|
['value' => 7, 'text' => 'Sábado', 'disabled' => true],
|
|
],
|
|
'jornadas' => [
|
|
['value' => 6, 'text' => '6 H'],
|
|
['value' => 8, 'text' => '8 H'],
|
|
['value' => 12, 'text' => '12 H'],
|
|
['value' => 24, 'text' => '24 H'],
|
|
],
|
|
'descansos' => [
|
|
['text' => '16 H', 'value' => 16, 'disabled' => true],
|
|
['text' => '18 H', 'value' => 18, 'disabled' => true],
|
|
['text' => '36 H', 'value' => 36, 'disabled' => true],
|
|
['text' => '48 H', 'value' => 48, 'disabled' => true],
|
|
],
|
|
];
|
|
}
|
|
|
|
private function getUnidadesComLotacaoCentroCusto()
|
|
{
|
|
$unidades = DB::table('cadastro_unidade')
|
|
->whereExists(function ($query) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_infraestrutura')
|
|
->whereColumn('cadastro_infraestrutura.unidade_id', 'cadastro_unidade.id')
|
|
->whereExists(function ($query) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_lotacao')
|
|
->whereColumn('cadastro_lotacao.infraestrutura_id', 'cadastro_infraestrutura.id');
|
|
})
|
|
->whereExists(function ($query) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_centro_custo')
|
|
->whereColumn('cadastro_centro_custo.infraestrutura_id', 'cadastro_infraestrutura.id');
|
|
});
|
|
})
|
|
->select(
|
|
'cadastro_unidade.id',
|
|
'cadastro_unidade.nome_fantasia'
|
|
)
|
|
->orderBy('cadastro_unidade.nome_fantasia')
|
|
->get();
|
|
|
|
$unidades->each(function ($unidade) {
|
|
|
|
$unidade->infraestruturas = DB::table('cadastro_infraestrutura')
|
|
->where('cadastro_infraestrutura.unidade_id', $unidade->id)
|
|
->whereExists(function ($query) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_lotacao')
|
|
->whereColumn('cadastro_lotacao.infraestrutura_id', 'cadastro_infraestrutura.id');
|
|
})
|
|
->whereExists(function ($query) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_centro_custo')
|
|
->whereColumn('cadastro_centro_custo.infraestrutura_id', 'cadastro_infraestrutura.id');
|
|
})
|
|
->select(
|
|
'cadastro_infraestrutura.id',
|
|
DB::raw("COALESCE(cadastro_infraestrutura.nome, '{$unidade->nome_fantasia}') AS nome")
|
|
)
|
|
->orderByRaw("COALESCE(cadastro_infraestrutura.nome, '{$unidade->nome_fantasia}')")
|
|
->get();
|
|
|
|
$unidade->infraestruturas->each(function ($infraestrutura) {
|
|
|
|
$infraestrutura->usuarios = DB::table('cadastro_usuario')
|
|
->join(
|
|
'cadastro_cidadao',
|
|
'cadastro_cidadao.id',
|
|
'cadastro_usuario.cidadao_id'
|
|
)
|
|
->whereExists(function ($query) use ($infraestrutura) {
|
|
|
|
$query
|
|
->select(DB::raw(1))
|
|
->from('cadastro_lotacao')
|
|
->whereColumn('cadastro_lotacao.usuario_id', 'cadastro_usuario.id')
|
|
->where('cadastro_lotacao.infraestrutura_id', $infraestrutura->id)
|
|
->whereNull('cadastro_lotacao.deleted_at')
|
|
->where('realiza_atendimento', true);
|
|
})
|
|
->select(
|
|
'cadastro_usuario.id',
|
|
'cadastro_cidadao.nome'
|
|
)
|
|
->orderBy('cadastro_cidadao.nome')
|
|
->get();
|
|
|
|
$infraestrutura->usuarios->each(function ($usuario) use ($infraestrutura) {
|
|
|
|
$usuario->ocupacoes = DB::table('sigtap.ocupacao')
|
|
->join(
|
|
'cadastro_lotacao',
|
|
'cadastro_lotacao.ocupacao_id',
|
|
'sigtap.ocupacao.id'
|
|
)
|
|
->where('cadastro_lotacao.usuario_id', $usuario->id)
|
|
->where('cadastro_lotacao.infraestrutura_id', $infraestrutura->id)
|
|
->whereNull('cadastro_lotacao.deleted_at')
|
|
->where('realiza_atendimento', true)
|
|
->select(
|
|
'sigtap.ocupacao.id',
|
|
DB::raw("CONCAT(sigtap.ocupacao.codigo, ' - ', sigtap.ocupacao.nome) as codigo_nome"),
|
|
'cadastro_lotacao.id AS lotacao_id'
|
|
)
|
|
->orderBy('sigtap.ocupacao.nome')
|
|
->get();
|
|
});
|
|
});
|
|
});
|
|
|
|
return $unidades;
|
|
}
|
|
|
|
public function update(PlantaoRequest $request, $id)
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$plantao = Plantao::findOrFail($id);
|
|
$params = $request->all();
|
|
|
|
if (!empty($params)) {
|
|
|
|
if (isset($params['status_id']) && is_numeric($params['status_id'])) {
|
|
|
|
$plantao->status_id = $params['status_id'];
|
|
}
|
|
|
|
if (isset($params['escala'])) {
|
|
|
|
$escala = $params['escala'];
|
|
|
|
if (isset($escala['inicio'])) {
|
|
|
|
$this->validateBusinessRulesToUpdateSinglePlantao($plantao);
|
|
|
|
if ($this->hasBusinessRulesErrors()) {
|
|
|
|
return response()->json($this->businessRulesErrors, Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
$inicio = new Carbon($escala['inicio']);
|
|
$fim = new Carbon($escala['fim']);
|
|
|
|
$this->validateTimeEscala($plantao->lotacao_id, $inicio, $fim, $plantao->id);
|
|
|
|
$plantao->inicio = $escala['inicio'];
|
|
$plantao->fim = $escala['fim'];
|
|
}
|
|
|
|
if (isset($escala['quantidade_atendimentos']) && is_numeric($escala['quantidade_atendimentos'])) {
|
|
|
|
$plantao->quantidade_atendimentos = $escala['quantidade_atendimentos'];
|
|
}
|
|
}
|
|
|
|
$plantao->save();
|
|
}
|
|
|
|
return response()->json($plantao->fresh(), Response::HTTP_OK);
|
|
}
|
|
|
|
public function updateAllStatus()
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
$plantoes = collect();
|
|
|
|
collect(request()->all())->each(function ($plantao) use ($plantoes) {
|
|
|
|
$plantao = tap(Plantao::findOrFail($plantao['id']))->update($plantao);
|
|
|
|
$plantoes->push($plantao->fresh());
|
|
});
|
|
|
|
return response()->json($plantoes, Response::HTTP_OK);
|
|
}
|
|
|
|
public function destroy($id)
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
Plantao::findOrFail($id)->delete();
|
|
|
|
return response()->json(null, Response::HTTP_NO_CONTENT);
|
|
}
|
|
|
|
public function destroyAll()
|
|
{
|
|
$this->auth(__FUNCTION__);
|
|
|
|
Plantao::destroy(request()->all());
|
|
|
|
return response()->json(null, Response::HTTP_NO_CONTENT);
|
|
}
|
|
|
|
private function validateBusinessRules()
|
|
{
|
|
$this->validateInicio();
|
|
$this->validateFim();
|
|
|
|
if ($this->isEscalaTipoFixa()) {
|
|
|
|
$this->validateDiasSemana();
|
|
}
|
|
}
|
|
|
|
private function validateBusinessRulesToUpdateSinglePlantao($plantao)
|
|
{
|
|
$this->validateInicio($plantao);
|
|
$this->validateFim($plantao);
|
|
}
|
|
|
|
private function validateInicio($plantao = null)
|
|
{
|
|
$errors = [];
|
|
|
|
if ($this->isInicioLessThanMinDate()) {
|
|
|
|
$errors[] = 'A data/hora inicial não pode ser uma data/hora anterior a um ano anterior da data atual.';
|
|
}
|
|
|
|
$inicio = new Carbon(request()->escala['inicio']);
|
|
|
|
if ($plantao && $plantao->date_time_of_first_atendimento && $inicio > $plantao->date_time_of_first_atendimento) {
|
|
|
|
$errors[] = "Início do plantão deve ser inferior ou igual ao primeiro "
|
|
. "atendimento {$plantao->date_time_of_first_atendimento->format('d/m/Y H:i')}.";
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
|
|
$this->businessRulesErrors['escala.inicio'] = $errors;
|
|
}
|
|
}
|
|
|
|
private function isInicioLessThanMinDate()
|
|
{
|
|
$minDate = Carbon::now()->subYear();
|
|
|
|
return new Carbon(request()->escala['inicio']) < $minDate;
|
|
}
|
|
|
|
private function validateFim($plantao = null)
|
|
{
|
|
$errors = [];
|
|
|
|
if ($this->isFimGreaterThanMaxDate()) {
|
|
|
|
$errors[] = 'A data/hora final não pode ser uma data/hora posterior a um ano anterior da data atual.';
|
|
}
|
|
|
|
if ($this->isEscalaTipoUnica() && $this->isFimGreaterThan24HoursFromInicio()) {
|
|
|
|
$errors[] = 'A data/hora final não pode ultrapassar 24 horas da data/hora inicial.';
|
|
}
|
|
|
|
$fim = new Carbon(request()->escala['fim']);
|
|
|
|
if ($plantao && $plantao->date_time_of_last_atendimento && $fim < $plantao->date_time_of_last_atendimento) {
|
|
|
|
$errors[] = "Fim do plantão deve ser superior ou igual ao último "
|
|
. "atendimento {$plantao->date_time_of_last_atendimento->format('d/m/Y H:i')}.";
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
|
|
$this->businessRulesErrors['escala.fim'] = $errors;
|
|
}
|
|
}
|
|
|
|
private function isFimGreaterThanMaxDate()
|
|
{
|
|
$maxDate = Carbon::now()->addYear();
|
|
|
|
return new Carbon(request()->escala['fim']) > $maxDate;
|
|
}
|
|
|
|
private function isEscalaTipoUnica()
|
|
{
|
|
return request()->escala['tipo_id'] === TipoEscala::UNICA;
|
|
}
|
|
|
|
private function isFimGreaterThan24HoursFromInicio()
|
|
{
|
|
$dateAfterInicio = (new Carbon(request()->escala['inicio']))->addDay();
|
|
|
|
return new Carbon(request()->escala['fim']) > $dateAfterInicio;
|
|
}
|
|
|
|
private function isEscalaTipoFixa()
|
|
{
|
|
return request()->escala['tipo_id'] === TipoEscala::FIXA;
|
|
}
|
|
|
|
private function validateDiasSemana()
|
|
{
|
|
if ($this->isJornada12Hours()) {
|
|
|
|
$this->validateDiasSemanaToJornada12Hours();
|
|
}
|
|
else if ($this->isJornada24Hours()) {
|
|
|
|
$this->validateDiasSemanaToJornada24Hours();
|
|
}
|
|
}
|
|
|
|
private function isJornada12Hours()
|
|
{
|
|
return request()->escala['jornada_em_horas'] === 12;
|
|
}
|
|
|
|
private function validateDiasSemanaToJornada12Hours()
|
|
{
|
|
$errors = [];
|
|
|
|
if ($this->hasNotAllowedDiasSemanaInDiasSemana($this->getNotAllowedDiasSemanaToJornada12Hours())) {
|
|
|
|
$errors[] = 'Se a jornada for de 12 horas, então deverá ter um intervalo de 1 dia '
|
|
. 'anterior e 1 dia posterior entre os dias da semana.';
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
|
|
$this->businessRulesErrors['escala.dias_semana.*'] = $errors;
|
|
}
|
|
}
|
|
|
|
private function getNotAllowedDiasSemanaToJornada12Hours()
|
|
{
|
|
$notAllowedDiasSemana = [];
|
|
|
|
foreach (request()->escala['dias_semana'] as $dia) {
|
|
|
|
array_push($notAllowedDiasSemana, WeekCalc::sub($dia, 1), WeekCalc::sum($dia, 1));
|
|
}
|
|
|
|
return $notAllowedDiasSemana;
|
|
}
|
|
|
|
private function isJornada24Hours()
|
|
{
|
|
return request()->escala['jornada_em_horas'] === 24;
|
|
}
|
|
|
|
private function validateDiasSemanaToJornada24Hours()
|
|
{
|
|
$errors = [];
|
|
|
|
if ($this->hasNotAllowedDiasSemanaInDiasSemana($this->getNotAllowedDiasSemanaToJornada24Hours())) {
|
|
|
|
$errors[] = 'Se a jornada for de 24 horas, então deverá ter um intervalo de 2 dias '
|
|
. 'anteriores e 2 dias posteriores entre os dias da semana.';
|
|
}
|
|
|
|
if (!empty($errors)) {
|
|
|
|
$this->businessRulesErrors['escala.dias_semana.*'] = $errors;
|
|
}
|
|
}
|
|
|
|
private function hasNotAllowedDiasSemanaInDiasSemana($notAllowedDiasSemana)
|
|
{
|
|
foreach (request()->escala['dias_semana'] as $dia) {
|
|
|
|
if (in_array($dia, $notAllowedDiasSemana)) {
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private function getNotAllowedDiasSemanaToJornada24Hours()
|
|
{
|
|
$notAllowedDiasSemana = [];
|
|
|
|
foreach (request()->escala['dias_semana'] as $dia) {
|
|
|
|
array_push(
|
|
$notAllowedDiasSemana,
|
|
WeekCalc::sub($dia, 1),
|
|
WeekCalc::sub($dia, 2),
|
|
WeekCalc::sum($dia, 1),
|
|
WeekCalc::sum($dia, 2)
|
|
);
|
|
}
|
|
|
|
return $notAllowedDiasSemana;
|
|
}
|
|
|
|
private function hasBusinessRulesErrors()
|
|
{
|
|
return !empty($this->businessRulesErrors);
|
|
}
|
|
|
|
private function validateTimeEscala($lotacaoId, $inicio, $fim, $currentPlantaoId = null)
|
|
{
|
|
$usuarioId = Lotacao::findOrFail($lotacaoId)->usuario_id;
|
|
|
|
if ($this->isConflictingEscala($usuarioId, $inicio, $fim, $currentPlantaoId)) {
|
|
|
|
throw new ConflictingPlantaoException;
|
|
}
|
|
}
|
|
|
|
private function isConflictingEscala($usuarioId, $inicio, $fim, $currentPlantaoId = null)
|
|
{
|
|
return Plantao::whereHas('lotacao', function ($lotacao) use ($usuarioId) {
|
|
|
|
$lotacao->where('usuario_id', $usuarioId);
|
|
})->when($currentPlantaoId, function ($query, $id) {
|
|
|
|
$query->where('id', '<>', $id);
|
|
})->where(function ($plantao) use ($inicio, $fim) {
|
|
|
|
$plantao
|
|
->where(function ($plantao) use ($inicio) {
|
|
|
|
$plantao
|
|
->where('inicio', '<=', $inicio)
|
|
->where('fim', '>=', $inicio);
|
|
})
|
|
->orWhere(function ($plantao) use ($fim) {
|
|
|
|
$plantao
|
|
->where('inicio', '<=', $fim)
|
|
->where('fim', '>=', $fim);
|
|
})
|
|
->orWhere(function ($plantao) use ($inicio, $fim) {
|
|
|
|
$plantao
|
|
->where('inicio', '>=', $inicio)
|
|
->where('inicio', '<=', $fim);
|
|
})
|
|
->orWhere(function ($plantao) use ($inicio, $fim) {
|
|
|
|
$plantao
|
|
->where('fim', '>=', $inicio)
|
|
->where('fim', '<=', $fim);
|
|
});
|
|
})->exists();
|
|
}
|
|
|
|
private function verificaConflitoTempoAdicionalPlantao($lotacaoId, $inicio)
|
|
{
|
|
$parametrizacao = Parametrizacao::first();
|
|
|
|
if (!is_null($parametrizacao) && $parametrizacao->tempo_adicional_plantao > 0) {
|
|
$plantaoComTempoAdicionalConflitante = Plantao::where('lotacao_id', $lotacaoId)
|
|
->whereDate('fim', $inicio->format('Y-m-d'))
|
|
->where('fim', '>=', $inicio->subMinutes($parametrizacao->tempo_adicional_plantao ?? 0)->format('Y-m-d H:i'))
|
|
->exists();
|
|
|
|
if ($plantaoComTempoAdicionalConflitante) {
|
|
throw new PlantaoComTempoAdicionalConflitanteException();
|
|
}
|
|
}
|
|
}
|
|
}
|