A quem interessar possa...
Aqui na Prefeitura de São José dos Campos conseguimos integrar a botoeira http://paineleletronico.net/opiniao/ com o NovoSGA versão 1.5.1, coletando a opinião e associando corretamente à senha sendo atendida no guichê.
O desenvolvedor da botoeira (Ericson) é super atencioso e acessível, e o equipamento funcionou corretamente.
Desta forma, os órgãos públicos que usam o NovoSGA podem atender ao artigo 23 da Lei Federal 13460/2017 de Qualidade nos serviços da administração pública:
"Os órgãos e entidades públicos abrangidos por esta Lei deverão avaliar os serviços prestados, nos seguintes aspectos:
I - satisfação do usuário com o serviço prestado; [...].
§ 1º A avaliação será realizada por pesquisa de satisfação feita, no mínimo, a cada um ano, ou por qualquer outro meio que garanta significância estatística aos resultados."
http://www.planalto.gov.br/ccivil_03/_ato2015-2018/2017/lei/l13460.htm
O atendente deve solicitar que a pessoa faça a avaliação ANTES de encerrar o atendimento no sistema NovoSGA.
Se a pessoa concordar em avaliar, aguardar aparecer na tela mensagem da botoeira confirmando a gravação e só então encerrar o atendimento.
Se o atendimento for encerrado antes da avaliação, a opinião será gravada no banco de dados, mas não será associada à senha correta.
...... SEGUE O PASSO A PASSO ......
1) Criada tabela avaliacao_botoeira
2) Criado arquivo coletaropiniaobotoeira.php gravado em SGA/PUBLIC
3) Criada view_atendimentos_un_protocolo para uso no QLikview (BI com relatórios detalhados).
4) Criados usuários no banco de dados
botoeira - permissão de select na tabela atendimentos e de insert na tabela avaliacao_botoeira (usado no PHP)
protocolo - permissão de select na view_atendimentos_un_protocolo (usado no BI)
5) Instalado o programa da botoeira e conectada uma botoeira na porta USB do micro
6) Na configuração da botoeira, no campo URL, foi colocada a chamada ao PHP com a passagem dos dados coletados pela botoeira. Adaptar a URL para os dados do seu ambiente, altere o IPdoservidor (coloque o mesmo do NovoSGA 1.5.1 do seu ambiente), unidade e guichê.
http://IPdoservidor/sga/public/coletaropiniaobotoeira.php?dia=<dia>&mes=<mes>&ano=<ano>&hora=<hora>&minuto=<minuto>&segundo=<segundo>&operador=<operador>&opiniao=<opiniao>&servidor=IPdoservidor&unidade=1&guiche=1
7) Depois de tudo configurado, se ainda não tem a botoeira e quiser testar se o PHP e o banco de dados estão OK, em um browser acesse o link:
http://IPdoservidor/sga/public/coletaropiniaobotoeira.php?dia=1&mes=1&ano=1&hora=1&minuto=1&segundo=1&operador=1&opiniao=1&servidor=IPdoservidor&unidade=1&guiche=100
Se for apresentado o texto abaixo o NovoSGA e o banco de dados estão configurados corretamente.
SELECT a.id from atendimentos a where a.unidade_id=1 and a.num_local=100 and a.dt_fim is null
Senhas localizadas: 0
ID Senha: 0
insert into avaliacao_botoeira values ( null, '1-1-1 1:1:1','1', '1', 1, 100, 0, now() )
Atenção: sempre que este teste é feito, é gravado um registro na tabela avaliacao_botoeira
com data igual a '0001-01-01 01:01:01', unidade 1 e guichê = 100. Estes registros não
interferem nas avaliações das senhas reais e podem ser apagados.
-- criação da tabela para registrar as avaliações
-- um registro é criado pelo coletaropiniaobotoeira.php sempre que um botão da botoeira é acionado dentro do intervalo de tempo válido para a coleta
-- o registro é gravado mesmo que não seja localizada a senha correspondente
-- registros sem nº de senha indicam que:
-- atendente fechou o atendimento antes da pessoa fazer a avaliação OU
-- a URL na configuração da botoeira daquele micro está com Unidade ou Guichê errado
CREATE TABLE avaliacao_botoeira (
id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'Id da avaliação - sequencial',
data_avaliacao DATETIME NOT NULL COMMENT 'Data e hora da avaliação (enviado pela botoeira)',
usuario_avaliado VARCHAR(30) NOT NULL COMMENT 'Usuario de rede (enviado pela botoeira)',
resposta VARCHAR(10) NOT NULL COMMENT 'Avaliacao (enviado pela botoeira)',
unidade_id INT(11) NOT NULL COMMENT 'Código da unidade no SGA (fixo na URL da configuração da botoeira)',
num_local SMALLINT(6) NOT NULL COMMENT 'Número do guichê (fixo na URL da configuração da botoeira)',
atendimento_id BIGINT(20) NULL DEFAULT NULL COMMENT 'ID da senha avaliada, se = 0 atendente encerrou antes
da avaliação ou botoeira foi acionada sem atendimento.',
data_gravacao DATETIME NOT NULL COMMENT 'Data e hora da gravação no banco de dados, se for diferente da
data_avaliacao indica que há tráfego na rede',
PRIMARY KEY (id)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
-- criar usuário botoeira para acessar a tabela atendimentos e gravar dados na tabela avaliacao_botoeira
CREATE USER 'botoeira'@'%' IDENTIFIED BY 'SENHA';
-- direito de insert na tabela avaliacao_botoeira e de select na tabela atendimentos
GRANT insert ON sga.avaliacao_botoeira TO botoeira;
GRANT select ON sga.atendimentos TO botoeira;
FLUSH PRIVILEGES;
SHOW GRANTS FOR botoeira;
-- Código do arquivo coletaropiniaobotoeira.php - gravado na pasta /SGA/PUBLIC
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// conectar com banco de dados - usuário com acesso apenas às tabelas atendimentos e avaliacao_botoeira
$servidor = $GET['servidor'];
$banco = mysqli_connect($servidor, "botoeira", "SENHA", "sga");
if (!$banco) {
echo " Erro ao conectar ao MySQL. servidor = $servidor" . PHP_EOL;
echo " Número do Erro: " . mysqli_connect_errno() . PHP_EOL;
echo " Erro: " . mysqli_connect_error() . PHP_EOL;
exit;
}
// conectou corretamente com o banco de dados sga
// colocar parametros da URL em variáveis
$dia = $GET['dia'];
$mes = $GET['mes'];
$ano = $GET['ano'];
$hora = $GET['hora'];
$minuto = $GET['minuto'];
$segundo = $GET['segundo'];
$operador = $GET['operador'];
$opiniao = $GET['opiniao'];
$unidade = $GET['unidade'];
$guiche = $_GET['guiche'];
// montar SQL que procura o id da senha daquela unidade e guiche, na tabela atendimentos, com data fim vazia
$query_procura = "SELECT a.id from atendimentos a where a.unidade_id=$unidade and a.num_local=$guiche ";
$query_procura.= "and a.dt_fim is null ";
// executar a query e localizar o ID do atendimento para a unidade e guichê avaliados
$resposta = mysqli_query($banco,$query_procura);
$registro = mysqli_fetch_array($resposta);
$senhas_localizadas = mysqli_num_rows($resposta);
$id_senha = 0;
if ($senhas_localizadas > 0) { $id_senha = $registro['id']; }
echo " $query_procura ";
echo "<br> Senhas localizadas: " . $senhas_localizadas;
echo "<br> ID Senha: $id_senha <br>";
// montar SQL para incluir um registro na tabela avaliacao_botoeira
// campos $ano $mes $dia $hora $minuto $segundo $operador $opiniao $unidade $guiche foram recebidos na URL
// campo $id_senha é a identificação da senha sendo avaliada
// $id_senha é igual a zero quando não foi localizada senha em atendimento,
// isso ocorre se botoeira é acionada quando não tem nenhum atendimento sendo feito, por exemplo:
// - ao limpar a botoeira
// - atendente encerra o atendimento antes do cliente gravar a opinião
// se na configuração da botoeira os parâmetros 'Próxima coleta' e 'Temporização da leitura' não forem
// corretamente configurados, e o cliente apertar mais de um botão, pode acontecer de gravar mais de uma
// avaliação para a mesma senha
$query_grava = "insert into avaliacao_botoeira values ( null, ";
$query_grava.= "'$ano-$mes-$dia $hora:$minuto:$segundo',";
$query_grava.= "'$operador', '$opiniao', $unidade, $guiche," ;
$query_grava.= " $id_senha, now() )";
// incluir o registro no banco de dados
$resposta=mysqli_query($banco,$query_grava);
echo " <br> $query_grava";
mysqli_close($banco);
?>
-- Criar view para mostrar atendimentos junto com a avaliação
-- ajustar no final do código para colocar a unidade desejada (aqui na nossa instalação unidade = 1) e para a quantidade de dias que a view deve coletar (aqui coloquei os últimos 35 dias)
-- Se uma senha não teve avaliação os 3 últimos campos = NULL
-- Se uma senha foi avaliada mais de uma vez, são apresentadas todas as avaliações
CREATE VIEW sga.view_atendimentos_un_protocolo as
select a.unidade_id AS CodUnidade, un.nome AS Unidade,
a.id AS idSenha, a.atendimento_id AS idAnterior,
a.sigla_senha AS Letra, a.num_senha AS NumSenha,
p.nome AS Prioridade, a.num_local AS Guiche,
(case weekday(date_format(a.dt_cheg,'%Y/%m/%d'))
when 0 then '2a'
when 1 then '3a'
when 2 then '4a'
when 3 then '5a'
when 4 then '6a'
when 5 then 'Sab'
when 6 then 'Dom' end) AS Dia,
a.dt_cheg AS Chegada,
a.dt_cha AS Chamada,
a.dt_ini AS Inicio,
a.dt_fim AS Fim,
(case
when ((a.status = 6) or ((a.status = 1) and (timediff(now(),a.dt_cheg) > '24:00:00'))) then ''
when isnull(a.dt_cha) then timediff(now(),a.dt_cheg)
else timediff(a.dt_cha,a.dt_cheg) end) AS Espera,
(case when isnull(a.dt_ini)
then '' else timediff(a.dt_ini,a.dt_cha) end) AS Deslocamento,
(case when ((a.status = 6) or isnull(a.dt_ini))
then '' else timediff(a.dt_fim,a.dt_ini) end) AS Atendimento,
(case when ((a.status = 6) or isnull(a.dt_ini))
then '' else timediff(a.dt_fim,a.dt_cheg) end) AS TempoTotal,
a.status AS CodigoStatus,
(case
when (a.status = 1) then 'Senha emitida/Aguardando chamar'
when (a.status = 2) then 'Chamado pela mesa'
when (a.status = 3) then 'Atendimento iniciado'
when (a.status = 4) then 'Atendimento encerrado'
when (a.status = 5) then 'Não compareceu'
when (a.status = 6) then 'Senha cancelada'
when (a.status = 7) then 'Erro triagem'
when (a.status = 8) then 'Atendimento encerrado e codificado'
else 'Erro' end) AS Status,
a.nm_cli AS Cliente, a.ident_cli AS Documento,
s.nome AS Serviço Triagem, sa.nome AS ServicoAtendido,
concat(u.nome,' ', u.sobrenome) AS AtendidoPor,
concat(ut.nome, ' ', ut.sobrenome) AS TriadoPor,
u.login AS CPFatendente, ut.login AS CPFtriagem,
bo.usuario_avaliado AS LoginRede,
bo.data_avaliacao AS DataAvaliacao,
bo.resposta AS Avaliacao
from ((((((((view_historico_atendimentos a
left join historico_atend_codif ha on((a.id = ha.atendimento_id)))
left join usuarios u on((a.usuario_id = u.id)))
left join usuarios ut on((a.usuario_tri_id = ut.id)))
left join prioridades p on((a.prioridade_id = p.id)))
left join servicos s on((a.servico_id = s.id)))
left join unidades un on((a.unidade_id = un.id)))
left join servicos sa on((ha.servico_id = sa.id)))
left join avaliacao_botoeira bo on((a.id = bo.atendimento_id)))
where ((a.unidade_id = 1)
and (a.dt_cheg >= (curdate() - interval 35 day)));