terça-feira, 15 de janeiro de 2013

Genexus - Envio de Email com Anexo

Essa matéria se propõem a analisar o método de envio de email com anexo adicionado, seja através de um caminho fixo do servidor, ou então a partir de uma variável blob. Esta variável, poderá por exemplo, vir de um atributo blob presente em alguma transação.

Trata-se de uma continuidade as tantas postagens a respeito deste assunto nos blogs da comunidade Genexus. Antes de continuar, sugiro uma leitura do post Genexus Mail, do excelente blog Genexando.
Para realizar este exemplo de envio de email, utilizarei 3 objetos Genexus: uma transação contendo os parâmetros de conexão com o host; uma web panel contendo três variáveis; e uma procedure.

Criação da Transação de Parâmetros

Geralmente quando iniciamos um projeto a transação de parâmetros estará presente na especificação do analista. É nesta transação que os dados de configurações do sistema serão registrados, e dentre estes registros possuímos os dados de conexão com o host smtp, responsável pelo envio de email através da aplicação.

Logo, nossa transação terá a seguinte estrutura:

Genexus Transação
Criação da Web Panel

Esta Web Panel criada não é essencial para o nosso exemplo, é apenas para demonstrar que poderemos passar o conteúdo deste email como parâmetro através de variáveis presentes em tela.

Então, apenas como exemplificação disto, adicionei na Form deste objeto três variáveis, além de outra que irei utilizar nos Eventos:
  1. (form) Assunto: VarChar(120);
  2. (form) Anexo: Blob;
  3. (form) TextoHTML: LongVarChar(2M);
  4. (eventos) SourceAnexo: VarChar(400);
Dessa forma, o usuário poderá determinar o Assunto e o Conteúdo da mensagem de email, além de anexar um documento. Ao clicar sobre o botão, o seguinte evento de usuário será executado:
Event Enter
//=====Captura o endereço gerado do documento anexado=====
&SourceAnexo = &Anexo.ToString()

//=====Chama Procedure de Envio de Email=====
EnviaEmail.Call(&Assunto,&TextoHTML,&SourceAnexo)
EndEvent
Criação da Procedure de Envio de Email

Por fim, precisamos programar a procedure que realizará o envio do email. Como este objeto não irá realizar gravação no banco de dados, podemos configurar a sua propriedade commit on exit, como "no".

Nesta procedure iremos receber os seguintes parâmetros (Rules):
parm(in:&Assunto,in:&TextoHTML,in:&SourceAnexo);
Estas variáveis recebidas possuem o mesmo DataType determinado na Web Panel anteriormente especificada.

Agora só nos falta programar os eventos, estes serão:
//=====Captura Dados de Conexão da Transação Parametros=====
for each
defined by ParametroId
//=====Host SMTP exemplo: smtp.live.com(outlook.com);
        //smtp.gmail.com(gmail.com)=====
&SMTPSession.Host = ParametroServidorSMTP.Trim()

//=====Autenticação: 1 (requer usuário e senha)=====
&SMTPSession.Authentication = ParametroAuthentication

//=====Dados de Login: Usuário e Senha=====
&SMTPSession.UserName = ParametroUserName.Trim()
&SMTPSession.Password = ParametroPassword.Trim()

//=====Remetente: Email e Nome=====
&SMTPSession.Sender.Address = ParametroSenderAdress.Trim()
&SMTPSession.Sender.Name = ParametroSenderName.Trim()
endfor

//=====Efetua o Login=====
&SMTPSession.Login()

//=====Verifica se ocorreu algum erro=====
if &SMTPSession.ErrCode <> 0
msg(&SMTPSession.ErrDescription)
else
//=====Insere o texto da mensagem=====
&MailMessage.HTMLText = &TextoHTML

//=====Insere o assunto da mensagem=====
&MailMessage.Subject = &Assunto

//=====Adiciona 1º Destinatário de email=====
&MailRecipient.Address = 'cicrano@hotmail.com'
&MailRecipient.Name = 'Cicrano'
&MailMessage.To.Add(&MailRecipient)

//=====Adiciona 2º Destinatário de email=====
&MailRecipient.Address = 'beltrano@outlook.com'
&MailRecipient.Name = 'Beltrano'
&MailMessage.To.Add(&MailRecipient)

//=====Adiciona email como Copia=====
&MailRecipient.Address = 'fulano@gmail.com'
&MailRecipient.Name = 'Fulano'
&MailMessage.CC.Add(&MailRecipient)

//=====Adiciona email como Copia Oculta=====
&MailRecipient.Address = 'genexus@outlook.com'
&MailRecipient.Name = 'Genexus'
&MailMessage.BCC.Add(&MailRecipient)

//=====Adiciona Anexo a partir de um caminho do servidor=====
&MailMessage.Attachments.Add('C:\Temp\VendaDiaria_20121217.csv')

//=====Adiciona Anexo a partir de uma variável Blob=====
if not &SourceAnexo.IsEmpty()
&MailMessage.Attachments.Add(&SourceAnexo)
endif

//=====Envia Email=====
&SMTPSession.Send(&MailMessage)

//=====Verifica se ocorreu erro=====
if &SMTPSession.ErrCode <> 0
msg(&SMTPSession.ErrDescription)
else
msg('Email enviado com sucesso!')
endif
endif
Observações

Duas observações a respeito deste código, o nome das variáveis são iguais aos seus tipos de dados. Por padrão a porta utilizada para o envio de email é a 25, normalmente utilizada pelos servidores SMTP. Caso seja necessário alterar esta porta, será preciso incluir o seguinte código antes de realizar o Login:
&SMTPSession.Port = 465

Pessoal, qualquer dúvida, incremento ou correção enviem através dos comentários ou pelo email genexus@outlook.com. Abraço.

sábado, 5 de janeiro de 2013

Genexus - Jogo da Velha

Lembro de um dia, em que ainda era um estagiário aprendendo a trabalhar com o Genexus, cada um tem sua própria história de como entrou nesse "mundo" e seria muito interessante escutar a de cada um, a minha um dia ainda conto.., mas nesse dia estava ocioso no meu canto da sala e pensei, será que seria possível realizar algum jogo a partir do Genexus??

É claro que nunca pensei em um jogo tipo mario ou call of duty hehehe, mas um jogo simples tipo aqueles de tabuleiro. Então nesse tal dia tentei realizar o jogo da velha... 

Bem, no fim, tirando a parte gráfica hahaha, consegui fazer um jogo da velha a partir de uma web panel usando variáveis bitmap e eventos de clique destas. Mas o melhor desse dia é que no fim disso tudo, consegui evoluir um pouco mais nos conhecimentos que tentava absorver.

Abaixo você poder ver uma pequena demonstração do resultado deste post:


Hoje vou passar um pouco disso pra galera que esta curiosa de saber.

Paint Brush - Desenhos

Bora lá, primeiro desenhei no Paint Brush mesmo, quatro desenhos:
  1. um quadrado com dimensões de 230x230px contendo o desenho clássico do jogo;
  2. um xis com dimensões de 66x66px;
  3. um círculo com dimensões de 66x66px;
  4. e uma tela branca com as mesmas dimensões de 66x66px;
Criação de nova classe Table

Após isso, iremos no Genexus criar uma nova classe de tabela, dentro do nosso tema trabalhado. A classe que criei, a nomeei de "TableFundoJogo", e nesta nova classe foram alteradas as seguintes propriedades:
        BackgroundRepeat: no-repeat
        Height: 230px
        Width: 230px
        BackgroundImagem: Fundo230 (nome da minha imagem de fundo)

Projetando nossa Web Panel 

Agora criaremos uma nova Web Panel (figura abaixo), iremos adicionar uma tabela de 3 Rows x 3 Columns. Esta tabela conterá a classe que criamos anteriormente, ou seja, já irá buscar suas propriedades definidas.

Genexus Web Panel

Nesta WebPanel iremos criar 21 variáveis, estas variáveis deverão ser apresentadas em Tela, na Form do objeto. As variáveis serão:
  1. Xis (Numeric(4)): placar do jogador da figura X;
  2. Circulo (Numeric(4)): placar do jogador da figura O;
  3. Contador (Numeric(4)): irá contar a quantidade de cliques realizados;
  4. um (Bitmap): variável posicionada na primeira célula da tabela;
  5. dois (Bitmap): variável posicionada na segunda célula da tabela;
  6. tres (Bitmap): variável posicionada na tereira célula da tabela;
  7. quatro (Bitmap): variável posicionada na quarta célula da tabela;
  8. cinco (Bitmap): variável posicionada na quinta célula da tabela;
  9. seis (Bitmap): variável posicionada na sexta célula da tabela;
  10. sete (Bitmap): variável posicionada na sétima célula da tabela;
  11. oito (Bitmap): variável posicionada na oitava célula da tabela;
  12. nove (Bitmap): variável posicionada na nona célula da tabela;
  13. umNome (Character(20)): irá reter o nome da imagem associada à variável um;
  14. doisNome (Character(20)): irá reter o nome da imagem associada à variável dois;
  15. tresNome (Character(20)): irá reter o nome da imagem associada à variável tres;
  16. quatroNome (Character(20)): irá reter o nome da imagem associada à variável quatro;
  17. cincoNome (Character(20)): irá reter o nome da imagem associada à variável cinco;
  18. seisNome (Character(20)): irá reter o nome da imagem associada à variável seis;
  19. seteNome (Character(20)): irá reter o nome da imagem associada à variável sete;
  20. oitoNome (Character(20)): irá reter o nome da imagem associada à variável oito;
  21. noveNome (Character(20)): irá reter o nome da imagem associada à variável nove;
Programando os Eventos

Bom, a idéia inicial é: teremos variáveis strings que irão controlar cada imagem do jogo, estão variáveis irão começar o jogo vazias, isto é sem xis e sem círculos. Por isso a quarta imagem criada no Paint (tela em branco) foi adicionada ao nosso projeto com o nome "Vazio". 

Como apenas 11 das 21 variáveis precisam ficar visíveis, as demais foram adicionadas dentro de uma outra tabela, e esta tabela nós deixamos invisível.
Event Start
//=====Inicializa variáveis nome da imagem como "Vazio"=====
&umNome = 'Vazio'
&doisNome = 'Vazio'
&tresNome = 'Vazio'
&quatroNome = 'Vazio'
&cincoNome = 'Vazio'
&seisNome = 'Vazio'
&seteNome = 'Vazio'
&oitoNome = 'Vazio'
&noveNome = 'Vazio'

//=====Inicializa contador de cliques e placar=====
&Contador = 0
&Xis = 0
&Circulo = 0

//=====Tabela com as variáveis de controle invisivel=====
TableVariaveis.Visible = 0
EndEvent
Agora, cada variável Bitmap irá conter um evento de Click. Neste evento iremos detectar se a sua variável de controle é "Vazio". Caso sim, iremos incrementar a variável de controles de cliques, e dividi-la por 2.

Se o resto desta divisão for 1, quem está clicando é o 1º jogador. Se o resto for igual a 0, quem está clicando será o segundo jogador.
Event &um.Click
//=====Se variável nao estiver definida (circulo ou xis)=====
if &umNome = 'Vazio'
//=====Controla nº de cliques=====
&Contador += 1

//=====Controla qual jogador clicou=====
if Mod(&Contador,2) = 1
&umNome = 'Xis'
else
&umNome = 'Circulo'
endif
endif
EndEvent
Bom, é no Evento Refresh que iremos utilizar o método "FromImage()", nesse caso, cada variável Bitmap esta recebendo como imagem a sua variável de controle. Esta variável de controle irá conter "Vazio" ou "Xis" ou "Circulo" (nome das variáveis adicionadas ao projeto).

Ainda neste evento, realizamos o controle de ganhador. Por exemplo, se o nome das variáveis de controle umNome, doisNome e tresNome forem iguais, algum jogador fechou a 1ª linha. Se houver ganhador a SubRotina "Fim" será realizada.
Event Refresh
//=====Define imagem para cada variável Bitmap=====
&um.FromImage(&umNome)
&dois.FromImage(&doisNome)
&tres.FromImage(&tresNome)
&quatro.FromImage(&quatroNome)
&cinco.FromImage(&cincoNome)
&seis.FromImage(&seisNome)
&sete.FromImage(&seteNome)
&oito.FromImage(&oitoNome)
&nove.FromImage(&noveNome)

//=====Controle se houve ganhador=====
do case
case &umNome <> 'Vazio' and &umNome = &doisNome and &umNome = &tresNome
&Ganhador = &umNome
do 'Fim'
case &umNome <> 'Vazio' and &umNome = &quatroNome and &umNome = &seteNome
&Ganhador &umNome
do 'Fim'
case &umNome <> 'Vazio' and &umNome = &cincoNome and &umNome = &noveNome
&Ganhador &umNome
do 'Fim'
case &doisNome <> 'Vazio' and &doisNome = &cincoNome and &doisNome = &oitoNome
&Ganhador = &doisNome
do 'Fim'
case &tresNome <> 'Vazio' and &tresNome = &seisNome and &tresNome = &noveNome
&Ganhador = &tresNome
do 'Fim'
case &tresNome <> 'Vazio' and &tresNome = &cincoNome and &tresNome = &seteNome
&Ganhador = &tresNome
do 'Fim'
case &quatroNome <> 'Vazio' and &quatroNome = &cincoNome and &quatroNome = &seisNome
&Ganhador = &quatroNome
do 'Fim'
case &seteNome <> 'Vazio' and &seteNome = &oitoNome and &seteNome = &noveNome
&Ganhador = &seteNome
do 'Fim'
endcase
EndEvent

Sub 'Fim'
//=====Mensagem de Fim de Jogo=====
msg('Fim de jogo, o '+&Ganhador.Trim()+' é o vencedor!')
//=====Marca Placar=====
if &Ganhador = 'Xis'
&Xis += 1
else
&Circulo += 1
endif

//=====Desabilita variáveis Bitmap=====
&um.Enabled = 0
&dois.Enabled = 0
&tres.Enabled = 0
&quatro.Enabled = 0
&cinco.Enabled = 0
&seis.Enabled = 0
&sete.Enabled = 0
&oito.Enabled = 0
&nove.Enabled = 0
EndSub
Abaixo, iremos adicionar os eventos dos botões "Novo Jogo" e "Zerar Placar":
Event 'NovoJogo'
//=====Inicializa variáveis nome da imagem como "Vazio"=====
&umNome = 'Vazio'
&doisNome'Vazio'
&tresNome'Vazio'
&quatroNome'Vazio'
&cincoNome'Vazio'
&seisNome'Vazio'
&seteNome'Vazio'
&oitoNome'Vazio'
&noveNome'Vazio'

//=====Inicializa contador de cliques e placar=====
&Contador = 0

//=====Habilita variáveis Bitmap=====
&um.Enabled = 1
&dois.Enabled = 1
&tres.Enabled = 1
&quatro.Enabled = 1
&cinco.Enabled = 1
&seis.Enabled = 1
&sete.Enabled = 1
&oito.Enabled = 1
&nove.Enabled = 1
EndEvent

Event 'ZerarPlacar'
//=====Zera variáveis do Placar=====
&Xis = 0
&Circulo = 0
EndEvent
Era isso pessoal, agora é só compilar e testar!! Abraço.

quinta-feira, 27 de dezembro de 2012

Genexus CSV - Parte II

Nessa segunda parte sobre criação e leitura de arquivos CSV, iremos visualizar como podemos realizar a leitura  de um arquivo exemplo (figura abaixo), criado anteriormente a partir do post Genexus CSV - Parte I.

Genexus CVS

Vamos imaginar que o nosso cliente contratou um novo software de frente de caixa, esse novo software oferece um relatório diário de todas as vendas realizadas na loja, e este relatório pode ser extraído no formato CSV. Em determinados períodos, o cliente precisará importar estes dados para o seu sistema gerencial.

Pois bem, agora precisamos criar em nossa aplicação uma tela que permita ao usuário importar o relatório desejado e gravar em nossa base de dados estas informações. Como faremos isso.. veremos a seguir..

Criação da Web Panel Importadora

Primeiro, iremos adicionar a variável &Blob à nossa web panel..

Genexus CSV


..e um botão "Importar Arquivo" que realizará o seguinte evento:
Event 'ImportarArquivo'
   //=====Chama Procedure de leitura passando o caminho da variável blob como parâmetro===
   LeArquivoCSV.Call(&Blob.ToString())
EndEvent

Ao utilizar uma variável do tipo blob os arquivos selecionados através desta variável são abertos a partir da pasta "PrivateTempStorage", definida nas propriedades do nosso gerador. Portanto, quando utilizamos a função "ToString()" estamos na verdade trabalhando com o caminho (source) do arquivo selecionado.

Criação de Procedure de Leitura dos Arquivos Importados

Agora precisamos programar nossa Procedure "LeArquivoCSV" criada.

Esta procedure irá receber como parâmetro o caminho (source) do arquivo importado na web panel.
//=====Variável Arquivo = Varchar, caminho do arquivo recebido=====
parm(in:&Arquivo);

Na aba Source da nossa Procedure iremos adicionar o seguinte código.

Obs.: Quando uma determinada variável Blob não é usada junto a algum registro da base de dados, não é possível capturar a sua extensão através da função "FileType()". Logo, para capturarmos a extensão desta variável, teremos que pegá-la através do seu caminho completo...
//=====Captura extensão do arquivo recebido como parâmetro=====
&PosicaoInicial = StrSearchRev(&Arquivo,'.',&Arquivo.Trim().Length())
&PosicaoInicial += 1
&Extensao = SubStr(&Arquivo,&PosicaoInicial,5)

//=====Se a extesão nao for csv, envia mensagem=====
if &Extensao.ToLower() <> 'csv'
msg('Arquivo Incorreto!')
else

//=====Abre Arquivo recebido como parâmetro=====
&retorno = dfrOpen(&Arquivo,,',','"','utf-8')

//=====Realizar a seguinte rotina enquanto não chegar ao fim do arquivo=====
do while dfrNext() = 0

//=====Leitura dos registros contidos=====
&retorno = dfrGNum(&LivroCodigo)
&retorno = dfrGTxt(&LivroNome)
&retorno = dfrGTxt(&LivroEdicao)
&retorno = dfrGNum(&LivroValor)
&retorno = dfrGTxt(&EditoraNome)
&retorno = dfrGDate(&NotaFiscalData,'dmy','/')
&retorno = dfrGTxt(&Hora)
&NotaFiscalHora.FromString(&Hora)
&retorno = dfrGNum(&NotaFiscalNSU)
&retorno = dfrGTxt(&PagamentoTipo)
&retorno = dfrGNum(&PagamentoId)
enddo

//=====Fechar arquivo=====
&retorno = dfrClose()
endif
A função StrSearchRev() serve para procurarmos a posição de um determinado caractere de trás para frente. Esta função recebe como parâmetros:

  1. String que desejamos realizar a procura - variável &Arquivo;
  2. Caractere(s) que estamos procurando - caractere ponto ".";
  3. Posição inicial da procura - fim do caminho do arquivo.

Note que não é possível capturarmos o registro hora de forma direta, o genexus não fornece uma função específica para este tipo de formato. Portanto, precisamos primeiro capturá-lo como uma String para após associá-lo a varíável hora (DateTime, propriedades: picture Date format = none).

Bom pessoal, pretendo postar mais alguns exemplos de desenvolvimento nos próximos posts. Bom ano novo pra todos, abraço!

segunda-feira, 17 de dezembro de 2012

Genexus CSV - Parte I

Dando continuidade aos nossos posts, a partir de hoje iremos aprender como criar e ler arquivos CSV. Quase todos os analistas genexus em algum momento já se depararam com a necessidade de trabalhar com este tipo de arquivos. Como sabem, assim como o XML, o CSV é muito utilizado para transmitir registros e informações, porém quando estes registros e informações são muito extensos, o CSV torna-se mais adequado.

Este tipo de arquivo é padrão de bancos, administradoras de cartões de crédito e sistemas ERP, entre outros. Como as transações ocorrem diariamente em uma grande quantidade, os bancos, por exemplo, disponibilizam estes arquivos diariamente, junto com um manual de leitura, e dessa forma, torna-se mais fácil às empresas realizar um programa de leituras destas informações e por fim, registrá-las em seu próprio sistema.

O que vem a ser este tipo de arquivo?

CSV significa Coma Separator Value, traduzindo: Valores Separados por Vírgula. De forma padrão um arquivo CSV, contém diversos valores, campos (ou colunas de tabelas), separados por vírgulas. Porém não necessariamente estes valores necessitam estar separados por este tipo de caractere (vírgula), através do genexus qualquer caractere que definirmos realizará esta separação, eu particularmente prefiro o ponto e vírgula. Principalmente quando um destes campos contém um valor (onde se utiliza a vírgula).

Exemplo de criação de arquivos CSV

Para começar este assunto, daremos continuidade ao nosso exemplo de uma aplicação para controle de uma livraria digital. Um novo ERP foi adquirido pela empresa, e precisamos criar um arquivo CSV diariamente com todas as vendas realizadas para que o ERP possa importá-las. Cada campo do CSV representará uma coluna da tabela de vendas, e cada linha representará uma venda, logo...

O nosso exemplo de arquivo contém:
  1. código do livro vendido;
  2. nome do livro vendido;
  3. edição;
  4. valor bruto;
  5. editora;
  6. data da venda;
  7. hora da venda;
  8. número único da transação;
  9. forma de pagamento;
  10. código de pagamento;
Genexus CSV

Vamos lá então, primeiro passo, em uma Web Panel inserimos uma variável Varchar(40) e um botão ao lado. Através desta variável, o usuário poderá determinar em qual pasta este arquivo será gerado. Veja figura abaixo:

Genexus Web Panel

Ao clicar sobre o botão o seguinte evento é executado:
Event 'GeraArquivo'
if not &Destino.IsEmpty()
GeraArquivoCSV.Call(&Destino)
else
msg('Informe o Destino do arquivo!')
endif
EndEvent
Agora, na procedure "GeraArquivoCSV" criada, iremos definir a propriedade "commit on exit: no".

Incluir em suas Regras o recebimento do parâmetro, variável Destino:
parm(in:&Destino);
E, em seu Source, o seguinte código:
//=====Captura Ano/Mes/Dia=====
&Ano = Year(ServerDate())
&Mes = Month(ServerDate())
&Dia = Day(ServerDate())

/*=====Monta Nome do Arquivo=====
O nome irá conter:
1º Caminho (pasta a ser gravado)
2º Nome do Arquivo (Data de Geração - Ano/Mes/Dia)
Exemplo: VendaDiaria_20121215
3º Extensão (.csv)
*/
&NomeArquivo = &Destino.Trim()+'VendaDiaria_'
&NomeArquivo += &Ano.ToString().Trim()+&Mes.ToString().Trim()+&Dia.ToString().Trim()
&NomeArquivo += '.csv'

/*=====Cria novo arquivo=====
Parâmetro:
1º Nome do Arquivo completo
2º Delimitador de registros (, - vírgula)
3º Delimitador de conteúdo (" - aspas duplas)
4º Anexar = false (caso exista outro arquivo com o mesmo nome, irá sobrescrever)
5º Encoding (utf-8)
*/
&retorno = dfwOpen(&NomeArquivo,',','"',0,'utf-8')

//=====Percorre tabela de notas fiscais====
for each NotaFiscalData NotaFiscalHora

/*Inserir registros (os delimitadores se inserem automaticamente)
quando utilizarmos "dfwPNum" precisamos informar um parâmetro: quantidade de decimais
quando utilizarmos "dfwPTxt" o ideal é utilizarmos a função .Trim()
quando utilizarmos "dfwPDate" precisamos informar dois parâmetros:
  1º formato da data, "d" para dia, "m" para mês e "y" para ano
  2º separador dos caracteres dia,mês e ano

os registros inseridos com "dfwPNum" e "dfwPDate", por não serem Strings não irão ficar entre aspas duplas "
*/
&retorno = dfwPNum(LivroCodigo,0)
&retorno = dfwPTxt(LivroNome.Trim())
&retorno = dfwPTxt(LivroEdicao.Trim())
&retorno = dfwPNum(LivroValor,2)
&retorno = dfwPTxt(EditoraNome.Trim())
&retorno = dfwPDate(NotaFiscalData,'dmy','/')
&retorno = dfwPTxt(NotaFiscalHora.ToString().Trim())
&retorno = dfwPNum(NotaFiscalNSU,0)
&retorno = dfwPTxt(PagamentoTipo.Trim())
&retorno = dfwPNum(PagamentoId,0)

//=====Ir para a próxima linha=====
&retorno = dfwNext()
endfor

//=====Fechar arquivo=====
&retorno = dfwClose()

Ao trabalhar com arquivos csv, utilizamos as funções

  • dfw...(Delimited File Write) - para escrever arquivos;
  • dfr...(Delimited File Read) - para ler arquivos;

Por hoje era isso, no próximo post entraremos na função de leitura de arquivos .csv, e para facilitar, continuaremos utilizando este mesmo exemplo. Grande abraço.

sábado, 8 de dezembro de 2012

Genexus Business Component - Parte II

Nesta segunda parte do assunto Business Component (acesse aqui a parte 1), iremos verificar como realizar rotinas de inserção através de Data Provider, além de atualizações e exclusões de registros. Se a utilização de BC já reduz as linhas de programação e facilita o desenvolvimento, a combinação deste com Data Provider facilita ainda mais.

Mas lembre-se, através de Data Provider só podemos realizar inserções através do Business Component. Veremos abaixo como realizar isto.

Inserção de registros através de Data Provider

Continuando com o exemplo da Parte 1, considere uma aplicação Genexus para uma livraria. Nesta livraria os livros são catalogados por Assunto, Editora e edição correspondente. A partir do seu Assunto cada livro recebe um código único.

Após definirmos o desenho da transação e declarar suas regras, definidos a propriedade "Business Component" como trueNeste código, os três primeiros dígitos é o código de seu assunto e os três últimos são sequenciais. Então, os livros do assunto "Negócios" (código 100), terão códigos de 100001 a 100999.
Livros

Para facilitarmos a inserção de novos livros, é criado uma Web Panel contendo um grid, com todos os livros registrados. Na última coluna da direita deste grid, inserimos uma imagem e criamos um evento associado a esta, com a opção de clonar este livro. Isto é, inserir um novo livro a partir dos dados do livro selecionado. Logo em nossa form teríamos:


Genexus Grid

Adicionamos a variável "Livro" que terá como Tipo de Dado o Business Component Livro. Agora, na aba de eventos desta Web Panel, iremos programar o evento associado ao clique da imagem "Clonar":
Event 'ClonarLivro'
//=====Chama o Data Provider passando o código do livro clicado como parâmetro=====
&Livro = DPLivro(LivroCodigo)

//=====Salva os Dados=====
&Livro.Save()

//=====Finaliza a UTL=====
commit

//=====Atualiza a página para aparecer o novo registro no grid=====
Refresh
EndEvent
Data Provider utilizado, a propriedade Output foi definida com o objeto Transação Livro. Os objetos Data Provider não possuem parâmetros de saída (out), este parâmetro é sempre definido a partir de suas propriedades, conforme abaixo:

Genexus Data Provider

Regra declarada:
parm(in:&LivroCodigo);
Podemos notar que o parâmetro recebido, id da tabela de Livros, serve como condição para capturar os dados referentes a este registro (where LivroCodigo = &LivroCodigo).

O atributo LivroCodigo e LivroDataCadastro não estão especificados no Data Provider em função de serem atribuídos a partir das regras da transação Livro. Isto é, o Business Component irá herdar estas regras (Regras especificadas na parte 1).

Atualização de registros através de Business Component

Imaginamos a seguinte situação, após determinados períodos, a nossa livraria necessita alterar o preço de todos os livros cadastrados, aumentando ou diminuindo 5% ou então 10%. Seria muito trabalhoso para o administrador da aplicação entrar em todos os livros e realizar esta alteração.

Logo, iremos inserir um campo de ajuste e um botão em nossa web panel para permitir ao administrador alterar todos os registros a partir de uma determinada porcentagem. Assim as mudanças da Form do objeto ficaram da seguinte forma:

Genexus Grid

Ao clicar sobre o botão o seguinte evento é realizado:
Event 'RealizarAjuste'
//=====Se valor informado não for vazio=====
if not &Ajuste.IsEmpty()

//=====Para cada linha do Grid=====
for each line in Grid

//=====Carrega BC com chave primária=====
&Livro.Load(LivroCodigo)

//=====Define novo valor do livro=====
&Livro.LivroValor = LivroValor * (1+(&Ajuste/100))

//=====Salva alteração e finaliza UTL=====
&Livro.Save()
commit
endfor

//=====Refresh após todos valores serem alterador=====
Refresh
else

//=====Se valor informado for vazio, exibir mensagem=====
msg('Informe a porcentagem de ajuste!')
endif
EndEvent
Note que ao realizar o Load, apenas passamos a chave primária, nos Business Components não precisamos passar todos os parâmetros recebidos pela transação, como o Modo (Update, Delete, Insert ou Display).

Exclusão de registros através de Business Component

Por fim, veremos como excluir registro através do BC.

Nossa seguinte demanda é, após algumas falhas de inclusões (um administrador novato tomou conta do sistema..hehe), precisamos facilitar a forma de exclusão dos livros. Caso se deseje excluir 100 livros, esta tarefa se torna muito trabalhosa, caso tenha que entrar de um em um. Logo, iremos inserir um check box na linha do grid, com a opção do usuário selecionar aquelas linhas que deseje excluir apenas clicando sobre um botão.

Nossa Form ficaria da seguinte forma:

Genexus Grid

Ao clicar sobre o botão "Excluir Registros Selecionados" o seguinte evento é realizado:
Event 'ExcluirRegistrosSelecionados'
//=====Para cada linha do Grid=====
for each line in Grid
if &Excluir = 'S'
//=====Carrega BC com chave primária=====
&Livro.Load(LivroCodigo)

//=====Exclui registro e finaliza UTL=====
&Livro.Delete()
commit
endif
endfor

//=====Refresh após todos valores serem alterador=====
Refresh
EndEvent
Bom gurizada, caso tenham alguma dúvida perguntem nos comentários, não há necessidade de se identificar. Forte Abraço.