=========
`xMova Android `_
=========
---------------
MODEL
---------------
O xMova interpreta o modelo de dados para criar as telas do fluxo. No modelo define-se todas as entidades
e seus campos. Em cada entidade e campo pode-se definir atributos e eventos.
Formato
=======
O modelo é definido da seguinte forma::
Apontamento sync=in|out|beforeInstall
id inc
idSeq long uuid
data Now
campo1 int
campo2 String
events
beforeInsert
log Evento que ocorre antes de inserir um registro.
beforeSync
log Não sincroniza se retornar 0.
fieldEvents
onValidate
campo1
//Permite prosseguir apenas se o valor inserido for maior que zero.
return campo1 > 0
crudActions
MostrarResumo
show TelaResumoApontamento
Tipos de Campo
==============
* ``Batterylevel``
* ``Binary``
* ``Boolean | Bool``
* ``Bytes``
* ``Date``
* ``Decimal``
* ``Double``
* ``Entity``
* ``Float``
* ``inc``
* ``Integer | int``
* ``List``
* ``Location``
* ``Long``
* ``Now``
* ``ReceivedFile [nome pode ser alterado]``
* ``String | Str``
* ``Text``
Atributos de Entidades
======================
* ``bluetoothKeepRecordsWhenNewRecordsIsEmpty``: Usado quando atualiza dados via bluetooth. Caso a lista de dados enviada esteja vazia, mantém os dados existentes no mobile.
* ``cleanupDays``: Apaga a entidade após passado a quantidade de dias configurado no cleanupDays. Antes de apagar, verifica se existe algum fixedPoint, só realizar o procedimento de apagar caso não exista entidade em uso.
* ``confirm``: Mostra a tela de confirmação antes da criação ou finalização da entidade. (ex.: confirm=Create|Finish)
* ``delete``: Permite que o usuário delete dinamicamente um registro da entidade.
* ``descriptionFields``: Quando for exibido em uma lista, define o que vai aparecer em cada elemento.
* ``emptyVerify``: Antes de iniciar o preechimento do fluxo, verifica se a entidade sync=in está vazia. Se configurado como emptyVerify=true, não permite prosseguir se estiver vazia. (ex.: emptyVerify=true ou emptyVerify=false)
* ``favorite``: Marca os ultimos registros selecionados com a cor amarela e adiciona no topo da listagem (permite até 3 itens).
* ``insert``: Permite que o usuário insira dinamicamente um registro na entidade.
* ``insert`` - ``insertFields``: Definição dos campos que serão pedidos na insersão de um registro.
* ``insert`` - ``insertFieldNotFillId``: Nesse caso é necessário o preenchimento manual do id por parte do programador.
* ``memory``: Usado em entidades (in e out) para indicar que elas serão mantidas em memória para que as leituras sejam rápidas. (veja :ref:`Entidade em Memória `)
* ``messageScheduled``: Usado para agendar a visualização de um texto para a hora pré-definida. (veja :ref:`Mensageria `)
* ``noFinishAction``: Retira a opção do crud que finaliza a entidade.
* ``noSyncAction``: Retira a opção do crud que sincroniza os dados.
* ``notSavedMessage``: Não mostra "salvo com sucesso" após salvar o inicio de uma entidade.
* ``openFinish``: Preenche o campo mobStatus (0 :aberto | 1:fechado)
* ``recursive``: Usado em entidades que se auto referenciam.
* ``SyncBackgroundOnFinishRecord`` Deve ser utilizado na entidade Boletim. Faz com que o sincronismo seja chamado em background ao finalizar a entidade.
**Exemplo**::
Entidade1 recursive
id int
name Str
idParent Entidade1
* ``searchFields``: Define os campos que podem ser usados na busca dos registros da entidade.
* ``sync``: Define o tipo de sincronismo da entidade. (veja :ref:`Tipo de Sincronismo da Entidade `)
Atributos de Campos
===================
* ``autoFill``: Adiciona o valor pré-definido ao campo. Não pede o preechimento do campo para o usuário.
* ``acceptEmpty``: Permite que o usuario passe para o próximo campo sem informar um valor.
* ``defaultValue``: Valor pré-definido para um campo caso seu retorno seja nulo.
* ``externalName``: Define como nome do campo que será enviado para o servidor.
* ``fill=Finish``: Adicionado ao campo para que ele seja preenchido somente no fim do apontamento.
* ``fillCondition``: Verifica se o campo deve ser preenchido. Se retornado false, permite que o usuario passe para o próximo campo sem informar um valor.
* ``fillConfirm``: Indica que antes de um campo ser preenchido, sera pergutado ao usuario se deseja preencher o campo.
* ``fixedPoint``: Indica que o aplicativo deve retornar o campo com o fixedPoint quando reiniciado, caso o field seja acessado no preechimento.
* ``getInputScreenLabel``: Alteração para mudar titulo da tela.
* ``getInputTopMessageLabel``: Alteração para mudar a mensagem que é apresentada entre o título e o primeiro item da lista.
* ``hide``: Oculta um campo e seu valor na tela de detalhe de um elemento da lista.
* ``ignoreExternal``: Retira o campo do registro enviado para o servidor.
* ``maxLength``: Usado para limitar o tamanho de um campo.
* ``notBack``: Usado em campos que pedem informações ao usuário para indicar que o usuário não poderá voltar para o campo anterior.
* ``notFill``: Indica que não deve solicitar ao usuário que preencha esse campo
* ``notSync``: Usado em uma entidade sync=in para manter o valor gravado no mobile, mesmo que o registro seja atualizado com o sincronismo.
* ``onGetDefaultInputValue``: Pré-preenche o valor de um campo, para mostrar ao usuário. Permite a alteração do valor.
* ``onlineValidate``: Recebe uma string como parâmetro (nome de um método), a validação é feita web. A web deve enviar todos os campos já preenchidos pelo mobile, além dos campos de retorno. (ex.: onlineValidate=validaLider) (veja :ref:`Validação On-Line `)
* ``onlineValidate`` - ``clearOnValidationFail``: Reinicia o processo de preenchimento e reseta os valores quando o valor do campo não passa na validação.
* ``onlineValidate`` - ``continueOnError``: Prossegue com o fluxo quando a validação retornar erro.
* ``onlineValidate`` - ``continueOnFail``: Prossegui com o fluxo quando a validação falhar.
* ``onlineValidate`` - ``goToFieldOnValidateStatus``: Tem a propriedade para pular de campo quando ocorrer um status na validacao online do campo (ex.: onlineValidate=validaLider, goToFieldOnValidateStatus:1,codigoLider).
* ``reader``: [reader=cam|nfc|bt] Abre a camera do aparelho. Utilizado para leitura de códigos.
* ``uuid``: Indica que o campo sera preenchido automaticamente por um uuid long ou alfanumerico (ex.: G9x5I.YD:df98W), contemplando os ids do auth, timemillis, etc
* ``mask``: Permite adicionar uma máscara a um campo de entrada. A máscara permite caracteres numéricos, alfanuméricos, todos caracteres e símbolos especiais. Para utilizar caracteres especiais, precisamos na string que determina a máscara colocar o caractere de scape seguido do símbolo especial, por exemplo \9. Os símbolos especiais da máscara são: 9 (dígito), A (alfa caractere), * (Dígito ou Alfa caractere) e ? (Dígito, Alfa caractere ou símbolos especiais).
**Exemplo de uso da máscara**::
Boletim sync=out cleanupDays=20 notSavedMessage
id inc
idSeqBoletim uuid
mascaraCPF Long mask="999.999.999-99"
mascaraNumeral Long mask="9.9.9.9.9.9"
placaVeiculo Str mask="AAA-9999"
mascaraTelefoneCelular Str mask="(12)\99999-9999"
mascaraFicticia Str mask="99A*\?"
Binary
-----------------------
* ``Binary`` - ``draw``: Mostra tela para desenhar. Utilizado para campo de assinatura.
* ``Binary`` - ``picture``: Abre a camera do aparelho. Utilizado para tirar foto.
* ``Binary`` - ``audiorecord``: Mostra uma tela de gravação de som. Utilizado para gravar/reproduzir o som corrente. O formato é o 3gp (mais leve para transferência/armazenamento).
* ``Binary`` - ``picturemarker``: Permite ao usuário tirar uma foto e efetuar marcações sobre a mesma.
BluetoothFile
-----------------------
* ``Nome_da_Entidade`` - ``bluetoothFile``: Indica que este campo será recebido via bluetooth.
* ``Nome_da_Entidade`` - ``bluetoothFile`` - ``sendFields``: Usado para indicar quais campos da entidade, a qual o campo que tem o atributo 'bluetoothFile', devem ser enviados quando iniciar o recebimento dos arquivos via bluetooth. (Exemplo: Coletor bluetoothFile sendFields: id, name, data).
Boolean
-----------------------
* ``Boolean`` - ``notShowNo``: Mstra apenas o botão SIM e VOLTAR, não mostrar o botão NAO. Combinado com notBack nao mostra o botão voltar.
* ``Boolean`` - ``notShowYes``: Mostra apenas o botão NAO e VOLTAR, não mostrar o botão SIM. Combinado com NotShowNo nao mostra apenas o botao voltar.
Date
-----------------------
* ``Date`` - ``onlydate``: Pede apenas a data.
* ``Date`` - ``onlytime``: Pede apenas a hora.
Decimal
-----------------------
* ``Decimal`` - ``decimalSize``: Define quantas casas decimais serão mostradas quando o número for formatado.
* ``Decimal`` - ``manualDecimal``: Usado para desabilitar a formatação automática de um campo do tipo decimal.
Entity
-----------------------
* ``add``: Permite preencher os campo da entidade, ao invés de mostrá-la como lista.
* ``autoFillWhenOneItem``: Se houver apenas um registro na lista (após o filtro), ignora o preenchimento do campo, e preenche o campo com este registro automaticamente.
* ``fullDescription``: Permite uma lista detalhada com uso do descriptionFields.
* ``ignoreWhenListIsEmpty``: Quando a lista de escolha do RecordSelector estiver vazia, ignora o preenchimento do campo.
* ``inUpper``: Indica que o campo devera ser convertido para uppercase antes de apresentá-lo
* ``transient``: Não deve ser incluido na serialização do objeto
List
-----------------------
* ``loop``: Indica que uma vez iniciado o primeiro registro, deve continuar inserindo mais automaticamente.
* ``loop`` - ``autoInitializeNew``: Indica que a inserção de registros na lista deve ser iniciada automaticamente.
* ``loop`` - ``autoInitializeNew`` - ``finishOnEndLoop``: Finaliza a entidade que está em loop automaticamente, quando terminar o preenchimento.
* ``getManyRecords``: Retorna os registros de uma entidade. Faz com que a entidade seja preenchida uma vez para cada registro retornado. Este valor retornado é atribuído a um campo do mesmo tipo na entidade a ser preenchida.
* ``inlineData``: Para entidades sync=out, faz com que os valores preenchidos em outra entidade seja atribuído ao campo e enviado junto com a entidade para o servidor.
* ``notRequired``: Usado para verificar se o campo list não precisa ter algum valor selecionado para prosseguir o fluxo.
* ``notUseAsFilter``: Indica que o campo não deve ser usado como filtro quando estiver selecionando uma lista que refencia este campo.
* ``useAsFilter``: Indica que o campo deve ser usado como filtro quando estiver selecionando um item na lista, mesmo que a entidade do campo não seja SyncIn.
* ``viewAsColorIcon``: Apresenta um icone colorido para cada registro na lista.
* ``viewAsColorIcon`` - ``disableContinueButtonOnColorIcon``: Não mostra o botão Continuar quando utilizar a cor do icones (default habilitada).
* ``viewAsColorIcon`` - ``disableColorIcon``: Desabilita icone colorido na lista (default habilitada).
* ``viewAsColorIcon`` - ``enableColorIcon``: Habilita icone colorido na lista (default habilitada).
* ``viewAsColorIcon`` - ``toggleColorIcon``: Permite a troca de cor do item ao clicar nele.
* ``fullColorIconList`` - Necessário o uso do atributo viewAsColorIcon, permite que o label seja completo na linha.
Number
-----------------------
* ``internalStatus``: Indica que o campo é usado pelo xmova para controlar o status do registro, onde 0 é o status de criado, 2 é o status de finalizado.
* ``notFormatThousand``: Usado em campos numéricos para retirar os pontos e virgulas do texto
* ``numericKeyboard``: Uso para forçar a exibição do teclado numérico mesmo quando um campo é do tipo String.
* ``onlineFlagCreate``: Indica que o campo é uma flag online/offline de criação do registro.
* ``onlineFlagFinish``: Indica que o campo é uma flag online/offline de finalizacao do registro.
Eventos da Entidade [events]
===================
* ``afterInsert``: Realiza o evento após gravar o registro pela primeira vez.
* ``afterFinish``: Realiza o evento após gravar o registro depois de finalizar a entidade.
* ``afterSyncSave``: Após realizar o sincronismo da entidade. É chamado o evento, após o salvamento de cada registro.
* ``beforeInsert``: Realiza o evento antes de gravar o registro pela primeira vez.
* ``beforeFinish``: Realiza o evento antes de finalizar a entidade. Caso o retorno seja falso, não permite a finalização.
* ``beforeDelete``: Realiza o evento antes de excluir o registro.
* ``beforeSync``: Realiza o evento antes de realizar o sincronismo.
* ``onInsertAlreadyExists``: Realiza o evento ao realizar a instrução insert da entidade e o registro já existir.
* ``onItemClick``: Realiza o evento ao clicar no item da lista de uma entidade.
* ``onCrudOptionsBack``: Evento executado quando o aplicativo está na tela de opções do crud e é pressionado a opção de voltar, caso retorne 'false' a ação padrão da tecla voltar (sair do aplicativo) não é executada.
* ``OnShowScheduledMessage``: Evento executado no momento que as mensagens estão sendo listadas para serem exibidas. Caso o evento retorne o valor 'false' a mensagem não é exibida.
Eventos do Campo [fieldEvents]
===================
* ``afterFill``: Realiza o evento após o preenchimento do campo.
* ``autoFill``: Pré-preenche o valor de um campo. Não pede o preechimento do campo para o usuário.
* ``fillCondition``: Verifica se o campo deve ser preenchido. Se retornado false, permite que o usuario passe para o próximo campo sem informar um valor. (default true)
* ``filterListRecord``: Filtra o número de elementos de uma lista, cada registro pode ser acessado atravéz da variável ``listRecord``.
* ``getInputScreenLabel``: Alteração para mudar titulo da tela.
* ``getInputTopMessageLabel``: Alteração para mudar a mensagem que é apresentada entre o título e o primeiro item da lista.
* ``getManyRecords``: Retorna os registros de uma entidade. Faz com que a entidade seja preenchida uma vez para cada registro retornado. Este valor retornado é atribuído a um campo do mesmo tipo na entidade a ser preenchida.
* ``onGetDefaultInputValue``: Pré-preenche o valor de um campo, para mostrar ao usuário. Permite a alteração do valor.
* ``onValidate``: Verifica se o valor é valido e o fluxo pode prosseguir.(default true)(confirm abre uma tela de confirmação)
* ``webView``: Retorna texto com url. Funcionalidade de mostrar pagina html adicionando o atributo webView="url" no campo String.
Padrões de Nomes
================
Nome da entidade usada no server
--------------------------------
O xMova Server quando acessar a entidade do sistema de terceiro ou banco de dados,
usará o próprio nome da entidade no JSON e SQL.
.. note:: Note a saída do JSON. O nome da entidade Serviço não foi alterado. Já o nome da entidade Frente, aparece no JSON como FrenteAG.
**Exemplo de Entidade**::
Servico
id inc
nome String
Frente
id inc
nome String
server name FrenteAG
**JSON que será gerado para o sistema de terceiro durante o sync**::
{"deviceUuid":"357517051399154",
"appCode":"E",
"intVersion":12,
"version":"1.0.11",
"auth":{"obra":76,"operador":177749,"celular":10495},
"types":[
{"version":0,"name":"Servico"},
{"version":0,"name":"FrenteAG"}
]
}
Quantidade de itens selecionados em listas
------------------------------------------
Para obter a quantidade de itens selecionados e não selecionados numa lista multi-select,
o xmova usa um padrão de nomes de campos para definir os valores.
No campo que termina com ``Selecteds`` será definida a quantidade de itens selecionados.
No campo que termina com ``Unselecteds`` será definida a quantidade de itens não selecionados,
ou seja, o total de itens na lista menos a quantidade de itens selecionados.
**Exemplo**::
Apontamento
id inc
funcionarios List
funcionariosSelecteds int notFill
funcionariosUnselecteds int notFill
Campo com os itens que não foram selecionados
---------------------------------------------
Num campo de checklist são armazenados os ids dos registros que foram selecionados. Para se obter os ids dos que não foram selecionados declara-se um outro campo com nome terminando com 'UnselectedRecords'.
**Exemplo**::
Apontamento
id inc
funcionarios List
funcionariosUnselectedsRecords List notFill
---------------
GERAL
---------------
Ações de CRUD [crudActions]
==========
Permite adicionar ações customizadas na tela de opções do crud
**Exemplo**::
Boletim sync=out cleanupDays=20 notSavedMessage
id inc
idSeqBoletim uuid
numero int notFill
crudActions
myCrudAction
actionLabel
return id
fill numero
* ``crud``: Chama o preenchimeto de uma entidade.
* ``isVisible``: Retorna se opção será visivel no menu. (default true)
* ``fill``: Chama o preenchimeto de um campo na mesma entidade.
* ``show``: Retorna uma tela customizada (custom ou tableLayout)
* ``actionLabel``: Retorna o texto visivel para a opção no menu.
Options
=======
Permite adicionar ações customizadas no menu de opções que pode ser exibido na tela de opções do crudo e nas telas de lista de entidades.
**Exemplo**::
Boletim sync=out cleanupDays=20 notSavedMessage
id inc
idSeqBoletim uuid
numero int notFill
options
myOption
actionLabel
return id
fill numero
* ``isVisible``: Retorna se opção será visivel no menu. (default true)
* ``actionLabel``: Retorna o texto visivel para a opção no menu.
Entidades que podem ser acessadas no fluxo.
=========================================
* ``AppEntityVer``: Grava as versões de cada entidade.
* ``_Deleted``: Grava os registros deletados da entidade. (usar: nome_da_entidade + _Deleted)
* ``_Favorite``: Grava os registros salvos como favorito da entidade. (usar: nome_da_entidade + _Favorite)
* ``_FixedPoint``: Salva e recupera o estado da tela para retornar ao app no mesmo ponto do fluxo quando reiniciar o app.
* ``_SyncOut``: Grava os registros salvos da entidade sync=out que deverá ser enviada para o servidor no próximo sincronismo. (usar: nome_da_entidade + _SyncOut)
* ``_Favorite``: Grava os registros salvos como favorito da entidade. (usar: nome_da_entidade + _Favorite)
---------------
Linguagem xMova
---------------
.. _sync-ref:
Tipo de Sincronismo da Entidade
===============================
Em cada entidade pode-se definir o tipo de sincronismo. Quando o app faz um sync com o servidor
cada entidade será analisada para verificar se os dados dela serão enviados ou recebidos do servidor,
ou se a entidade será ignorada no sync.
``sync=in``: O servidor retornará os dados desta entidade em todos os sync Foreground.
``sync=out``: Em todos os Sync, Foreground ou Background, os dados dessa entidade serão enviados ao servidor.
``sync=in|out``: O servidor retornará os dados desta entidade em todos os sync Foreground, e enviará
os dados inseridos nela em todos os sync.
``sync=backgroundIn``: O servidor retornará os dados desta entidade em todos os sync,
independente de ser Foreground ou Background.
``sync=beforeInstall``: O servidor retornará os dados desta entidade apenas no primeiro sync ANTES da
instalação do app. Serve para fluxos em que seja necessário exibir lista de opções durante o processo
de configuração inicial do fluxo.
.. _timezone-ref:
.. _now-ref:
Data e Hora
===========
No modelo de dados, pode-se definir um campo como tipo ‘now’ para que nesse campo seja armazenada a data e hora
corrente quando cria-se um apontamento.
Quando o xmova armazena a data e hora corrente em um registro de apontamento, ela pode ser de 4 tipos.
A letra do tipo é que será enviado ao sistema externo.
* ``U``: Data e hora indefinida;
* ``S``: Data e hora obtida do servidor;
* ``M``: Data e hora informada pelo usuário/operador manualmente;
* ``G``: Data e hora obtida do GPS;
* ``D``: Data e hora nativa obtida do device;
No fluxo pode-se definir que a data e hora não seja solicitada ao usuário, mas que seja pega a data e hora
corrente do device. Quando isso ocorrer, o xmova não enviará para o servidor o tipo de
data ``M`` Manual, mas sim enviará o tipo de data ``D`` Device.
**Exemplo**::
App appCode=R offlineDate=Device
No modelo, no campo que guarda a data e hora do tipow ‘now’, pode-se definir o nome de campo no sistema externo
onde será informado o tipo de data que foi utilizada. Para isso use o atributo ``timeTypeField``.
Dessa forma, quando enviar o JSON para o sistema externo, o xMova Server enviará 2 campos,
o campo do tipo ``now`` contendo a data e hora, que o desenvolvedor criou no modelo,
e um segundo campo para informar o tipo de data e hora utilizada, que não faz parte da
entidade no mobile, mas foi especificado no campo do tipo ``now``.
**Exemplo**::
Apontamento
boletim Boletim
data now timeTypeField=tipoData
servico Servico
**Exemplo de envio da data no JSON**::
{"boletim":100,
"data":"11/07/2014 09:10:32",
"tipoData":"G",
"servico":200}
=================
FUNCIONALIDADES
=================
.. _memory-ref:
-----------------
Entidade em Memória
-----------------
Para que as buscas de uma determinada entidade seja feita com performance máxima, basta ativar o gerenciamento da entidade em memória.
O xMova manterá todos os registros da entidade em memória deixando a leitura dos dados muito rápida, pois não terá que lê-la do banco de dados.
Na primeira vez que uma entidade de memória for usada o xMova carregará os dados dela do banco em memória, e isso poderá demorar um pouco
dependendo da quantidade de dados. Enquanto estiver lendo os dados do banco e colocando na memória, aparecerá uma tela bloqueando a tela
informando ao usuário que aguarde o carregamento dos dados.
Para ativar o gerenciamento em memória de uma entidade, basta adicionar o atributo ``memory`` na entidade.
**Exemplo de Entidade em Memória**::
Servico sync=in memory
id inc
nome String
Frente
id inc
nome String
No exemplo acima, a entidade ``Servico`` será mantida em memória.
.. _change_config-ref:
-----------------------------------
Alteração dos Dados de Configuração
-----------------------------------
Essa seção descreve os passos necessários para alterar os dados de configuração do
aplicativo sem a necessidade de realizar o procedimento de limpeza.
Primeiro é preciso criar a opção Trocar Líder, que ficará no menu da tela inicial.
**No App**::
Main main entity=AuthInput fields=descricaoObra,descricaoLider,descricaoCelular
actions
Boletim Ok
crud Boletim
TrocarLider
Integer numApontBoletim = rowCount table=Boletim_SyncOut
Integer numApontApontamento = rowCount table=ApontamentoFuncionario_SyncOut
if numApontBoletim + numApontApontamento + numApontFuncionarios + numApontLocation == 0
crud ChangeLider
else
toast Sincronize os Dados!
A opção ``TrocarLider`` deverá ser adicionada no ``actions`` do ``Main``.
Qualquer alteração dos dados de configuração somente poderá ser feita se não houver dados offline.
Portanto é necessário realizar uma validação em todas as Entidades que realizam ´´sync=out´´
do aplicativo, confirmando se há algum registro aguardando para ser enviado.
Isso é realizado obtendo a quantidade de registros de todas as entidades do tipo ``_SyncOut``
do aplicativo. Deve-se então atribuir a um campo ``Integer`` o resultado do ``rowCount`` de cada Entidade.
Por exemplo, para a Entidade Boletim foi criado o Integer numApontBoletim, que recebe o valor
do ``rowCount`` da Entidade Boletim_SyncOut.
Após obter o ``rowCount`` de todas as entidades, é realizada uma validação, somando todos
os valores.
Se o resultado for maior que zero, significa que existem dados gravados e a alteração dos dados
não poderá ser realizada. Nesse caso uma mensagem será mostrada, pedindo para sincronizar os dados.
Se o valor for igual a zero, significa que não há dados gravados, e alteração poderá ser realizada.
Nesse caso, um ``CRUD`` será executado. Esse ``CRUD`` é relacionado a uma Entidade que deverá ser definida
no modelo, conforme exemplo abaixo.
**No Model**::
Auth
obra int
lider int
celular int
AuthInput notSavedMessage
obra obra
lider int
celular int
ChangeLider notSavedMessage
lider int
events
afterInsert
AuthInput authInput = selectFirst from AuthInput
authInput.lider = lider
save authInput
Auth auth = selectFirst from Auth
auth.lider = lider
save auth
dropTable AppEntityVer
dropTable Funcionario
exit
No exemplo acima, temos as entidades envolvidas nessa alteração: Auth, AuthInput e ChangeLider.
O Auth é a Entidade que contém as informações que serão enviadas no JSON de todos os apontamentos.
O AuthInput é a Entidade preenchida na primeira vez que o aplicativo é instalado.
O ChangeLider é a Entidade que será criada para alterar algum valor do Auth e AuthInput. Nesse exemplo, será alterado o líder.
Quando executado, o ChangeLider irá pedir o campo líder.
Após o preenchimento desse campo, o evento ``afterInsert`` será executado.
O AuthInput é carregado e o valor de seu campo líder é alterado para o valor informado.
O Auth é carregado e seu campo líder é alterado para o valor informado.
Se houver a necessidade de obter alguma Entidade após essa alteração,
é preciso apagar os valores que estão no celular e obtê-los novamente.
Nesse exemplo, a lista de Funcionários vinculados a líder será apagada e obtida novamente.
Portanto deve-se apagar a entidade de versões e a de Funcionários.
Para isso utiliza-se o comando ``dropTable`` + o nome da entidade.
Por fim é executado o comando ``exit``, que fecha o aplicativo.
Isso é necessário para os dados sejam obtidos assim que for iniciado.
Auth e AuthInput
=================
.. danger:: No update essas entidades Auth e AuthInput são mantidas para não ter que digitar os dados de instalação novamente a cada update. Se alterar os campos dessas entidades, visto que elas não são apagadas, o modelo tem campos diferentes dos campos da entidade, corrompendo os dados. Caso seja necessário alterar os campos das entidades Auth e AuthInput, será necessário desisntalar e fazer a instalação do fluxo novamente.
.. _onlineValidate-ref:
-----------------
Validação On-Line
-----------------
O xMova pode fazer validação online dos valores inseridos nos campos de uma entidade.
Basta adicionar ao campo o atributo ``onlineValidate=obra``.
**Exemplo**::
Boletim
boletim Boletim
data now timeTypeField=tipoData
codigoOperador int onlineValidate=operador
idOperador int notFill
nomeOperador String notFill
Retorno de Dados Validados
==========================
.. danger:: O xMova Server enviará para o sistema de terceiro o registro inteiro para validação. O sistema deve retornar novamente o sistema inteiro, com os mesmos dados que foram enviados, adicionando ao registro dados adicionais que foram validados. No exemplo acima, deverá ser retornado para o xMova os valores nos campos ``idOperador`` e ``nomeOperador``, bem como todos os dados que foram enviados.
O sistema de terceiro deve retornar os seguites status:
* Sucesso: ``status=0``
* Erro: ``status=1``
* Falha: ``status>=2``
Mensagem de Erro de Validação
=============================
Quando a validação retornar um status 1 (erro), o xMova mobile pega a mensagem de erro na seguinte ordem:
#. ``entity.Boletim.codigoOperador.onlineValidateError``
#. ``msg.onlineValidateError`` (obrigatório)
Mensagem de Falha de Validação
==============================
Quando a validação retornar um status diferente, ou seja ``>= 2`` (falha), o xmova pega a mensagem na seguinte ordem:
#. ``entity.Boletim.codigoOperador.onlineValidate.{STATUS}``
#. ``entity.Boletim.codigoOperador.onlineValidateFail``
#. ``msg.onlineValidateFail`` (obrigatório)
.. _barcode-ref:
-------
BARCODE
-------
O xMova pode ler codigo de barras de diversos tipo por meio da câmera do celular.
QRCODE
======
Para ler as informações de um QRCODE, deve ser alterado o APP do fluxo, definindo no reader a propriedade camera, que irá definir o comportamento da leitura.
Para ler com QRCODE deve ser adicionado á propriedade camera o atributo type e sizes, onde type define o tipo de leitura( ex: QRCODE,CODE93,CODE128) e o sizes define o numero de caracteres que o QRCODE/BARCODE representa.
Quando é definido um valor ao sizes, será feita a busca por códigos de barras, ou barcode, que representam aquele numero de caracteres definido, não reconhcendo QRCODE/BARCODE que possuam mais ou menos dígitos e os entendendo como invalidos.
Caso não seja definido o atributo sizes, ele irá ler quaisquer QRCODE/BARCODE que lhe for lhe for apresentado independente de seu tamanho.
segue um exemplo de como ficará no APP
No exemplo a seguir foi definido no app que a funcionalidade de leitura somente reconhcerá QRCODES e que representem caracteres de 9 digitos.
**Exemplo**::
App appCode=LIDER periodicSync
id 555
name ConstruMobil
reader
camera types=QRCODE sizes=9 minQuality=20
Caso haja a necessidade de aceitar outras quantidades de caracteres, é necessário informá-las no atributo sizes.
No exemplo a seguir, o aplicativo aceita QRCODES de tamanho 5 e de tamanho 9.
**Exemplo**::
App appCode=LIDER periodicSync
id 555
name ConstruMobil
reader
camera types=QRCODE sizes=5,9
Para que um campo possa ser lido a partir de um QRCODE/BARCODE, deve ser definido o campo como long e adicionado ao campo o atributo reader com o valor (reader=cam).
No exemplo a seguir mostra a definição de um campo(code) de uma entidade(TesteQRCode) no model, que será lido de um QRCODE que será lido pela câmera do celular e mostrado uma mensagem com o valor do campo lido.
**Exemplo**::
TesteQRCode sync=out
code long reader=cam
fieldEvents
onValidate
code
return confirm lang=custom.msgQRCode vars=qrcode:code
.. _bluetooth-ref:
----------------------------------
Sincronismo Off-line por Bluetooth
----------------------------------
Master: Recebimento de Dados de Cadastro off-line
=================================================
O celular que envia dados de cadastro ``sync=in`` para outro é chamado de Master. O que recebe os dados é chamado de Slave. No sincronismo via Bluetooth ou Http off-line ocorre tanto o envio dos dados off-line para o master, quanto o recebimento dos dados de cadastro do master para o slave, numa mesma requisição Bluetooth ou HTTP.
Para tornar um fluxo master, defina a linha master no App. No atributo appCodes você define quais os appCodes que esse master vai atender. Se um fluxo Slave com ``appCode=LIDER`` tentar enviar dados para um master que não definiu esse appCode, ele apenas conseguirá fazer o envio dos dados offline, mas não o recebimento dos dados ``sync=in``.
**Veja um exemplo de como definir um fluxo como Master**::
App appCode=LIDER
id 555
name ConstruMobil
Main main
master appCodes=A,B
A
Servico slaveName=Serv
onInit
Equipamento equipamento = auth.equipamento
Familia familia = selectLast from Familia where id == :equipamento.familia
onFilter
Integer i = 0
if id in familia.servicos && familia.flagPrincipal == auth.familiaPrincipal
return true
Familia
onFilter
log filtrando...
Entidade AuthSlave
==================
No modelo do fluxo do Master é necessário definir a entidade auth de todos os fluxos de slaves aceitáveis. A definição deve seguir o padrão de nome ``AuthSlave_ + AppCode do slave``. Exemplo: ``AuthSlave_L``. Os campos dessa entidade devem ser idênticos aos campos da entidade auth original do Slave.
Evento onFilter
===============
Para cada appCode definido no master, pode-se definir o evento onFilter para cada entidade. Dessa forma, o Master pode obter os dados completos de uma entidade do servidor, mas enviar apenas uma parte desses dados que interessem ao Slave. Esse evento será chamado para cada registro da entidade em que ele foi definido. São padrão no evento onFilter as variáveis record, auth, e todas as variáveis locais definidas no evento onInit.
Variável record
---------------
É o registro que está sendo filtrado no momento. É também o context do evento, podendo ser acessados os campos diretamente. Em vez de digitar ``if record.familia == 5`` pode-se usar diretamente o nome do campo ``if familia == 5``.
Variável auth
-------------
É o registro inteiro, com todos os dados do auth do fluxo Slave. Esse registro auth é enviado pelo Slave no início da requisição. Dessa forma, pode-se filtrar os dados de acordo com alguma informação do auth do fluxo do Slave, enviando apenas dados que interesse a ele.
Evento onInit
=============
O evento onInit pode ser definido em cada entidade do Slave. Ele é executado antes de começar a percorrer os registros da entidade que será enviada. Todas as variáveis definidas nesse evento poderão ser usadas no evento onFilter como se fossem variáveis locais definidas lá no onFilter, pois os valores delas são copiados do evento onInit para o evento onFilter. Normalmente usa-se esse evento para pré-carregar registros do banco que serão usados massivamente no evento onFilter.
.. _location-ref:
---
GPS
---
Para implementar o GPS no fluxo xMova é necessário adicionar a
entidade Location no Modelo e configurar o location no App.
**No Modelo**::
Location sync=out
lat double
long double
alt double
gpsTime long
**No App**::
App
location minTime=1m minDistance=100 minLastTime=10m
* ``minTime``: Intervalo de tempo para o core atualizar a posição atual do GPS
* ``minDistance``: Distância mínima para o core atualizar a posição atual do GPS
* ``disableNotifyMessage``: Desabilita a mensagem que é exibida ao usuário quando o aplicativo tenta usar o GPS e o mesmo está desativado
* ``disableGpsRestartOnResume``: Desabilita a funcionalidade que faz com que o GPS seja reiniciado cada vez que o aplicativo sai do estado de background para foreground. (API Android chama o método onResume).
* ``minLastTime``: É o tempo da última posição válida obtida do GPS que o apontamento pode utilizar. Se tiver configurado para 10 minutos e a última posição válida obtida do GPS for de 20 minutos, o Location nesse caso será nulo, ou seja, não será enviado junto ao apontamento. O tempo ideal estipulado para esse campo é 10 minutos.
Se definir ``minTime`` como 1h e ``minDistance`` 100m, os dois valores serão tratado como AND, ou seja,
só atualizará quando os dois casos forem verdadeiros. Após 1h e tendo deslocado pelo menos 100m.
Se passou 2h, mas andou somente 50m, a posição não será atualizada.
Se o ``minTime`` for 0 e o ``minDistance`` for 100m, o GPS será atualizado sempre que ultrapassar 100m,
independente de horário.
Se o ``minTime`` for 1h e o ``minDistance`` for 0m, o GPS será atualizado a cada hora,
independente da distância.
Apontamento com GPS
===================
Para enviar a informação do GPS em uma entidade basta adicionar um campo do tipo Location em tal entidade.
**No Modelo**::
Boletim sync=out
id inc
idSeqBoletim Long
location Location inlineData
Apontamento sync=out
id inc
idSeqApontamento Long
location Location inlineData
.. note:: Utilize inlineData para que o registro de Location não fique separado do apontamento.
**Exemplo do JSON que será criado nos apontamentos acima descritos**::
Boletim
{
"id":1,
"idSeqBoletim":"1023043202340",
"location":
{
"lat": -23.1935728
"long": -45.8929331,
"alt": 0.0,
"gpsTime": 1406721814242,
}
}
Apontamento
{
"id":1,
"idSeqApontamento":"1023234402340",
"location":
{
"lat": -23.1935728
"long": -45.8929331,
"alt": 0.0,
"gpsTime": 1406721814242,
}
}
Tracking
========
Para Tracking deve-se adicionar o atributo ``tracking`` no ``location`` do app,
e adicionar ``minDistance`` = 0m. O `minTime`` também deve ser configurado, e seu valor deve ser maior que zero.
Utilize o evento ``onInsert`` para adicionar informações adicionais no apontamento
ou executar outras instruções antes de um Tracking ser inserido. No exemplo
abaixo adicionamos a hora local ao Location no evento ``onInsert``.
**No App**::
App
location minTime=1m minDistance=0 minLastTime=10m tracking
onInsert [opcional]
dataHora = currentDate
**No Model**::
Location sync=out
lat double
long double
alt double
gpsTime long
dataHora now
.. _message-ref:
----------
Mensageria
----------
O xMova pode receber e enviar mensagens.
Recebimento de Mensagem
=======================
Para receber mensagens, precisamos ativar o sync periódico no xmova, de forma que ele faça sync mesmo que não tenha dados offline. O tempo de intervalo entre os sync será o mesmo tempo definido em syncInterval no app. Para ativar o sync periódico, basta adicionar o atributo periodicSync no App.
Nos sync offline normalmente o xMova não retorna qualquer entidade, apenas envia os dados offline. Como o objetivo do sync periódico é retornar as mensagens, precisamos definir na entidade que receberá as mensagens ``sync=BackgroundIn`` para que o xMova retorne essa entidade em todos os sync foreground ou background.
**Exemplo**::
App appCode=LIDER periodicSync
id 555
name ConstruMobil
afterSync
show MensagemScr
MainSrc …
...
MessageScr message title=Mensagem entity=Mensagem messageField=msg dateField=data fromField=from
actions
ok
INSERT INTO ResumoMensagem (texto,data,remetente,enviada) VALUES (:texto,:data,:remetente,false)
Envio de Mensagem
=================
A funcionalidade de envio de mensagens é feita com cadastro normal do xmova, como se fosse um apontamento.
Para o xMova ficar solicitando mensagens
----------------------------------------
**No App**::
App syncInterval=1m periodicSync
...
#No events, adicionar:
afterSync
show MessageScr
Main ...
actions
#Adicionar a Action...
Mensagem
crud CentralMensagem
#Adicionar a Screen
MessageScr message title=Mensagem entity=MensagemRecebida messageField=texto dateField=data fromField=remetente
actions
ok
INSERT INTO ResumoMensagem (texto,data,remetente,enviada) VALUES (:texto,:data,:remetente,false)
#Adicionar a Screen
Adicionar em Constants
TipoMensagemEnviarSelecionar 1
TipoMensagemEnviarEscrever 2
TipoMensagensEnviadas 1
TipoMensagensRecebidas 2
TipoMensagemEnviar 3
#Adicionar no InstallData
InstallData
TipoMensagemEnviar
1 Selecionar
2 Escrever
TipoMensagens
1 Enviadas
2 Recebidas
3 Enviar
**No Model**::
MensagemCadastro sync=in EmptyVerify=false
id int
descricao Str
MensagemRecebida sync=backgroundIn EmptyVerify=false
id int
data Str
texto Str
remetente Str
MensagemEnviada sync=out cleanupDays=15 notSavedMessage
data Now
texto text
TipoMensagemEnviar
id int
descricao Str
TipoMensagens
id int
descricao Str
ResumoMensagem cleanupDays=15
texto Str
data Str
remetente Str
enviada boolean
CentralMensagem cleanupDays=5 notSavedMessage
id inc
tipoMensagens TipoMensagens
tipoEnviar TipoMensagemEnviar fillCondition="tipoMensagens == %TipoMensagemEnviar"
data Now
mensagemCadastro MensagemCadastro fillCondition="tipoEnviar == %TipoMensagemEnviarSelecionar"
mensagemTexto text fillCondition="tipoEnviar == %TipoMensagemEnviarEscrever"
enviadas ResumoMensagem fillCondition="tipoMensagens == %TipoMensagensEnviadas"
recebidas ResumoMensagem fillCondition="tipoMensagens == %TipoMensagensRecebidas"
fieldEvents
afterFill
mensagemCadastro
INSERT INTO MensagemEnviada (data ,texto ) VALUES (:data,:mensagemCadastro.descricao)
INSERT INTO ResumoMensagem (texto,data,enviada) VALUES (:mensagemCadastro.descricao,:data, true)
sync background
mensagemTexto
INSERT INTO MensagemEnviada (data ,texto ) VALUES (:data,:mensagemTexto)
INSERT INTO ResumoMensagem (texto,data,enviada) VALUES (:mensagemTexto,:data, true)
sync background
filterListRecord
enviadas
if (listRecord.enviada == false)
return false
recebidas
if (listRecord.enviada == true)
return false
#Onde desejar exibir a opção de Mensagens, adicionar na entidade pai:
Boletim
crudActions
Mensagens
fill centralMensagem
**No Lang**::
EntityLabel.CentralMensagem = Central Mensagem
EntityLabel.MensagemCadastro = Cadastro
EntityLabel.TipoMensagens = Central Mensagens
EntityLabel.TipoMensagemEnviar = Enviar
FieldLabel.CentralMensagem.enviadas = Enviadas
FieldLabel.CentralMensagem.recebidas = Recebidas
FieldLabel.CentralMensagem.mensagemTexto = Mensagem
EntityLabel.ResumoMensagem = Mensagens
FieldLabel.ResumoMensagem.texto= Texto
FieldLabel.ResumoMensagem.data= Data
FieldLabel.ResumoMensagem.remetente= Remetente
Mensagem Agendada
=================
Com o atributo **MessageScheduled** e a adição de alguns campos obrigatórios é possível receber dados que serão usados para exibir uma mensagem em um determinado horário (todos os dias) ou então em uma determinada data uma única vez.
**No App**::
App syncInterval=1m periodicSync
**No Model**::
ScheduledMessage sync=backgroundIn messageScheduled
id int
title Str
text Str
hour Str
date Str
fixedPoint int
executed Date
scheduled Date
events
onShowScheduledMessage
log title
log scheduled
log executed
- O campo **id** é obrigatório, o Core faz uso deste campo para manipular os dados das mensagens a serem agendadas e para encontrá-las depois que foram exibidas para deletar ou fazer o update caso seja uma mensagem que tenha repetição.
- O Core irá buscar o primeiro campo do tipo String para fazer uso como título da mensagem e o campo abaixo para o conteúdo da mensagem, no caso do exemplo acima o campo **title** será usado como título da mensagem e o campo **text** será usado como o conteúdo da mensagem. (Obs.: os campos podem ter outro nome, desde que sejam os primeiros campos do tipo String).
- O fluxo deve conter um campo de nome **hour** do tipo String ou um campo **date**; que pode ser String, long ou Date, ou conter os dois campos. Quando o aplicativo contiver os dois campos será dada a preferência para o campo **hour** caso o valor seja vazio então será usado o valor do campo **date** para fazer o agendamento da mensagem.
- (Obs.: Caso nenhum valor seja encontrado para o campo **hour** ou **date** a mensagem não será agendada, caso o Core use o valor do campo **date** e a data for menor do que a data atual a mensagem não será agendada e caso o Core use o valor do campo **hour** e o horário for menor do que o horário atual a mensagem será agendada para ser executada no próximo dia).
- Sempre que o valor do campo **hour** é utilizado para o agendamento da mensagem o Core reagenda a mensagem para ser executada sempre no mesmo horário, todos os dias.
- O campo **fixedPoint** do tipo inteiro indica se deve ou não existir um fixed point salvo no aplicativo para que a mensagem seja exibida. Caso o valor seja 1 o aplicativo somente irá exibir a mensagem se tiver um fixed point salvo.
- O formato esperado para o campo **hour** é **HH:mm** ou **HH:mm:ss**.
- O formato esperado para o campo **date** é **yyyyMMddHHmmssSSS**
- Caso o campo **executed** exista o Core atribui a ele o valor de quando foi a última vez que a mensagem foi exibida e confirmada pelo usuário
- Caso o campo **scheduled** exista o Core atribui a ele o valor de quando a mensagem foi agendada
- O evento 'onShowScheduledMessage' é executado antes da mensagem ser exibida, caso o evento retorne 'false' a mensagem não é exibida. O contexto do evento é o registro da mensagem que será exibida, então podem ser usados os valores dos campos da entidade para comparações.
- Para calcular o tempo para agendar a exibição da mensagem o Core faz uso do ERT (Elapsed Real Time) que registra o tempo de atividade do aplicativo desde o último boot e a diferença em millisegundos da data atual válida para a data de execução da mensagem.
- Sempre que o dispositivo é desligado ou há uma mudança da hora válida dos tipos 'D ou M' para os tipos 'G ou S' todos os eventos são reagendados.
- Sempre que o dispositivo recebe novos dados da entidade para agendamento de mensagem todos as mensagens ainda não exibidas são canceladas e são agendadas todas mensagens recebidas.
- Caso o Core não encontre o registro no banco de dados no momento de exibir a mensagem agendada a mensagem agendada é cancelada.
**No Lang**::
FixedKeyMsgScheduledScreenTitle = Mensagem (Valor padrão)
FixedKeyMsgScheduledHour = Horário (Valor padrão)
FixedKeyMsgScheduledTitle = Título (Valor padrão)
FixedKeyMsgScheduledMessage = Mensagem (Valor padrão)
FixedKeyMessageSourceScreenMessageConfirmOK = OK (Valor padrão)