terça-feira, 23 de outubro de 2012

Desenvolvimento - Gerenciamento de Históricos

Dando continuidade aos antigos posts, hoje iremos conhecer um modo muito interessante de gerenciar as ações de inserções, alterações e exclusões realizadas através das nossas aplicações. 

Em muitos projetos percebemos a intenção dos nossos clientes em controlar quem, quando e qual foi a ação realizada pelos usuários do sistema, isto é, qual usuário realizou uma certa inserção de um registro, quando isso foi realizado, em termos de data/hora e IP, e o mais importante, quais foram os dados informados.

A partir do post, "Genexus SDT - Criação de Log da Aplicação", iremos realizar a leituras destes XML's criados (visualizar leitura de XML a partir do post "Genexus - Leitura de XML" ), compará-los com outros históricos, ou então com a posição atual deste registro, para por último, obtermos um grid que demonstra a  comparação dos atributos em suas determinadas datas. No final teremos uma Web Form semelhante a esta:

Genexus XML

Vídeo do exemplo em ação:



obs.: utilize como apoio o post "Criação de Log da Aplicação".

1º Passo: Criação do SDT para comparar os XML's:

Genexus SDT

2º Passo: Geração de um WokWith para a Transação Log:

Nesta Web Form foi adicionado um Web Component a direita do grid principal, além disto, as propriedades deste grid principal foram setadas conforme a figura abaixo:

Genexus Propriedades

No mesmo Work With, na aba de  "Eventos" foram incluídos os códigos abaixo:
Event Grid.Load
 //=====Variaveis presente no grid de Log=====
 &aLogId = LogId
 &aLogAtividade = LogAtividade
 &aLogAtividadeId = LogAtividadeId
 
 //=====Evento Visualizar=====
 &Display.Link = Log.Link(TrnMode.Display, LogId)
EndEvent

Event TrackContext(&aLogId)
 //=====Cria Web Component ao selecionar linha do grid=====
 WebComp1.Object = WWLogComparar.Create(&aLogId,&aLogAtividade,&aLogAtividadeId)
 
 //=====Apresenta Botão de comparação com posição atual=====
 ButtonCompararAtual.Visible = 1
EndEvent
Pronto, agora ao selecionar uma linha do nosso Grid de Logs, à direita irão aparecer todos os log existentes para esta mesma atividade e mesmo Id, com exceção daquele log selecionado. Vide imagem abaixo:

Genexus Web Component

3º Passo: Comparação entre dois logs selecionados.

Bom pessoal então, ao clicar sobre uma linha da Work With, irá ser criado um Web Component que contém somente um Grid praticamente idêntico, inclusive com as mesma propriedades. Esta Web Componente contém a Regra parm:
parm(in:&aLogId,in:&aLogAtividade,in:&aLogAtividadeId);
Os eventos:
Event Grid.Load
 //=====Variavel presente no grid de Log=====
 &bLogId = LogId
EndEvent

Event TrackContext(&bLogId)
 /*
 Ao selecionar linha chama Web Panel HistoricoComparacao levando as variáveis:
 &aLogId = recebida como parâmetro
 &aLogAtividade = recebida como parâmetro
 &bLogId = linha selecionado
 */
 HistoricoComparacao.Call(&aLogId,&bLogId,&aLogAtividade)
EndEvent
E as condições (referentes ao Grid):
//=====Não mostrar o mesmo Log para seleção=====
LogId <> &aLogId;

//=====Log de mesma Atividade=====
LogAtividade = &aLogAtividade;

//=====Logs do mesmo registro (Id)=====
LogAtividadeId = &aLogAtividadeId;

4º Passo: Criação da Web Panel de Comparação entre os logs selecionados em cada Grid.

Neste quarto e último passo, vamos receber as Ids dos log selecionados, ler o XML de cada um destes e por fim, mediante o tipo de variável XMLReader, vamos incluir no nosso SDT de comparação e mostrá-lo em tela.

Pode ter ficado um pouco confuso, mas vamos devagar, primeiro - receber as Ids através da regra parm:
parm(in:&aLogId,in:&bLogId,in:&aLogAtividade);
Após, adicionar o código em eventos (contendo a busca e leitura do XML e a inserção no SDT):
Event Start
 //=====Captura Campos do 1º Histórico selecionado=====
 for each
    where LogId = &aLogId
    &LogHistorico = LogHistorico
    &aLogDataHora = LogDataHora
    &aOperacao = LogOperacao.EnumerationDescription()
    &aUsuarioNome = UsuarioNome
 endfor
 do 'LeXML'
 
 //=====Captura Campos do 2º Histórico selecionado=====
 
 //=====Se NÃO FOR Posição Atual=====
 if not &bLogId.IsEmpty()
    for each
      where LogId = &bLogId
      &LogHistorico = LogHistorico
      &bLogDataHora = LogDataHora
      &bOperacao = LogOperacao.EnumerationDescription()
      &bUsuarioNome = UsuarioNome
    endfor
    ctlHistoricoB.Title = &bOperacao.Trim()+' - '+&bLogDataHora.ToString().Trim()
 
 //=====Se FOR Posição Atual=====
 else
    do 'PreencheSDT'
    &bUsuarioNome = ''
    ctlHistoricoB.Title = 'Posição Atual'
 endif

 ctlHistoricoA.Title = &aOperacao.Trim()+' - '+&aLogDataHora.ToString().Trim()
 do 'LeXMLComparativo'
 
 //=====Adiciona Usuários de cada Histórico=====
 &SDT_CompararItem = new()
 &SDT_CompararItem.Atributo = 'Realizado por'
 &SDT_CompararItem.HistoricoA = &aUsuarioNome
 &SDT_CompararItem.HistoricoB = &bUsuarioNome
 &SDT_Comparar.Add(&SDT_CompararItem)
EndEvent

Event Grid1.Load
 //=====Se linha do Histórico A for <> de Histórico B, pinta de amarelo=====
 if &SDT_Comparar.CurrentItem.HistoricoA <> &SDT_Comparar.CurrentItem.HistoricoB
    ctlAtributo.BackColor = RGB(255,255,1)
    ctlHistoricoA.BackColor = RGB(255,255,1)
    ctlHistoricoB.BackColor = RGB(255,255,1)
 endif
EndEvent

Sub 'PreencheSDT'
 //=====Verifica a Atividade para Capturar Chave Primária=====
 do case
    case &aLogAtividade = Atividade.Cliente
      &SDT_Cliente.FromXml(&LogHistorico)
      &SDT_Cliente = DP_Cliente.Udp(&SDT_Cliente.ClienteCod) 
      &LogHistorico = &SDT_Cliente.ToXml()
 endcase
EndSub

Sub 'LeXML'
 //=====Abre o documento XML de um atributo/variavel interna=====
 &XMLReader.OpenFromString(&LogHistorico)
 
 //=====Realizar a seguinte rotina enquanto não atingir o fim=====
 do while &XMLReader.EOF <> true
   &i += 1
  
   //=====Ler a próxima Tag=====
   &XMLReader.Read()
  
   //=====Captura o Nome do Elemento=====
   &ElementName = &XMLReader.Name
  
   //=====Captura o Valor do Elemento=====
   &ElementValue = &XMLReader.Value
  
   //=====Se não for as Tags de abertura/fechamento do SDT=====
   if not &ElementName like 'SDT_%'
   
     //=====Adiciona ao SDT - Grid=====
     &SDT_CompararItem = new()
     &SDT_CompararItem.Atributo = &ElementName
     &SDT_CompararItem.HistoricoA = &ElementValue
     &SDT_Comparar.Add(&SDT_CompararItem)
   endif
 enddo
 
 //=====Fecha a leitura do XML=====
 &XMLReader.Close()
EndSub

Sub 'LeXMLComparativo'
 //=====Abre o documento XML de um atributo/variavel interna=====
 &XMLReader.OpenFromString(&LogHistorico)
 
 //=====Realizar a seguinte rotina enquanto não atingir o fim=====
 do while &XMLReader.EOF <> true
   &i += 1
  
   //=====Ler a próxima Tag=====
   &XMLReader.Read()
  
   //=====Captura o Nome do Elemento=====
   &ElementName = &XMLReader.Name
  
   //=====Captura o Valor do Elemento=====
   &ElementValue = &XMLReader.Value
  
   //=====Se não for as Tags de abertura/fechamento do SDT=====
   if not &ElementName like 'SDT_%'
   
     //=====Adiciona ao SDT - Grid=====
     for &SDT_CompararItem in &SDT_Comparar
       if &SDT_CompararItem.Atributo = &ElementName
         &SDT_CompararItem.HistoricoB = &ElementValue
       endif
     endfor
   endif
 enddo
 
 //=====Fecha a leitura do XML=====
 &XMLReader.Close()
EndSub


quinta-feira, 18 de outubro de 2012

Certificação Genexus - Simulado Parte V

Bom pessoal após a Parte I, Parte IIParte III e Parte IV daremos continuidade ao nosso assunto sobre certificação Genexus, hoje iremos realizar mais 4 questões do nosso simulado.

Caso deseje esta prova em versão PDF, deixe seu email na parte de comentário que irei compartilhar com todo prazer!
Genexus Certificação

12. Considere uma aplicação Genexus para uma montadora de automóveis. A mesma conta a Transação Remessa para registrar as remessas despachadas para as locomotivas. Dado o seguinte desenho de transações, determine as tabelas bases dos for each que aparecem abaixo:

Genexus Certificação
       a) For each Externo {Remessa}, for each interno {RemessaCarro}
       b) For each Externo {Remessa}, for each interno {Carro}
       c) For each Externo {RemessaCarro}, for each interno {RemessaCarro}
       d) For each Externo {Remessa}, for each interno {Remessa}

Resposta: A - devemos verificar os atributos que estão definidos em cada for each. Para este atributos definidos, o Genexus irá buscar a menor tabela que os contenha. O for each externo contém 2 atributos que podem ser acessados por 2 tabelas, {Remessa} e {RemessaCarro}, a menor tabela que contém estes atributos é {Remessa}. Já o for each interno contém 2 atributos que podem ser acessados através da tabela base do for each externo, {Remessa}, logo a tabela base será {RemessaCarro}.
Obs. Se no for each interno tivéssemos os atributos LocomotivaId e LocomotivaNome, as tabelas bases seriam {Remessa} e {Locomotiva}, em virtude destes atributos não terem associação com os do for each externo.

13. Considere uma aplicação Genexus para uma montadora de automóveis. A mesma conta a Transação Remessa para registrar as remessas despachadas para as locomotivas. Dado seguinte desenho de transações, determine que tipo de for each é o seguinte:
Genexus Certificação
       a) JOIN
       b) Produto Cartesiano
       c) Break
       d) Nenhuma das anteriores

Resposta: C - for each aninhados são aqueles que contém ao menos um for each externo e um for each interno. Estes for each podem ter 3 tipos:
       JOIN: quando existe relação entre os dois for each, porém estes são de tabelas bases diferentes.
       Produto Cartesiano: não existe relação entre os dois for each.
       Break: quando, além de existir relação entre os dois for each, estes são de mesma tabela base.
Tanto a tabela base do for each externo quanto a do interno é {Remessa}. Em virtude disto, é realizado um Break.

14. Determine qual das seguintes afirmações sobre Data Provider é correta:
       a) O Data Provider é um objeto que nos permite processar dados de informações de forma estruturada
       (SDT, BC, etc.).
       b) O Data Provider é um objeto utilizado para atualizar a base de dados.
       c) Nenhuma das anteriores está correta.

Resposta: A - utilizamos o Data Provider para devolver dados estruturados, ao invés de uma procedure, isto, em função de sua facilidade de escritura e clareza. Porém este objeto por si só não realiza atualizações na base de dados.

15. Determine qual das seguintes afirmações sobre Business Component (BC) é correta:
       a) Um objeto BC permite invocar uma transação a partir do código Genexus como se estivesse sendo
       executado a partir de sua Web Form.
       b) Através do BC podemos atualizar a base de dados a partir de sua Web Form.
       c) Ao utilizar um BC, este não efetua um COMMIT sobre a base de dados e cabe ao programador a
       confirmação dos dados na base de dados.
       d) Todas as anteriores.

Resposta: D - um Business Component permite utilizar a lógica das transações (regras, eventos, controles de integridade) sem a necessidade de trabalhar diretamente com ela. Ou seja, pode ser utilizada em Web Forms.

quinta-feira, 11 de outubro de 2012

Genexus - Leitura de XML

A cerca de um mês visualizamos a partir de um post, a possibilidade de realizarmos um controle/histórico de dados da nossa aplicação. Para isto, foram utilizados objetos SDT, Data Provider, além de regras de transações. Como resultado, teremos o registro das alterações, exclusões e inserções de dados através de  de um XML.

A partir deste XML, podemos incrementar este histórico criado, e por que não, realizarmos um controle semelhante ao que o Genexus utiliza para os históricos dos objetos internos. Para quem não se recorda, quando realizamos alterações em qualquer objeto Genexus, este guarda um histórico da posição anterior a alteração, vide figura abaixo. A partir disso, podemos comparar duas posições e visualizar através de tracejados em verde, o que de fato foi alterado.

Genexus XML

No próximo post, iremos aprender como realizar a mesma comparação de históricos a partir daquele nosso XML gravado. Porém antes de tudo, é importante conhecermos um pouco sobre o XML e como realizar a sua leitura.

Então, a XML - eXtensible Markup Language ou Linguagem de Marcação Extensiva - assim como o nome diz, é uma linguagem de marcação, bem como a HTML. A diferença é que a HTML foi projetada para exibir dados, já a XML foi projetada para descrever dados. Enquanto a HTML possui tags pré-definidas (<img />, <br>), na XML é o usuário que define as próprias tags e a própria estrutura do seu documento. 

Esta linguagem não faz nada por si só, pode ser um pouco difícil de entender, mas ela não foi projetada para fazer algo, e sim para estruturar, armazenar e enviar informações. Acredito que atualmente seja a linguagem mais utilizada para a transmissão de dados, um bom exemplo é o próprio governo que a utiliza para as famosas NFe e CTe.

Basicamente um XML contém elementos e atributos, elementos descrevem dados enquanto atributos são como as propriedades dos elementos. Não existe uma regra que indique quando você deve usar um ou outro, veja o exemplo abaixo:
Genexus XML
Exemplo de XML

Utilização de elemento para definição de sexo da pessoa:
<pessoa>
    <sexo>feminino</sexo>
    <nome>Ana</nome>
</pessoa>

Utilização de um atributo para definição de sexo da pessoa:
<pessoa sexo="feminino">
    <nome>Ana</nome>
</pessoa>

Lendo XML através do Genexus

Bom agora vamos colocar estes conceitos para serem utilizados a partir do nosso mestre Genexus. Hoje iremos aprender como desenvolvemos a leitura de um determinado XML, para isto iremos utilizar o tipo de variável XMLReader. O XML a ser trabalhado será:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<MUSICAS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <MUSICA codigo="001" estilo="rock">
        <NOME>Maluco Beleza</NOME>
        <ARTISTA>Raul Seixas</ARTISTA>
    </MUSICA>
    <MUSICA codigo="002" estilo="samba">
        <NOME>Moleque Atrevido</NOME>
        <ARTISTA>Jorge Aragao</ARTISTA>
    </MUSICA>
    <MUSICA codigo="003" estilo="mpb">
        <NOME>Roda Viva</NOME>
        <ARTISTA>Chico Buarque</ARTISTA>
    </MUSICA>
</MUSICAS>
Esse XML acima foi inserido dentro de um arquivo .txt, e logo após, este arquivo foi renomeado para .xml. Agora, programando no Genexus, iremos abrir este arquivo, realizar a leitura de Tag por Tag, verificando se é uma Tag de abertura, para após, capturar os seus atributos (nome e valor) e as definições de cada elemento (nome e valor). Logo, dentro do evento Start digitaremos o seguinte:
//=====Abre o documento que contém o XML=====
&XMLReader.Open('C:\Temp\file.xml')
 
//=====Realizar a seguinte rotina enquanto não atingir o fim=====
do while &XMLReader.EOF <> true
  
 //=====Ler a próxima Tag=====
 &XMLReader.Read()
  
 //=====Tipo da Tag 1:Elemento 2:EndTag 4:Text 8:Comment=====
 &ElementType = &XMLReader.NodeType
  
 //=====Se a Tag for um elemento=====
 if &ElementType = 1
   
  //=====Captura o Nome do Elemento=====
  &ElementName = &XMLReader.Name
   
  //=====Captura Qtd de Atributos do Elemento=====
  &ContadorAtributos = &XMLReader.AttributeCount
   
  //=====Realizar rotina enquanto houver atributos não lidos=====
  for &i = 1 to &ContadorAtributos
    
   //=====Nome do Atributo=====
   &AttributeName = &XMLReader.GetAttributeName(&i)
    
   //=====Valor do Atributo=====
   &AttributeValue = &XMLReader.GetAttributeByIndex(&i)
  endfor
   
  //=====Captura o Valor do Elemento=====
  &ElementValue = &XMLReader.Value
 endif
enddo
 
//=====Fecha a leitura do XML=====
&XMLReader.Close()
Bom pessoal, este foi exemplo bem simples de uma leitura de um XML, pretendo retomar este assunto posteriormente e analisar um caso mais avançado, como um exemplo de nota fiscal eletrônica. Agradeço a leitura e bons negócios!

segunda-feira, 1 de outubro de 2012

Certificação Genexus - Simulado Parte IV

Bom pessoal após a Parte I, Parte II e Parte III, daremos continuidade ao nosso assunto sobre certificação Genexus, hoje iremos realizar mais 4 questões do nosso simulado.

Caso deseje esta prova em versão PDF, deixe seu email na parte de comentário que irei compartilhar com todo prazer!

8. Considere uma aplicação Genexus para uma montadora de automóveis. Dado o seguinte desenho das transações. Supondo que existe somente um País inserido no Banco de Dados com PaisId = 4. O que aconteceria se tentássemos inserir uma nova Marca com PaisId = 9.
Genexus Certificação
a) A nova marca é inserida e automaticamente se cria o País com o nome de país vazio.
b) O Genexus verifica a existência do país 9 na tabela Pais. Como não existe, emite uma mensagem de erro e a nova marca não é inserida.
c) A nova marca é inserida sem um país associado.
d) Nenhuma das anteriores.
Resposta: B - Dada o desenho das Tabelas, o atributo PaisId é chave primária da tabelas Pais e chave estrangeira da tabela Marca. Logo, não é possível que seja realizado inserções, alterações ou exclusões de registros da tabela Pais a partir de qualquer outra tabela. O Genexus realiza este controle automaticamente, e o informa, através de mensagens de alertas e erros!

9. Considere uma aplicação Genexus para uma montadora de automóveis. A mesma conta a Transação Remessa para registrar as remessas despachadas para as locomotivas. A hora da remessa (RemessaHora) deve ser atribuída no exato momento em que a remessa é inserida. Se declara então, a seguinte regra na Transação Remessa, determine a opção correta:
Genexus Certificação
Genexus Certificação
a) A regra esta bem declarada porque: ao se executar antes do COMMIT e só no modo INSERT, a hora é gravada com o valor desejado.

b) A regra esta mal declarada porque: embora ela seja executada antes do COMMIT, o registro do cabeçalho já foi gravado na base de dados.

c) A regra esta mal declarada porque: ela é executada uma vez para cada registro do segundo nível.

d) Nenhuma das anteriores.
Resposta: B - A regra deve ser declarada de ser uma das seguintes:

RemessaHora = now() on BeforeInsert;

RemessaHora = now() if insert on AfterValidate;
pois estes eventos são os últimos antes da inserção dos dados do cabeçalho.

10. Considere uma aplicação Genexus para uma montadora de automóveis. A mesma conta a Transação Remessa para registrar as remessas despachadas para as locomotivas. Se deseja que, ao trabalhar com cada linha do detalhe da remessa (RemessaCarro), se execute o procedimento logRemessa que receberá como parâmetro o identificador da remessa.
Genexus Certificação
a) logRemessa.call(RemessaId);

b) logRemessa.call(RemessaId) on AfterComplete;


c) logRemessa.call(RemessaId) on AfterValidate;


d) logRemessa.call(RemessaId) on AfterValidate level CarroId;
Resposta: D - a letra "a" não possui evento de disparo. A letra "b" irá ocorrer somente uma vez após o commit dos dados. A letra "c" irá ocorrer somente uma vez após a validação dos dados do cabeçalho da transação. Já a letra "d" irá ocorrer após a validação de cada linha do detalhe da Remessa (RemessaCarro).

11. Considere uma aplicação Genexus para uma montadora de automóveis. A mesma conta a Transação Remessa para registrar as remessas despachadas para as locomotivas. É necessário emitir um relatório das remessas por locomotiva. Serão listadas somente aquelas locomotivas que têm alguma remessa realizada. Determine a implementação correta.


Genexus Certificação
Resposta: B - Como o objetivo é listar somente as Locomotivas que contém Remessas, não podemos iniciar nossa procura pela tabela de Locomotiva, mas sim pela tabela Remessa. Logo é necessário utilizar a cláusula defined by seguido de algum atributa desta tabela, para especificar a tabela base que iremos trabalhar.
----------------------------------------------------------------------------------------------------------

Siga o restante do simulado através dos links:

Deixe um comentário com o seu email e posso repassar o documento pdf que contém esta e mais 16 questões!