* * Este programa é software livre; você pode redistribuí-lo e/ou modificá-lo * sob os termos da Licença Pública Geral GNU conforme publicada pela Free * Software Foundation; tanto a versão 2 da Licença, como (a seu critério) * qualquer versão posterior. * * Este programa é distribuí­do na expectativa de que seja útil, porém, SEM * NENHUMA GARANTIA; nem mesmo a garantia implí­cita de COMERCIABILIDADE OU * ADEQUAÇÃO A UMA FINALIDADE ESPECÍFICA. Consulte a Licença Pública Geral * do GNU para mais detalhes. * * Você deve ter recebido uma cópia da Licença Pública Geral do GNU junto * com este programa; se não, escreva para a Free Software Foundation, Inc., no * endereço 59 Temple Street, Suite 330, Boston, MA 02111-1307 USA. * * @author Lucas D'Avila * @category i-Educar * @license @@license@@ * @package Biblioteca * @subpackage Modules * @since Arquivo disponível desde a versão ? * @version $Id$ */ require_once 'lib/Portabilis/Controller/ApiCoreController.php'; require_once 'include/pmieducar/clsPmieducarExemplar.inc.php'; require_once 'include/pmieducar/clsPmieducarBibliotecaDia.inc.php'; require_once 'include/pmieducar/clsPmieducarBibliotecaFeriados.inc.php'; require_once 'lib/Portabilis/Array/Utils.php'; class EmprestimoApiController extends ApiCoreController { protected $_nivelAcessoOption = App_Model_NivelAcesso::SOMENTE_BIBLIOTECA; // validadores regras negócio protected function validatesExistenceOfExemplar() { $valid = true; $exemplares = $this->loadExemplar($reload = true); if (! is_array($exemplares) || count($exemplares) < 1) { $id = $this->getRequest()->exemplar_id; $tombo = $this->getRequest()->tombo_exemplar; $this->messenger->append("Aparentemente não existe um exemplar com id $id e/ou tombo $tombo, para a biblioteca informada."); $valid = false; } return $valid; } protected function validatesExistenceOfCliente() { $valid = true; if (! $this->loadCliente()) { $this->messenger->append("Não existe um cliente com id '{$this->getRequest()->cliente_id}'."); $valid = false; } return $valid; } protected function validatesClienteIsNotSuspenso() { $cliente = $this->loadCliente(); if($cliente['suspenso']) { $this->messenger->append("Operação não pode ser realizada, pois o cliente esta suspenso.", 'error'); return false; } return true; } protected function validatesSituacaoExemplarIsIn($expectedSituacoes) { if (! is_array($expectedSituacoes)) $expectedSituacoes = array($expectedSituacoes); $situacao = $this->getSituacaoExemplar(); $situacao = $situacao['flag']; $msg = "Operação não realizada, pois a situação atual do exemplar é $situacao quando deveria ser " . implode(' ou ', $expectedSituacoes) . "."; return $this->validator->validatesValueInSetOf($situacao, $expectedSituacoes, 'situação', false, $msg); } protected function canAcceptRequest() { return parent::canAcceptRequest() && $this->validatesPresenceOf(array('instituicao_id', 'escola_id', 'biblioteca_id', 'cliente_id', 'tombo_exemplar')) && $this->validatesIsNumeric('tombo_exemplar') && $this->validatesExistenceOfExemplar() && $this->validatesExistenceOfCliente(); } protected function canPostEmprestimo() { return $this->validatesPresenceOf(array('exemplar_id')) && $this->validatesExistenceOfExemplar() && $this->validatesClienteIsNotSuspenso() && $this->validatesSituacaoExemplarIsIn('disponivel'); /* #TODO validar: qtd emprestimos em aberto do cliente <= limite biblioteca valor R$ multas em aberto do cliente <= limite biblioteca não existe outro exemplar mesma obra emprestado para cliente validates situacao exemplar is disponivel or is reservado cliente */ } protected function canPostDevolucao() { return $this->validatesPresenceOf(array('exemplar_id')) && $this->validatesExistenceOfExemplar() && $this->validatesSituacaoExemplarIsIn(array('emprestado', 'emprestado_e_reservado')); } /* metódos auxiliares resposta operação / recurso metódos iniciados com load consultam informação no banco de dados metódos iniciados com get consultam informação em objetos */ protected function loadCliente($id = null) { if (! $id) $id = $this->getRequest()->cliente_id; // load cliente $cliente = new clsPmieducarCliente($id); $cliente = $cliente->detalhe(); if ($cliente) { $cliente = Portabilis_Array_Utils::filter($cliente, array('cod_cliente' => 'id', 'ref_idpes' => 'pessoa_id')); // load pessoa $pessoa = new clsPessoa_($cliente['pessoa_id']); $pessoa = $pessoa->detalhe(); $cliente['nome'] = $this->toUtf8($pessoa["nome"]); // load suspensao $sql = "select 1 from pmieducar.cliente_suspensao where ref_cod_cliente = $1 and data_liberacao is null and data_suspensao + (dias||' day')::interval >= now()"; $suspenso = $this->fetchPreparedQuery($sql, $params = array($id), true, 'first-field'); $cliente['suspenso'] = $suspenso == '1'; } return $cliente; } protected function loadQtdDiasEmprestimoForExemplar($exemplar = null) { $acervo = $this->loadAcervo($exemplar['acervo']['id']); $exemplarTipoId = $acervo['exemplar_tipo_id']; // obtem id tipo de cliente $clienteTipoCliente = new clsPmieducarClienteTipoCliente(); $clienteTipoCliente = $clienteTipoCliente->lista(null, $this->getRequest()->cliente_id, null, null, null, null, null, null, $this->getRequest()->biblioteca_id); $clienteTipoId = $clienteTipoCliente[0]['ref_cod_cliente_tipo']; // obtem quantidade dias emprestimo $clienteTipoExemplarTipo = new clsPmieducarClienteTipoExemplarTipo($clienteTipoId, $exemplarTipoId); $clienteTipoExemplarTipo = $clienteTipoExemplarTipo->detalhe(); if (! $clienteTipoExemplarTipo || ! is_numeric($clienteTipoExemplarTipo["dias_emprestimo"])) throw new CoreExt_Exception("Aparentemente não foi definido a quantidade de dias de emprestimo para o tipo de cliente '$clienteTipoId' e tipo de exemplar '$exemplarTipoId'."); return $clienteTipoExemplarTipo["dias_emprestimo"]; } protected function getDataPrevistaDisponivelForExemplar($exemplar, $dataInicio, $format = 'd/m/Y') { $qtdDiasEmprestimo = $this->loadQtdDiasEmprestimoForExemplar($exemplar); // reformada data dd/mm/aaaa => mm/dd/aaaa $_format = explode('/', $format); if (count($_format) > 0 && $_format[0] == 'd') { list($diaInicio, $mesInicio, $anoInicio) = explode("/", $dataInicio); $dataInicio = "$mesInicio/$diaInicio/$anoInicio"; } // soma dias emprestimo $date = date('Y-m-d', strtotime("+$qtdDiasEmprestimo days", strtotime($dataInicio))); // #TODO Caso seja a devolução seja refatorada, separar esse trecho num método para reutilizar código $dias_da_semana = array( 'Sun' => 1, 'Mon' => 2, 'Tue' => 3, 'Wed' => 4, 'Thu' => 5, 'Fri' => 6, 'Sat' => 7 ); $obj_biblioteca_dia = new clsPmieducarBibliotecaDia(); $lst_biblioteca_dia = $obj_biblioteca_dia->lista($this->getRequest()->biblioteca_id); if( is_array( $lst_biblioteca_dia ) && count( $lst_biblioteca_dia ) ) { foreach ($lst_biblioteca_dia AS $dia_semana) { // dias de funcionamento da biblioteca $biblioteca_dias_semana[] = $dia_semana["dia"]; } } // Array de dias de não funcionamento $biblioteca_dias_folga = array_diff($dias_da_semana, $biblioteca_dias_semana); // inverte as relacoes entre chaves e valores ( de $variavel["Sun"] => 1, para $variavel[1] => "Sun") $biblioteca_dias_folga = array_flip($biblioteca_dias_folga); $obj_biblioteca_feriado = new clsPmieducarBibliotecaFeriados(); $lst_biblioteca_feriado = $obj_biblioteca_feriado->lista( null, $this->getRequest()->biblioteca_id ); if( is_array( $lst_biblioteca_feriado ) && count( $lst_biblioteca_feriado ) ) { foreach ($lst_biblioteca_feriado AS $dia_feriado) { // dias de feriado da biblioteca $biblioteca_dias_feriado[] = dataFromPgToBr($dia_feriado["data_feriado"], "D Y-m-d"); } } $data_entrega = dataFromPgToBr($date, "D Y-m-d"); if(!is_array($biblioteca_dias_folga)) { $biblioteca_dias_folga = array(null); } if(!is_array($biblioteca_dias_feriado)) { $biblioteca_dias_feriado = array(null); } // verifica se a data cai em algum dia que a biblioteca n funciona while( in_array(substr($data_entrega,0,3), $biblioteca_dias_folga) || in_array($data_entrega, $biblioteca_dias_feriado) ) { $data_entrega = date("D Y-m-d ",strtotime("$data_entrega +1 day")); $data_entrega = dataFromPgToBr($data_entrega, "D Y-m-d"); } $data_entrega = dataFromPgToBr($data_entrega, $format); return $data_entrega; } protected function loadReservasForExemplar($exemplar, $clienteId = null, $reload = false) { if ($reload || ! isset($this->_reservas)) { $reservas = new clsPmieducarReservas(); $reservas = $reservas->lista(null, null, null, $clienteId, null, null, null, null, null, null, $exemplar['id'], 1, $this->getRequest()->biblioteca_id, $this->getRequest()->instituicao_id, $this->getRequest()->escola_id, $data_retirada_null = true); if($reservas) { $reservas = Portabilis_Array_Utils::filterSet($reservas, array('cod_reserva' => 'id', 'data_reserva' => 'data', 'ref_cod_cliente' => 'cliente_id', 'data_prevista_disponivel')); // adicionada informaçoes adicionais a cada reserva foreach($reservas as $index => $reserva) { $cliente = $this->loadCliente($reserva["cliente_id"]); $reserva['cliente'] = $cliente; $reserva['nome_cliente'] = $cliente['id'] . ' - ' . $cliente['nome']; $reserva['data'] = date('d/m/Y', strtotime($reserva['data'])); $reserva['situacao'] = $this->getSituacaoForFlag('reservado'); /* para o cliente da reserva: considera a data prevista disponivel gravada na reserva. para outros considera a data prevista disponivel da reserva + a quantidade de dias de emprestimo do exemplar */ if ($this->getRequest()->cliente_id == $cliente['id']) $reserva['data_prevista_disponivel'] = date('d/m/Y', strtotime($reserva['data_prevista_disponivel'])); else $reserva['data_prevista_disponivel'] = $this->getDataPrevistaDisponivelForExemplar($exemplar, $reserva['data_prevista_disponivel'], 'd/m/Y'); } //fim for each } $this->_reservas = $reservas; } return $this->_reservas; } protected function loadEmprestimoForExemplar($exemplar = null) { if(is_null($exemplar)) $exemplar = $this->loadExemplar(); $emprestimo = new clsPmieducarExemplarEmprestimo(); $emprestimo = $emprestimo->lista(null, null, null, null, $exemplar['id'], null, null, null, null, null, $devolvido = false, $this->getRequest()->biblioteca_id, null, $this->getRequest()->instituicao_id, $this->getRequest()->escola_id); if($emprestimo) { $emprestimo = array_shift($emprestimo); $emprestimo = Portabilis_Array_Utils::filter($emprestimo, array('cod_emprestimo' => 'id', 'data_retirada' => 'data', 'ref_cod_cliente' => 'cliente_id')); // adiciona informações adicionais ao emprestimo $cliente = $this->loadCliente($emprestimo["cliente_id"]); $emprestimo['cliente'] = $cliente; $emprestimo['nome_cliente'] = $cliente['id'] . ' - ' . $cliente['nome']; $emprestimo['situacao'] = $this->getSituacaoForFlag('emprestado'); $emprestimo['data'] = date('d/m/Y', strtotime($emprestimo['data'])); $emprestimo['data_prevista_disponivel'] = $this->getDataPrevistaDisponivelForExemplar($exemplar, $emprestimo['data'], 'd/m/Y'); } return $emprestimo; } protected function existsReservaForExemplar($exemplar = null, $clienteId = null) { $reservas = $this->loadReservasForExemplar($exemplar, $clienteId, $reload = true); return is_array($reservas) && count($reservas) > 0; } protected function getSituacaoForFlag($flag) { $situacoes = array( 'indisponivel' => array('flag' => 'indisponivel', 'label' => 'Indisponível'), 'disponivel' => array('flag' => 'disponivel' , 'label' => 'Disponível' ), 'emprestado' => array('flag' => 'emprestado' , 'label' => 'Emprestado' ), 'reservado' => array('flag' => 'reservado' , 'label' => 'Reservado' ), 'emprestado_e_reservado' => array('flag' => 'emprestado_e_reservado', 'label' => 'Emprestado e reservado' ), 'invalida' => array('flag' => 'invalida' , 'label' => 'Inválida' ) ); return $situacoes[$flag]; } protected function loadSituacaoForExemplar($exemplar) { $situacao = new clsPmieducarSituacao($exemplar["situacao_id"]); $situacao = $situacao->detalhe(); $reservado = $this->existsReservaForExemplar($exemplar); $emprestado = $situacao["situacao_emprestada"] == 1; $situacaoPermiteEmprestimo = $situacao["permite_emprestimo"] == 2; $exemplarPermiteEmprestimo = $exemplar["permite_emprestimo"] == 2; if ($emprestado && $reservado) $flagSituacaoExemplar = 'emprestado_e_reservado'; elseif ($emprestado) $flagSituacaoExemplar = 'emprestado'; elseif ($reservado) $flagSituacaoExemplar = 'reservado'; elseif ($situacaoPermiteEmprestimo && $exemplarPermiteEmprestimo) $flagSituacaoExemplar = 'disponivel'; elseif (! $situacaoPermiteEmprestimo || ! $exemplarPermiteEmprestimo) $flagSituacaoExemplar = 'indisponivel'; else $flagSituacaoExemplar = 'invalida'; return $this->getSituacaoForFlag($flagSituacaoExemplar); } protected function getSituacaoExemplar($exemplar = null) { if (is_null($exemplar)) $exemplar = $this->loadExemplar(); if ($exemplar['situacao']['flag'] == 'reservado') $exemplar['situacao']['flag'] = $this->validateReservaOfExemplar($exemplar); return $exemplar['situacao']; } // Verifica se há reservas para o exemplar // Efetua retirada da reserva caso seja para o cliente em questão protected function validateReservaOfExemplar($exemplar = null){ if (is_null($exemplar)) $exemplar = $this->loadExemplar(); $reservas = $this->loadReservasForExemplar($exemplar); $cont = 0; $clientePossuiReserva = false; $codReserva = 0; if (is_array($reservas) && count($reservas)){ foreach ($reservas as $registro) { $cont; if ($registro['cliente_id'] == $this->getRequest()->cliente_id){ $clientePossuiReserva = true; $codReserva = $registro['id']; break; } } } if ($clientePossuiReserva){ if ($cont==1){ $reservas = new clsPmieducarReservas($codReserva); $reservas->data_retirada = date('Y-m-d H:i:s'); $reservas->edita(); $return = 'disponivel'; }else{ $this->messenger->append("Outros clientes já haviam reservado o exemplar anteriormente.".$cont, 'success'); $return = 'reservado'; } }else if($cont>0){ $this->messenger->append("Outros clientes já haviam reservado o exemplar.", 'success'); $return = 'reservado'; } return $return; } protected function getPendenciasForExemplar($exemplar) { if (! isset($exemplar['situacao'])) throw new CoreExt_Exception("Exemplar deve possuir uma chave 'situacao' para getPendenciasForExemplar."); $situacaoExemplar = $exemplar['situacao']; $pendencias = array(); // get emprestimo if (strpos($situacaoExemplar['flag'], 'emprestado') > -1) { $emprestimo = $this->loadEmprestimoForExemplar($exemplar); if($emprestimo != false) $pendencias[] = $emprestimo; } // get reservas if (strpos($situacaoExemplar['flag'], 'reservado') > -1) { $reservas = $this->loadReservasForExemplar($exemplar); if ($reservas != false) $pendencias = array_merge($pendencias, $reservas); } return $pendencias; } protected function loadAcervo($id = '', $reload = false) { if (empty($id)) $id = $this->getRequest()->acervo_id; if ($reload || ! isset($this->_acervos)) $this->_acervos = array(); if (! isset($this->_acervos[$id])) { $acervo = new clsPmieducarAcervo($id); $acervo = $acervo->detalhe(); if ($acervo) { $acervo = Portabilis_Array_Utils::filter($acervo, array('cod_acervo' => 'id', 'ref_cod_exemplar_tipo' => 'exemplar_tipo_id', 'ref_cod_acervo' => 'acervo_referencia_id', 'ref_cod_acervo_colecao' => 'colecao_id', 'ref_cod_acervo_idioma' => 'idioma_id', 'ref_cod_acervo_editora' => 'editora_id', 'ref_cod_biblioteca' => 'biblioteca_id', 'titulo', 'sub_titulo', 'cdu', 'cutter', 'volume', 'num_edicao', 'ano', 'num_paginas', 'isbn', 'data_cadastro')); } $this->_acervos[$id] = $acervo; } return $this->_acervos[$id]; } protected function loadExemplares($reload = false, $id = null) { if ($reload || ! isset($this->_exemplares)) { $exemplares = new clsPmieducarExemplar(); // filtra por acervo_id e/ou tombo_exemplar (caso tenha recebido tais parametros) $exemplares = $exemplares->lista($id, null, null, $this->getRequest()->acervo_id, null, null, null, null, null, null, null, null, null, 1, null, null, null, null, $this->getRequest()->biblioteca_id, null, $this->getRequest()->instituicao_id, $this->getRequest()->escola_id, $this->getRequest()->tombo_exemplar); if ($exemplares) { $exemplares = Portabilis_Array_Utils::filterSet($exemplares, array('cod_exemplar' => 'id', 'ref_cod_fonte' => 'fonte_id', 'ref_cod_motivo_baixa' => 'motivo_baixa_id', 'ref_cod_acervo' => 'acervo_id', 'ref_cod_biblioteca' => 'biblioteca_id', 'ref_cod_situacao' => 'situacao_id', 'permite_emprestimo', 'tombo')); // adiciona situacao e pendencias de cada exemplar foreach($exemplares as $index => $exemplar) { $acervo = $this->loadAcervo($exemplar['acervo_id']); $exemplares[$index]['acervo'] = array(); $exemplares[$index]['acervo']['id'] = $exemplar['acervo_id']; $exemplares[$index]['acervo']['titulo'] = $acervo['titulo']; $exemplares[$index]['acervo']['exemplar_tipo_id'] = $acervo['exemplar_tipo_id']; $exemplares[$index]['exemplar_tipo_id'] = $acervo['exemplar_tipo_id']; $exemplares[$index]['situacao'] = $this->loadSituacaoForExemplar($exemplares[$index]); $exemplares[$index]['pendencias'] = $this->getPendenciasForExemplar($exemplares[$index]); } } $this->_exemplares = $exemplares; } return $this->_exemplares; } protected function loadExemplar($reload = false, $id = null) { if (! $id) $id = $this->getRequest()->exemplar_id; return array_shift($this->loadExemplares($reload, $id)); } /* metódos resposta operação / recurso metódos nomeados no padrão operaçãoRecurso */ protected function getExemplares() { $this->appendResponse('exemplares', $this->loadExemplares($reload = true)); } protected function loadSituacaoExemplar($permiteEmprestimo = true, $padrao = true, $emprestada = false){ $permiteEmprestimo = $permiteEmprestimo == true ? 2 : 1; $emprestada = $emprestada == true ? 1 : 0; if (! is_null($padrao)) $padrao = $padrao == true ? 1 : 0; $situacao = new clsPmieducarSituacao(); $situacao = $situacao->lista(null, null, null, null, $permiteEmprestimo, null, $padrao, $emprestada, null, null, null, null, 1, $this->getRequest()->biblioteca_id, $this->getRequest()->instituicao_id, $this->getRequest()->escola_id); if ($situacao) { $situacao = Portabilis_Array_Utils::filter($situacao[0], array('cod_situacao' => 'id', 'ref_cod_biblioteca' => 'biblioteca_id', 'nm_situacao' => 'label', 'situacao_padrao' => 'padrao', 'situacao_emprestada' => 'emprestada', 'permite_emprestimo', 'descricao')); } return $situacao; } protected function updateSituacaoExemplar($newSituacao){ if (! $newSituacao) throw new CoreExt_Exception('$newSituacao não pode ser falso em updateSituacaoExemplar.'); $exemplar = new clsPmieducarExemplar(); $exemplar->cod_exemplar = $this->getRequest()->exemplar_id; $exemplar->ref_cod_acervo = $this->getRequest()->acervo_id; $exemplar->ref_cod_situacao = $newSituacao['id']; $exemplar->ref_usuario_exc = $this->getSession()->id_pessoa; return $exemplar->edita(); } protected function postEmprestimo() { if ($this->canPostEmprestimo()) { // altera situacao exemplar para emprestado $situacaoEmprestimo = $this->loadSituacaoExemplar($permiteEmprestimo = false, $padrao = null, $emprestada = true); if($situacaoEmprestimo && ! $this->updateSituacaoExemplar($situacaoEmprestimo)) $this->messenger->append("Aparentemente a situação do exemplar não foi alterada para emprestado.", 'error'); elseif(! $situacaoEmprestimo) $this->messenger->append("Não foi encontrado uma situação cadastrada para emprestimo.", 'error'); // grava emprestimo if(! $this->messenger->hasMsgWithType('error')) { $emprestimo = new clsPmieducarExemplarEmprestimo(); $emprestimo->ref_usuario_cad = $this->getSession()->id_pessoa; $emprestimo->ref_cod_cliente = $this->getRequest()->cliente_id; $emprestimo->ref_cod_exemplar = $this->getRequest()->exemplar_id; if ($emprestimo->cadastra()) $this->messenger->append("Emprestimo realizado com sucesso.", 'success'); else $this->messenger->append("Aparentemente o realizado não foi cadastrado, por favor, tente novamente.", 'error'); } } $this->appendResponse('exemplar', $this->loadExemplar($reload = true)); } protected function postDevolucao() { if ($this->canPostDevolucao()) { // altera situacao exemplar para disponivel $situacaoDisponivel = $this->loadSituacaoExemplar($permiteEmprestimo = true, $padrao = true, $emprestada = false); if($situacaoDisponivel && ! $this->updateSituacaoExemplar($situacaoDisponivel)) $this->messenger->append("Aparentemente a situação do exemplar não foi alterada para disponivel.", 'error'); elseif(! $situacaoDisponivel) $this->messenger->append("Não foi encontrado uma situação padrão cadastrada para exemplar disponivel.", 'error'); // grava emprestimo if(! $this->messenger->hasMsgWithType('error')) { $_emprestimo = $this->loadEmprestimoForExemplar(); $emprestimo = new clsPmieducarExemplarEmprestimo(); $emprestimo->cod_emprestimo = $_emprestimo['id']; $emprestimo->ref_usuario_devolucao = $this->getSession()->id_pessoa; $emprestimo->data_devolucao = date("Y-m-d"); // TODO calcular / setar valor multa (se) devolução atrasada? if ($emprestimo->edita()) $this->messenger->append("Devolução realizada com sucesso.", 'success'); else $this->messenger->append("Aparentemente a devolução não foi cadastrada, por favor, tente novamente.", 'error'); } } $this->appendResponse('exemplar', $this->loadExemplar($reload = true)); } public function Gerar() { if ($this->isRequestFor('get', 'exemplares')) $this->getExemplares(); elseif ($this->isRequestFor('post', 'emprestimo')) $this->postEmprestimo(); elseif ($this->isRequestFor('post', 'devolucao')) $this->postDevolucao(); else $this->notImplementedOperationError(); } }