Nesta página5 seções
Antes de começar
- A tabela ZA1 criada no Configurador, com os campos, os índices, o gatilho de idade, as pastas e os agrupamentos dos artigos anteriores da série.
- As funções U_ZA1NUM() (inicializador do código) e U_ZA1VldIdade() (validação do nascimento), dos artigos anteriores, compiladas no mesmo repositório.
- Um ambiente de desenvolvimento onde você possa compilar fontes no repositório.
- Acesso ao Configurador para pôr a rotina no menu de um módulo.
Tabela criada, campos configurados, índice e gatilho no lugar — e nada disso
aparece para ninguém até existir uma rotina que abra a tabela. O dicionário
descreve; quem mostra é uma tela. Este texto entrega a tela mínima para a
ZA1, o cadastro de motoristas desta série, e diz o que conferir nela para
saber se o que foi configurado no Configurador está funcionando.
A tela é MVC. O motivo prático: FWFormStruct lê o dicionário e monta a
estrutura sozinha, então tudo o que você configurou — título, tipo, combo,
validação, inicializador, pasta, gatilho — chega à tela sem uma linha a mais
de código. Se MVC é novidade, comece por
MVC no Protheus: o que é e por que existe.
O que a primeira inclusão tem de mostrar
Este é o plano de teste. Quando a rotina estiver no menu, clique em Incluir e
confira cada linha abaixo; cada uma testa uma configuração feita num artigo
anterior. Se um item falhar, o problema não está no fonte da próxima seção,
que não sabe nada sobre esses campos: está no dicionário ou numa das duas
funções que ele chama, U_ZA1NUM() e U_ZA1VldIdade() — confira se ambas
estão compiladas no repositório.
| O que ver na tela | O que isso comprova | Onde foi configurado |
|---|---|---|
| Código já preenchido | O inicializador U_ZA1NUM(), que só pede número na inclusão | Campo caractere |
| Nome vazio é recusado | A obrigatoriedade do nome, marcada na pasta Uso em Campo caractere e cobrada ao confirmar, e o NaoVazio() da validação do campo | Validação |
| Idade calculada sozinha | O gatilho ZA1_NASC → ZA1_IDADE, com um nascimento que U_ZA1VldIdade() aceite | Gatilhos |
| Vínculo em lista | O combo 1=Proprio;2=Agregado;3=Terceiro | Campo combo |
| MOPP é caixa de marcar | O campo lógico | Campo lógico |
| Observação multilinha | O campo memo, área de texto | Campo memo |
| Campos em duas pastas | As pastas Dados do motorista e Observacoes | Pastas |
| Separador Identificacao | O agrupamento A01: ZA1_COD, ZA1_NOME, ZA1_NASC e ZA1_IDADE sob um título | Agrupamentos |
| Painel Vinculo e MOPP | O agrupamento A02: ZA1_VINC e ZA1_MOPP, que podem ser escondidos e revelados | Agrupamentos |
Se uma linha falhar, confira no dicionário:
- Código já preenchido:
X3_RELACAOdoZA1_COD. - Nome vazio é recusado: o obrigatório na pasta Uso do Configurador;
X3_VALIDeX3_VLDUSERdoZA1_NOME. - Idade calculada sozinha:
X3_TRIGGERdoZA1_NASCe a regra naSX7. - Vínculo em lista:
X3_CBOXdoZA1_VINC. - MOPP é caixa de marcar:
X3_TIPOdoZA1_MOPP=L. - Observação multilinha:
X3_TIPOdoZA1_OBS=M. - Campos em duas pastas:
X3_FOLDERde cada campo e as pastas naSXA. - Separador Identificacao:
X3_AGRUP=A01nos quatro campos;XA_TIPO=2naSXA. - Painel Vinculo e MOPP:
X3_AGRUP=A02nos dois campos;XA_TIPO=1naSXA.
A consulta ao fim do texto traz essas colunas da SX3; as da SXA estão na
consulta de pastas e agrupamentos.
O fonte
Para chegar a essa tela basta o mesmo molde do cadastro didático publicado em
Seu primeiro cadastro MVC, do dicionário à tela,
trocando a tabela e os nomes: função principal com o browse, e as três
Static Function que o framework procura pelo nome.
#Include "Protheus.ch"
#Include "FWMVCDef.ch"
/*/{Protheus.doc} ZA1CAD
Cadastro de motoristas (tabela customizada ZA1) em MVC, entidade unica.
Toda a tela vem do dicionario: FWFormStruct le a SX3 da ZA1 e traz
titulos, tipos, combos, validacoes, inicializadores, pastas e gatilhos.
Nao ha gravacao no fonte: o MPFormModel instala o commit padrao.
Exemplo didatico. Crie a tabela ZA1 no Configurador antes de compilar.
@type user function
@return nil
@example U_ZA1CAD()
/*/
User Function ZA1CAD()
Local oBrowse := Nil
oBrowse := FWMBrowse():New()
oBrowse:SetAlias("ZA1")
oBrowse:SetDescription("Motoristas")
// Nome do FONTE onde esta o MenuDef, nao o nome da funcao.
oBrowse:SetMenuDef("ZA1CAD")
oBrowse:Activate()
Return Nil
/*/{Protheus.doc} MenuDef
Opcoes do browse. As de edicao apontam todas para VIEWDEF.ZA1CAD; o
OPERATION e que distingue incluir, alterar e excluir.
@type static function
@return array, o aRotina do browse
/*/
Static Function MenuDef()
Local aRotina := {}
ADD OPTION aRotina TITLE "Pesquisar" ACTION "AxPesqui" OPERATION 1 ACCESS 0
ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.ZA1CAD" OPERATION 2 ACCESS 0
ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.ZA1CAD" OPERATION 3 ACCESS 0
ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.ZA1CAD" OPERATION 4 ACCESS 0
ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.ZA1CAD" OPERATION 5 ACCESS 0
Return aRotina
/*/{Protheus.doc} ModelDef
O modelo: estrutura lida do dicionario e chave primaria.
@type static function
@return object, o modelo de dados
/*/
Static Function ModelDef()
Local oModel := Nil
// 1 = estrutura do MODELO, a partir da SX3.
Local oStruct := FWFormStruct(1, "ZA1")
// O ID do modelo e diferente do nome da funcao principal.
oModel := MPFormModel():New("ZA1CADM")
oModel:AddFields("ZA1MASTER", /*cOwner*/, oStruct)
oModel:SetDescription("Motoristas")
oModel:GetModel("ZA1MASTER"):SetDescription("Dados do motorista")
// Mesma chave do indice 1 da ZA1.
oModel:SetPrimaryKey({"ZA1_FILIAL", "ZA1_COD"})
Return oModel
/*/{Protheus.doc} ViewDef
A tela: recebe o modelo e diz onde cada componente aparece.
@type static function
@return object, a view ligada ao modelo
/*/
Static Function ViewDef()
Local oView := Nil
Local oModel := FWLoadModel("ZA1CAD")
// 2 = estrutura da VIEW. As pastas da SXA vem junto.
Local oStruct := FWFormStruct(2, "ZA1")
oView := FWFormView():New()
oView:SetModel(oModel)
oView:AddField("VIEW_ZA1", oStruct, "ZA1MASTER")
oView:CreateHorizontalBox("TELA", 100)
// Sem SetOwnerView o componente existe e nao aparece.
oView:SetOwnerView("VIEW_ZA1", "TELA")
Return oViewO fonte segue linha a linha o molde publicado; não foi compilado para este texto. As regras que valem para ele são as mesmas de lá, e cada uma tem artigo próprio:
SetMenuDef("ZA1CAD")eFWLoadModel("ZA1CAD")recebem o nome do fonte — por isso o fonte precisa se chamarZA1CAD(MenuDef).FWFormStruct(1, ...)vai para o modelo,FWFormStruct(2, ...)para a tela; trocar os dois é erro de tipo em tempo de execução (ModelDef, ViewDef).SetPrimaryKeyrecebe a mesma chave do índice 1 daZA1,ZA1_FILIAL+ZA1_COD(Índices no Protheus).
Compilar e chamar
Compile o fonte ZA1CAD no repositório do ambiente de desenvolvimento
(Compilar AdvPL e TLPP pela linha de comando).
Depois ponha U_ZA1CAD no menu do módulo, como função de usuário — o passo a
passo, com o grupo Customizados no Faturamento, está em
Menus do Protheus.
A rotina abre um browse vazio, com as opções do MenuDef.
A primeira inclusão
Clique em Incluir e percorra a tabela do plano de teste, no início do texto.
Dois cuidados nessa conferência:
A idade precisa mudar com o nascimento. Informe uma data, veja a idade;
troque a data, veja a idade mudar. Use datas que atendam a idade mínima do
parâmetro MV_XIDMIN, lido pela U_ZA1VldIdade(): uma data abaixo dela é
recusada com a mensagem da validação, e a idade não aparece — isso é a regra
funcionando, não o gatilho falhando
(Validação).
Para saber qual idade mínima vale no seu ambiente:
SELECT X6_FIL, X6_VAR, X6_TIPO, X6_DESCRIC, X6_CONTEUD
FROM SX6010
WHERE X6_VAR = 'MV_XIDMIN'
AND D_E_L_E_T_ = ' 'Sem linha, o parâmetro não foi criado e a função usa o 21 do fonte. Se a
data foi aceita e a idade não aparece, o gatilho não
disparou — a consulta à SX7 do artigo de gatilhos mostra se ele existe e
com qual condição. Se aparece errada perto do aniversário, a regra está
fazendo conta de dias em vez de usar DateDiffYear().
Dois “Outros” diferentes. O primeiro é a aba Outros, das pastas.
Bloqueio (ZA1_MSBLQL) e foto (ZA1_BITMAP) não foram distribuídos em
Dados do motorista nem em Observacoes. Campo sem pasta reconhecida aparece em
Outros — é inclusive o sintoma que a Central de Atendimento descreve quando a
SXA de uma tabela não é reconhecida e o cadastro inteiro cai nessa aba
(Pastas e agrupamentos).
Se o bloqueio não estiver lá, confira o nível: o _MSBLQL criado pelo
Configurador nasce com nível 9, visível apenas para o Administrador, e um
usuário comum só o vê depois de ajustado o nível de cada módulo
(Campos reservados).
O segundo é dos agrupamentos: segundo a TDN, os campos que não estiverem em
nenhum agrupamento aparecem listados num separador chamado Outros. Um é
aba (pasta), o outro é separador (agrupamento); não confunda um com o outro
ao conferir onde cada campo foi parar.
Depois de gravar, abra a alteração do mesmo registro e confira o nascimento: ele foi configurado para ser editável só na inclusão (Modo de edição). Se você adotou uma das variantes daquele artigo que liberam a correção na alteração — para administradores ou para usuários autorizados —, quem está nesses grupos continua editando o campo. Faça esse teste com um usuário comum.
Confira no banco
O registro gravado, lido direto da tabela física:
SELECT ZA1_FILIAL, ZA1_COD, ZA1_NOME, ZA1_NASC, ZA1_IDADE, ZA1_VINC, ZA1_MOPP
FROM ZA1010
WHERE D_E_L_E_T_ = ' '
ORDER BY ZA1_CODO sufixo 010 é o da empresa; troque pelo do seu ambiente. ZA1_NASC volta
como texto AAAAMMDD
(Campo data),
e a observação, por ser memo, não se lê direto por essa consulta.
Se a consulta não devolve nada depois de uma inclusão que a tela aceitou, ou se a tabela física nem existe, comece conferindo o dicionário:
SELECT X3_CAMPO, X3_TIPO, X3_TAMANHO, X3_TITULO, X3_RELACAO, X3_VALID,
X3_VLDUSER, X3_CBOX, X3_TRIGGER, X3_FOLDER, X3_AGRUP
FROM SX3010
WHERE X3_ARQUIVO = 'ZA1'
AND D_E_L_E_T_ = ' '
ORDER BY X3_ORDEMCampo que falta aqui não existe na tela, no modelo nem no banco — e nenhum
ajuste no ZA1CAD resolve isso. As mesmas colunas diagnosticam as linhas do
plano de teste; pastas e agrupamentos se completam com a
consulta à SXA.
Se a sua primeira tela abre e algum desses itens não bate, fale com a gente.
Referências
TDNtdn.totvs.com
TDN — AdvPl utilizando MVCTDNtdn.totvs.com
TDN — MPFormModelGrava os dados pelo dicionário; o bloco bCommit tem como padrão FWFormCommit.TDNtdn.totvs.com
TDN — FWFormStructEstrutura de metadado do dicionário para Model e View: tipo 1 para o modelo, 2 para a view.TDNtdn.totvs.com
TDN — Comportamento de gatilhos em MVCO MVC executa as validações e os gatilhos dos campos envolvidos na regra.TDNtdn.totvs.com
TDN — SXA, Pastas e Agrupamentos de camposPastas da SXA num FormField de rotina MVC.TDNtdn.totvs.com
TDN — Painel e Separador em rotinas MVCSeparador define título; Painel permite esconder e revelar campos. Campos fora de agrupamento aparecem listados num Separador chamado Outros.Central de Atendimentocentraldeatendimento.totvs.com
Central de Atendimento TOTVS — Cadastro de cliente só apresenta a aba OutrosCampos sem pasta reconhecida na SXA aparecem na aba Outros.
Continue por aqui
- Vídeo
ProtheusReferência técnica
Índices no Protheus: filial primeiro e nickname em tabela padrão
Índices no Protheus: por que o índice começa pela filial, como a ordem passa de 9 para A e por que um índice seu em tabela padrão precisa de nickname.