sexta-feira, 15 de março de 2013

Como submeter, aguardar e verificar o status dos Concorrentes via Código

Olá!

Hoje vamos falar um pouco de Oracle Concurrents. Os Concurrents, também chamados de Concorrentes, por nós Brazucas, são transações específicas dentro Oracle EBS (Oracle E-Business Suite, popularmente chamado de Application), com o objetivo de executar determinadas tarefas de forma organizada e lógica. Eles podem obedecer a uma hierarquia e a uma sequência de execução. Os concorrentes são cadastrados como programas dentro do EBS, onde é possível, inclusive, definir uma série de parametrizações e formas de execução. Eles também podem ser agrupados para execução em conjunto, inclusive interagindo-se entre si. As execuções são realizadas por uma tela de gerenciamento de execução, onde de lá, chamamos determinado concorrente cadastrado e submetemos o mesmo à execução. Através desta tela, podemos acompanhar o status de execução e algumas informações como saídas e logs de erro. Também podemos executar um concorrente através de uma opção de menu, o que é comum em alguns casos. Contudo, o foco deste post não é entrar em detalhes sobre como são cadastrados e definidos os concorrentes dentro do EBS. Para isto sugiro consultar a documentação do Oracle E-Business Suite. O foco aqui é demonstrar como executar um concorrente via código, de dentro de uma PROCEDURE, PACKAGE ou FORMS, por exemplo. Apenas para constatar, além dos objetos de banco de dados, também podemos executar concorrentes através de Forms, Reports ou arquivos externos, como por exemplo, arquivos com extensão SQL.

Abaixo segue o pacote para a execução de um concorrente. Conforme, falei, precisamos definir algumas informações e parametrizações para que a execução possa ser realizada com sucesso.

w_request_id := fnd_request.submit_request( application IN varchar2
                                           ,program     IN varchar2
                                           ,description IN varchar2 default NULL
                                           ,start_time  IN varchar2 default NULL
                                           ,sub_request IN boolean  default FALSE
                                           ,argument1   IN varchar2 default CHR(0)
                                           ...
                                           ,argumentNN  IN varchar2 default CHR(0));

Conforme pode ser visto a cima, o pacote é o FND_REQUEST e a função é a SUBMIT_REQUEST. Esta função retorna o REQUEST_ID (no exemplo, recebido pela variável W_REQUEST_ID), que é o número da solicitação (ID do concorrente, como nós chamamos). Caso o pedido de execução do concorrente tenha ocorrido com sucesso, a função retornará o ID gerado pela submissão. Caso contrário, ele retornará 0 (zero). Note que este retorno não diz repeito ao status da execução propriamente dita do concorrente, ele é referente a submissão de execução, ou seja, diz respeito ao seu start. Se o Oracle conseguiu iniciar a execução, isto é tido como sucesso, e, portanto, é gerado um ID de solicitação para então prosseguir para a execução.
Além dos parâmetros que podem ser definidos pelo usuário, existem outros que são nativos e requeridos, que devem ser informados para que o start da execução tenha sucesso. São eles:

- Application: Short Name (apelido) da aplicação, por exemplo, AR, PO, SQLAP, etc. Ele vai variar dependendo de qual aplicação origem você deseja executar o concorrente. Por exemplo, se você estiver executando um concorrente do AR e o mesmo estiver configurado para este módulo, é necessário verificar qual é o Short Name do AR. Lembrando, que um concorrente cadastrado no EBS, está ligado a uma aplicação. Este apelido, você pode encontrar no cadastro de aplicações no Oracle EBS, pelas responsabilidades de administração e desenvolvimento do sistema.

- Program: Nome abreviado do concorrente. Quando cadastramos a definição do concorrente, temos que criar um nome abreviado para o mesmo. É este nome que devemos informar neste parâmetro.

- Description: Nome que irá aparecer na janela de solicitações de concorrentes, quando o mesmo for submetido. Caso não seja informado um (o padrão é deixar nulo), ele pegará o nome cadastrado na definição do concorrente. (default NULL)

- Start_time: Indica a hora de início da solicitação. Deixando como nulo caracterizará execução imediata. (default NULL)
- Sub_request: Indica a execução como sendo uma execução filha de outra. (default FALSE)

- Argument1: Primeiro parâmetro da execução. Se o concorrente contiver parâmetros para execução, é aqui que são informados. (default CHR(0))

- ArgumentNN: Último parâmetro, tipo ARGUMENT, no total de 100, que podemos utilizar. (default CHR(0)

Note que todos os parâmetros são do tipo IN, ou seja, de entrada.


Considerações sobre os parâmetros (Arguments):


Como eles possuem valores padrões em suas definições, os chamados valores Default, não necessitamos informar os 100 parâmetros, caso os mesmos não sejam utilizados. Contudo, levando em conta minha experiência em desenvolvimento, já houve casos de problemas na execução, se estes valores padrões não fossem informados. Desta forma, fica a dica. Caso algum erro esteja acontecendo e tudo já foi verificado, pode ser o momento de testar coisas imagináveis, como por exemplo, esta. Por via das dúvidas, sempre informo ;-p. Veja como ficaria a chamada, informando o todos os parâmetros:

w_request_id := fnd_request.submit_request
( 'INV'
 ,'INV'
 ,null
 ,null
 ,false
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
 ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
); 

No total, a chamada da função totaliza 105 parâmetros.

ATENÇÃO: Outro fator importante que deve ser considerado é que determinados concorrentes, principalmente, os nativos (se diz nativos, aqueles que são padrões do EBS, e não os customizados), podem necessitar de valores de determinadas variáveis de ambiente, ou variáveis locais para funcionar. Desta forma, quando você executa um concorrente nativo via código, através de um objeto customizado, por exemplo, estas variáveis podem não estar visíveis, podendo ocasionar um erro, não permitindo que o concorrente seja submetido. Caso isto aconteça, podemos simular o ambiente do EBS, configurando algumas varáveis.
Para mais detalhes sobre estas configurações, veja o artigo “Simulando sessão Oracle Application em Ferramentas de acesso a Banco de Dados”, neste blog.


Verificando Status do Concorrente:


Dentro do pacote FND_CONCURRENT há funções e procedimentos que podem ser úteis quando estamos manipulando concorrentes, e uma destas utilidades é a verificação do status ou da fase de um concorrente, em um determinado momento da execução, sendo durante ou após término da mesma. Veja a chamada a seguir:

w_request_status := fnd_concurrent.get_request_status( request_id      IN OUT NOCOPY number,
                                              ,appl_shortname  IN varchar2 default NULL,
                                             ,program         IN varchar2 default NULL,
                                             ,phase           OUT NOCOPY varchar2,
                                             ,status          OUT NOCOPY varchar2,
                                             ,dev_phase       OUT NOCOPY varchar2,
                                             ,dev_status      OUT NOCOPY varchar2,
                                             ,message         OUT NOCOPY varchar2);

Esta função, que retorna true ou false, possui parâmetros de saída e de entrada. Veja o significado de cada um deles:

Parâmetros de Entrada (IN):

- Request_id : ID do Concorrente que deve ser verificado. Obs. Este parâmetro também é de saída (OUT).
Obs.: Se a informação referente a aplicação (appl_shortname) e ao programa (Program) é passado como parâmetro, o ID do Concorrente mais recente para este programa é devolvido juntamente com o estado e fase.

- Appl_shortname: É referente a Aplicação o qual o programa pertence.
- Program: É referente ao nome do programa. Os parâmetros Appl_shortname e Program são usados somente se o ID do Concorrente não for fornecido.

Parâmetros de Saída (OUT):

- Phase: Retorna a Fase referente a execução do concorrente, no formato display, como por exemplo, “Em Execução” ou “Concluído” (depende da linguagem).

- Status: Retorna o Status referente a execução do concorrente, no formato display, como por exemplo, “Normal” (depende da linguagem).

- Dev_phase: Retorna a Fase referente a execução do concorrente, no formato código, como por exemplo, “RUNNING” ou “COMPLETE” (utilizado para comparações e verificações universais em programas).

- Dev_status: Retorna o Status referente a execução do concorrente, no formato código, como por exemplo, “NORMAL” (utilizado para comparações e verificações universais em programas).

- Message: Mensagem de conclusão do concorrente. Por exemplo, “Conclusão normal” (depende da linguagem).

Abaixo, um exemplo de chamada:

w_request_status := fnd_concurrent.get_request_status( w_request_id
                                                      ,null
                                                      ,null
                                                      ,v_phase
                                                      ,v_status
                                                      ,v_dev_phase
                                                      ,v_dev_status
                                                      ,v_message);


Aguardando a conclusão...:


Quando um concorre é submetido através de código, o pacote envia a solicitação e libera o objeto que está submetendo, para continuar sua sequencia de execução. Contudo, dependendo da necessidade, pode-se querer esperar o término da execução do concorrente, para que seja possível tomar alguma ação mediante o status da execução. Para isto, podemos utilizar o pacote FND_CONCURRENT.WAIT_FOR_REQUEST. Este pacote faz com que o objeto chamador aguarde pelo término da execução do concorrente. A chamada deste pacote deve ser realizada após a submissão do concorrente, pela chamada SUBMIT_REQUEST e após se certificar que o concorrente foi submetido (através do retorno do ID do concorrente vindo da função). Outro detalhe, a chamada ao WAIT_FOR_REQUEST, deve ser precedida de um COMMIT. Veja o exemplo abaixo:

...
if not fnd_concurrent.wait_for_request(w_request_id, 2, 0, v_phase, v_status, v_dev_phase,    v_dev_status, v_message) then
    raise_application_error(-20001, v_message);
else
  if v_dev_status not in ('NORMAL', 'WARNING')  then
    raise_application_error(-20001, v_message);
  end if;
end if;
...

Note no exemplo acima, que através do parâmetro de retorno V_DEV_STATUS, conseguimos saber com qual status o concorrente finalizou. Lembrando, que a chamada WAIT_FOR_REQUEST só libera a continuação da execução do objeto chamador, após o término da execução do concorrente ou após um tempo que pode ser definido na chamada desta função.

Além dos parâmetros referentes ao Status do concorrente, esta função, que retorna true ou false, também possui outros parâmetros de entrada e saída. Veja o significado de cada um deles:

w_request_wait := wait_for_request( request_id IN number default NULL
                               ,interval   IN number default 60
                               ,max_wait   IN number default 0
                               ,phase      OUT NOCOPY varchar2
                               ,status     OUT NOCOPY varchar2
                               ,dev_phase  OUT NOCOPY varchar2
                               ,dev_status OUT NOCOPY varchar2
                               ,message    OUT NOCOPY varchar2);


Parâmetros de Entrada (IN):

- Request_id: ID do Concorrente que deve ser monitorado, ou seja, esperar a conclusão.

- Interval: Frequência da verificação de término do concorrente (padrão 60 segundos).

- Max_wait: Quantidade máxima de espera (em segundos) para a conclusão do concorrente (coloque 0 para espera infinita).

Parâmetros de Saida (OUT):

- Phase: Retorna a Fase referente a execução do concorrente, no formato display, como por exemplo, “Em Execução” ou “Concluído” (depende da linguagem).

- Status: Retorna o Status referente a execução do concorrente, no formato display, como por exemplo, “Normal” (depende da linguagem).

- Dev_phase: Retorna a Fase referente a execução do concorrente, no formato código, como por exemplo, “RUNNING” ou “COMPLETE” (utilizado para comparações e verificações universais em programas).

- Dev_status: Retorna o Status referente a execução do concorrente, no formato código, como por exemplo, “NORMAL” (utilizado para comparações e verificações universais em programas).

- Message: Mensagem de conclusão do concorrente. Por exemplo, “Conclusão normal” (depende da linguagem).

Segue um exemplo completo, implementando todos estes recursos:


declare
  --
  -- Variável para a chamada SUBMIT_REQUEST.
  w_request_id     integer;
  w_request_status boolean;
  w_nr_verificacao number;
  w_cancel_request boolean;
  --
  -- Variáveis para a chamada WAIT_FOR_REQUEST.
  v_phase       varchar2(20);
  v_status      varchar2(20);
  v_message     varchar2(150);
  v_dev_phase   varchar2(20);
  v_dev_status  varchar2(20);
  --
  -- Variáveis para simulação da sessão EBS.
  w_resp_appl_id varchar2(50);
  w_resp_id      varchar2(50);
  w_user_id      varchar2(50);
  w_org_id       varchar2(50);
  --
begin
  --------------------------------
  --Submete o processo concorrente
  --------------------------------
  w_request_id := fnd_request.submit_request( 'TGR'
                                             ,'TGR_GL_GERA_VIS_ORCATO_FUT_ALL'
                                             ,null
                                             ,null
                                             ,false
                                             ,'371' ,'N' ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                             ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                            );
  --
  -----------------------------------------------------------------------
  -- Verifica se foi submetido com sucesso.
  -- Se foi submetido com sucesso, W_REQUEST_ID terá o ID do concorrente.
  -- Caso contrário, ele terá 0 (zero).
  -----------------------------------------------------------------------
  if w_request_id = 0 then
    raise_application_error(-20001, 'Não foi possível submeter o concorrente !!!: '||w_request_id);
  else
    dbms_output.put_line('Concorrente gerado: '||w_request_id);
  end if;
  --
  commit; -- Sempre colocar quando usar wait_for_request.
  --
  ------------------------------------
  -- Verifica o Status do Concorrente.
  ------------------------------------
  w_request_status := fnd_concurrent.get_request_status( w_request_id
                                                        ,null
                                                        ,null
                                                        ,v_phase
                                                        ,v_status
                                                        ,v_dev_phase
                                                        ,v_dev_status
                                                        ,v_message);
  --
  -- --------------------------------------------------------------
  -- Entra no processo de espera pelo términco do concorrente.
  -- --------------------------------------------------------------
  w_nr_verificacao := 1;
  loop
    --
    ---------------------------------------
    -- Aguarda a conclusão com concorrente.
    ---------------------------------------
    if not fnd_concurrent.wait_for_request( w_request_id
                                           ,1 -- verifica após um 1 segundo (sleep).
                                           ,3 -- após o início da verificação, aguarda 3 segundos e encerra a espera.
                                           ,v_phase
                                           ,v_status
                                           ,v_dev_phase
                                           ,v_dev_status
                                           ,v_message) then
      --
      raise_application_error(-20001, v_message);
      --
    end if;
    --
    -- Após 3 verificações de espera, e o concorrente ainda não finalizou, cancela a execução.
    if w_nr_verificacao = 3 then
      -- ---------------------------------------------------------------------------------------
      -- Se depois de 3 verificações o concorrente ainda não concluiu, cancelamos o concorrente.
      -- ---------------------------------------------------------------------------------------
      w_cancel_request := fnd_concurrent.Cancel_Request( w_request_id
                                                        ,v_message);
      --
      dbms_output.put_line('O tempo de execução inspirou! ('||w_nr_verificacao||' verificações).');
      --
    end if;
    --
    exit when (v_dev_phase = 'COMPLETE');
    --
    w_nr_verificacao := w_nr_verificacao + 1;
    --
  end loop;
  --
  dbms_output.put_line('Mensagem: '||v_message);
  --
  -----------------------------------------
  -- Verifica se foi concluído com sucesso.
  -----------------------------------------
  if v_dev_status not in ('NORMAL', 'WARNING')  then
    dbms_output.put_line('Concorrente terminou com erro: '||v_status);
  else
    dbms_output.put_line('Concorrente terminou com o status: '||v_status);
  end if;
  --
end;


Observações Gerais:

Para que a execução via código funcione, o concorrente deve estar cadastrado no EBS, com seus parâmetros definidos (caso houver), e repeitar a sequência destes parâmetros na chamada SUBMIT_REQUEST, ou seja, no caso da chamada via código, a sequencia dos parâmetros deve ser igual a sequencia cadastrada na definição do concorrente do EBS.

O que deve ficar claro, também, é que os parâmetros definidos no cadastro do concorrente (no EBS) são os equivalentes Argument1 a ArgumentNN da função.

Outro ponto que deve ser observado, é que alguns parâmetros utilizados nas chamadas de funções e procedimentos têm a diretriz NOCOPY. Parâmetros deste tipo não podem receber valores diretamente na chamada. Nestes casos, precisamos declarar variáveis para receber ou enviar valores, e utilizar as mesmas nas chamadas dos objetos.

Falows!

sexta-feira, 8 de março de 2013

Em breve novos posts....

Pessoal,

Ando meio sumido, mas em breve volto com mais posts...

Abraço!

segunda-feira, 4 de março de 2013

E assim nasce mais um blog Oracle

Pessoal, segue mais uma fonte de conhecimento Oracle.
Nosso amigo Eduardo Schurtz, disponibilizou um blog sobre dicas, notícias, produtividade, lifehacking, caça aos bugs e tudo que se refere ao seu dia-a-dia no mundo Oracle EBS. Vale a pena conferir...

Boa sorte, Eduardo! Parabéns pela iniciativa!

http://eduardoschurtz.com/oracle/2013/02/e-assim-nasce-mais-um-blog-oracle/

quarta-feira, 7 de abril de 2010

Retorna registros randômicos entre um grupo de registros

Hi!

Abaixo segue um exemplo bem interessante onde dentro de um grupo de registros é escolhido um registro aleatório.  Note que além da função DBMS_RANDOM, são utilizadas as funções RANK e OVER.
Em nossa tabela exemplo, teremos os seguintes dados:

Tabela: teste_random

Nome    Numero

======  ======
Felipe  1
Felipe  2
Felipe  3
Thiago  1
Thiago  2
Thiago  3
Edna    1

Segue SCRIPT para a criação da tabela e INSERTs:

create table teste_random
( nome   char(6)
 ,numero char(1)
)
/
insert into teste_random
values
('Felipe','1')
/
insert into teste_random
values
('Felipe','2')
/
insert into teste_random
values
('Felipe','3')
/
insert into teste_random
values
('Thiago','1')
/
insert into teste_random
values
('Thiago','2')
/
insert into teste_random
values
('Thiago','3')
/   
insert into teste_random
values
('Edna','1')
/
COMMIT
/


Qual a idéia. Temos 3 registros para o nome “Felipe”, 3 para o nome “Thiago” e 1 registro para o nome “Edna”. Queremos que dentro de um determinado grupo de registros (grupos por nome) seja escolhido um registro aleatório. Exemplo, para o grupo “Felipe”, onde há três registros “Felipe, 1”, “Felipe, 2” e “Felipe, 3”, o programa deve escolher um destes três registros. E faça isso também para os grupos ”Thiago” e “Edna”. No caso do grupo referente ao nome “Edna”, só existe um registro, portanto, sempre vai retornar o mesmo. Quanto aos outros, para cada grupo, em cada execução ele deve trazer um registro aleatoriamente.

Segue o SELECT que fará isto:
select nome, numero
from (
      select nome, numero
            ,rank() over(partition by nome order by numero) rnk
      from   teste_random
     ) a
where  rnk = (select ceil(dbms_random.value(0,(select count(*) from teste_random te2 where te2.nome = a.nome))) from dual)
 


Segue algumas execuções:



Falows!

segunda-feira, 5 de abril de 2010

Parâmetros tipo Data e Numérico vindos do EBS

Opa!


Quando trabalhamos com datas e números, sempre temos que prestar a atenção como estes dados estão chegando ao programa. É comum acontecer os famosos erros de formato referentes a números ou datas inválidas, principalmente, quando estamos construindo um determinado programa onde temos que passar estes valores para outros programas através de parâmetros.  Um problema muito comum acontece quando estamos trabalhando com concorrentes no EBS passando parâmetros para programas armazenados no banco. Segue abaixo os passos para solucionar estes problemas:


1) O primeiro passo é, quando for definir os parâmetros de um programa concorrente, colocar como listas de valores, as nativas do Oracle, FND_NUMBER e FND_STANDARD_DATE para os tipos NUMBER e DATE, respectivamente.

2) No seu programa armazenado em banco, numa PROCEDURE, por exemplo, crie os parâmetros que receberão os dados, declarando-os com o tipo VARCHAR2.

3) Dentro do seu programa utilize as funções abaixo para a conversão:


Exemplo 1 (utilização no corpo do programa):
...
  wvl_item number;
  wdt_hoje date;
  --
begin
  -- No caso de conversão para números.
  wvl_item := fnd_number.canonical_to_number(pvl_item); -- pvl_item: parâmetro do tipo varchar2.
  --
  -- No caso de conversão para data.
  wdt_hoje := fnd_date.canonical_to_date(pdt_entrega); -- pdt_entrega: parâmetro do tipo VARCHAR2.
end;


Exemplo 2 (utilização na área de declaração de variáveis):
...
  wvl_item number default fnd_number.canonical_to_number(pvl_item);
  wdt_hoje date   :=      fnd_date.canonical_to_date(pdt_entrega);
  --
begin
  ...
  ...
  ...
end;


O contrário também pode ser feito com a mesma função. Converter um numérico ou data para string:
...
  wvl_item varchar2(38);
  wdt_hoje varchar2(20);
  --
begin
  -- No caso de conversão para caracter.
  wvl_item := fnd_number.number_to_canonical(vl_item);
  --
  -- No caso de conversão para caracter.
  wdt_hoje := fnd_date.date_to_canonical(sysdate);
end;


O segredo destas funções é que as mesmas são específicas para o EBS, logo elas “sabem”, digamos assim, qual o formato que a suíte está trabalhando. Se você quiser saber quais são estes formatos, uma dica é verificar no LOG do concorrente as informações a respeito dos parâmetros passados para o concorrente no momento da execução, lá ele mostra cada parâmetro com seu respectivo valor informado. Note que ele não passa os valores no formato que escolhemos na janela de parâmetros do concorrente e sim no formato que ele está trabalhando em background.


Forte abraço!

sábado, 27 de março de 2010

Visualizando Perfis do EBS por Nível Hierárquico

Opa!

A seguir uma QUERY muito completa e interessante, onde ao informarmos uma string, ela pesquisa por todos os perfis correspondentes, mostrando seus valores em todos os níveis que o perfil existir. O % pode ser usado para tornar abrangente a pesquisa.

Segue script: http://www.ewginfo.com.br/askedu/profile_query.sql

Falows!

Configurando Informações de Impressão para um Concurrent (EBS) em Tempo de Execução

Opa!

Às vezes acontece a seguinte necessidade, temos um concorrente que chama um programa, por exemplo, uma PACKAGE, e esta, por sua vez, além de processar determinados dados, chama um ou mais concorrentes. Entretanto, algumas informações como, por exemplo, número de cópias para impressão, estilo de impressão e a própria impressora, podem ser mudados quando executamos um concorrente. Quando isto acontece precisamos levar estas novas configurações, escolhidas no momento da execução, para os concorrentes que serão executados pela PACKAGE. Abaixo segue um exemplo de como isto pode ser feito. Pense neste exemplo como sendo parte de um programa, que está sendo chamado através de um concorrente, onde este mesmo programa chamará outro concorrente.  Neste caso, precisamos passar as configurações escolhidas para ele, caso contrário ele utilizará as informações padrões, configuradas em seu cadastro. Fazemos isto através da função: FND_REQUEST.SET_PRINT_OPTIONS.

...
begin
  --
  -- Recuperando informações de impressão do concorrente corrente.
  --
  select printer
        ,number_of_copies
        ,print_style
  into   w_impressora
        ,w_num_copias
        ,w_estilo
  from   fnd_concurrent_requests
  where  request_id = fnd_global.conc_request_id;
  -- =======================================================================================
  -- Chamando função para configurar impressora, estilo e número de cópias.
  --
  w_conf_impres := fnd_request.set_print_options( printer   => w_impressora
                                                 ,style     => w_estilo
                                                 ,copies    => w_num_copias
                                                 );
  -- =======================================================================================
  --
  --
  -- Chamando Concurrent.
  wid_solicitacao := fnd_request.submit_request( 'ABC' -- short name da aplicação.
                                                ,'DEF' -- short name do programa.
                                                ,''
                                                ,''
                                                ,false
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0) ,chr(0)
                                                );
  --
  if wid_solicitacao = 0 then
    --
    fnd_file.put_line(fnd_file.log,'Não foi possível executar o concorrente DEF.');
    --
  else
    --
    fnd_file.put_line(fnd_file.log,'Concorrente DEF executado: '||wid_solicitacao);
    --
  end if;
  --
exception
  when others then
    fnd_file.put_line(fnd_file.log,'Erro ao executar concorrente DEF: '||sqlerrm);
end;
...


Forte abraço!

sexta-feira, 26 de março de 2010

Cadastrando um Perfil com Lista de Valores no EBS

Olá!

Hoje vamos ver como se cadastra um perfil no EBS e também agregarmos uma lista de valores a ele. Para cadastrarmos um perfil vamos acessar o EBS na responsabilidade “Desenvolvedor de Aplicações”, opção do menu, “Perfil”.  Abaixo segue um print com um exemplo de um perfil para guardar o código de uma retenção do OM.


Note que existem ali algumas informações que precisam ser cadastradas. Onde:

Nome: Um nome para a retenção. Este nome serve mais ou menos como código, portanto, recomendo colocar nomes simples, sem acento, espaço ou caracteres especiais.

Aplicação: Neste campo associamos a qual aplicação ele pertence. Como retenções fazem parte do OM, e nossa lista de valores também provém de dados desta aplicação, colocamos “Order Management”.

Nome de Perfil do Usuário: Aqui é colocado um nome breve, que apenas descreva com poucas palavras um descritivo referente ao perfil. OBS: É este o nome que vamos utilizar para pesquisar o perfil e cadastrar um valor para ele mais adiante.

Descrição: Neste campo colocamos uma descrição do que se trata o perfil. Aqui é o momento de colocar uma descrição que explique com mais detalhes o objetivo do perfil.

Data de Ativação: Aqui pode ser definida uma data Inicial e Final de ativação do perfil, ou seja, o período que ele estará ativo.

Validação SQL: Neste ponto fica interessante. É aqui que vamos colocar o SELECT que será a base para nossa lista de valores. Abaixo segue o código e seus detalhes:

SQL=" SELECT NAME,HOLD_ID
INTO  :visible_option_value,:profile_option_value
FROM  OE_HOLD_DEFINITIONS
WHERE (TRUNC(START_DATE_ACTIVE) <= TRUNC(SYSDATE)
      OR START_DATE_ACTIVE IS NULL)
AND   (TRUNC(END_DATE_ACTIVE) >= TRUNC(SYSDATE)
      OR END_DATE_ACTIVE IS NULL)
ORDER BY 1"
TITLE="Retenções"
HEADING="N"
COLUMN="NAME(100)"



No SELECT que utilizamos existem algumas informações que devem ser observadas. Temos a tag SQL, digamos assim, que recebe a nossa QUERY, propriamente dita. Note que em conjunto com ela, existe a cláusula INTO que vai receber os valores vindos do SELECT. Depois podemos definir um título através da tag TITLE, que será o título da lista de valores. Temos também as tags HEADING E COLUMN, que são utilizadas para definir se aparecerá a descrição da coluna na lista de valores e também definir o tamanho desta coluna, respectivamente. Para definir o tamanho da coluna você informa o nome da coluna referenciada no SELECT e entre parênteses o tamanho.

Tipo de Hierarquia: Neste ponto você escolhe os níveis de acesso por tipo de hierarquia. Sendo por acesso Local ou pela Aplicação, Responsabilidade, Servidor, Organização ou Usuário. Note que dependendo do tipo escolhido, o quadro “Nível de Acesso do Tipo de Hierarquia” vai apresentando as opções que podem ser configuradas. Geralmente, para nossas aplicações, utilizamos o tipo “Segurança”. Os níveis de hierarquia são utilizados para que você possa definir diversos valores e acessos em determinados pontos, como por exemplo, definir um valor a nível de usuário, de responsabilidade e assim por diante.

Acesso ao Usuário: Neste ponto você define se o usuário pode ou não visualizar o perfil e se poderá além de visualizar também alterá-lo.

Acesso ao Programa: Semelhante à definição realizada em Acesso ao Usuário, visto acima.

Agora, depois de cadastrado, vamos definir um valor para este perfil e verificar se nossa lista de valores foi criada de forma correta. Para isto acesse a responsabilidade “Administrador do Sistema”, opção do menu, “Perfil > Sistema”. A opção “Pessoal” serve para cadastrar o valor para o perfil, no usuário conectado. Caso você tenha habilitado o usuário para visualizar e/ou alterar, é por aqui que ele pode ser isto. Em outras responsabilidades também é possível fazer isto, através do menu “Editar > Preferências > Perfis”. Assim que clicarmos na opção “Sistema”, as telas abaixo são apresentadas:

 

O nível de hierarquia, ou seja, por onde o Oracle começa a procurar valores setados, segue da seguinte forma:

- Local
  - Servidor
     - Organização/Aplicação
        - Responsabilidade
         - Usuário


Seguindo esta hierarquia, o Oracle começa a verificar (debaixo para cima) onde pode existir um valor cadastrado. Exemplo, se não achar no Usuário, procura na Responsabilidade, se não achar na Responsabilidade, procura na Organização/Aplicação até chegar ao último nível.

Voltando ao nosso exemplo, na tela de localização de valores, deixe a opção Local marcada (já vem como default, senão marque) e no campo Perfil, próximo ao botão Localizar, preencha com o valor que inserimos no cadastrado do perfil, campo “Nome de Perfil do Usuário”. No nosso caso, o valor “Retençoes”. Depois disso clique no botão Localizar. Isto fará com que a tela de valores do perfil seja aberta. Posicione o cursor no campo Local. Note que dentro do campo aparece o botão típico de chamada para Lista de Valores. Veja como ficou nossa lista:

 

Neste exemplo cadastramos um valor para Local, mas poderíamos cadastrar para qualquer outro, como para Responsabilidade ou Aplicação. Basta marcar as caixas correspondentes e cadastrar os valores na tela, conforme print acima.

Obs.: Para definição de perfis a nível de Servidor e Aplicação, quando usados juntos, podem existir restrições. Acesse a documentação da Oracle para estar por dentro de mais detalhes.

Falows!

 

terça-feira, 23 de março de 2010

Gerando um Array de Datas

Hi!

Abaixo segue um jeito simples de gerarmos um array de datas através de um comando SELECT, e, diga-se de passagem, um jeito simples e esperto!

select (to_char (sysdate - 1 + level, 'dd-mon-rrrr'))    date_range
      ,(to_char (sysdate - 1 + level, 'month, dd rrrr')) date_word
from   dual connect by level <= 5 -- (número de dias a ser gerado)


Segue o resultado:


Contribuição: Romeu Schiessel Junior.

Abraço!

segunda-feira, 22 de março de 2010

Simulando sessão Oracle Application em Ferramentas de acesso a Banco de Dados

Hi!

Algumas vezes necessitamos executar programas ou SELECTS direto no banco de dados, ou seja, por fora do Aplicativo Oracle, através de ferramentas como SQL Navigator, SQL Tools, PL/SQL Developer ou outras ferramentas do gênero. Quase sempre, para VIEWS que são utilizadas no EBS, é necessário que o ambiente esteja com algumas variáveis “setadas” para que possamos visualizar os dados. Caso contrário, nossa QUERY ou programa não retorna nada. Segue abaixo um SCRIPT que sempre uso e que prepara o ambiente como se estivéssemos conectados no Oracle Applications. Ele funciona para 99% dos casos. Salvo outros procedimentos mais específicos que podem ocorrer dependendo do módulo e responsabilidade que desejamos acessar. Execute este SCRIPT na ferramenta que você estiver utilizando para acessar o banco de dados e substitua as varáveis: '&user_name' e '&responsibility_key' pelo nome do usuário e chave da responsabilidade, respectivamente. Este último você encontra no cadastro de responsabilidades no Administrado do Sistema.

declare
  p_application_id     number;
  p_responsibility_id  number;
  p_responsibility_key varchar2(200);
  p_user_id            number;
  p_user_name          varchar2(200);
  p_org_id             number;
begin
  --
  begin
    p_user_name := '&user_name';
    --
    select user_id
    into   p_user_id
    from   fnd_user
    where  user_name = p_user_name;
  exception
    when no_data_found then
      raise_application_error(-20001,'Usuário não encontrado: '||p_user_name);
    when others then
      raise_application_error(-20002,'Erro ao recuperar o id do usuário '||p_user_name||'. Erro: '||sqlerrm);
  end;
  --
  begin
    p_responsibility_key := '&responsibility_key';
    --
    select application_id
          ,responsibility_id
    into   p_application_id
          ,p_responsibility_id
    from   fnd_responsibility
    where  responsibility_key = p_responsibility_key;
  exception
    when no_data_found then
      raise_application_error(-20003,'Responsabilidade não encontrada: '||p_responsibility_key);
    when others then
      raise_application_error(-20004,'Erro ao recuperar o id da responsabilidade '||p_responsibility_key||'. Erro: '||sqlerrm);
  end;
  --
  begin
    fnd_client_info.setup_client_info( p_application_id
                                      ,p_responsibility_id
                                      ,p_user_id
                                      ,0);
  exception
    when others then
      raise_application_error(-20005,'Erro ao configurar variáveis de sessão (FND_CLIENT_INFO.SETUP_CLIENT_INFO). Erro: '||sqlerrm);
  end;
  --
  begin
    fnd_global.apps_initialize( p_user_id
                               ,p_responsibility_id
                               ,p_application_id
                               ,0);
  exception
    when others then
      raise_application_error(-20006,'Erro ao configurar variáveis de sessão (FND_GLOBAL.APPS_INITIALIZE). Erro: '||sqlerrm);
  end;
  --
  begin
    p_org_id := &p_org_id;
    --
    -- Para versão R12 do Oracle Applications (caso não seja, comente esta parte)
    mo_global.set_policy_context( p_access_mode  => 'S'
                                 ,p_org_id       => p_org_id);
  exception
    when others then
      raise_application_error(-20007,'Erro ao configurar variáveis de sessão (MO_GLOBAL.SET_POLICY_CONTEXT). Erro: '||sqlerrm);
  end;
end;


Obs.: Note que existe um adendo no código, para a versão R12 do Oracle Applications.

Falows!

sábado, 20 de março de 2010

Recuperar dados das Listas de Valores cadastradas no Oracle EBS

Opa!

Segue QUERY para recuperar os valores referentes às listas de valores cadastradas no Oracle EBS.

select b.flex_value
      ,t.description
from   fnd_flex_values_tl  t
      ,fnd_flex_values     b
      ,fnd_flex_value_sets s
where  b.flex_value_id     = t.flex_value_id
and    t.language          = userenv('LANG')
and    b.flex_value_set_id = s.flex_value_set_id
and    flex_value_set_name = &lista
and    trunc(sysdate)      between nvl(start_date_active, trunc(sysdate))
                           and     nvl(end_date_active, trunc(sysdate))
and    b.enabled_flag      = 'Y'
order  by t.description


Falows!

Como localizar arquivos gerados pelo Trace

Opa!

Quando queremos analisar o desempenho de um programa, utilizamos um processo chamado TRACE. O TRACE analisa a execução de um programa, fornecendo alguns dados para que possamos entender como o otimizador do banco de dados executou determinados comandos SQL que por ventura existam dentro do programa que esta sendo monitorado. Estes dados são guardados dentro de um arquivo com a extensão “.trc”, que fica gravado em um diretório do servidor. A QUERY abaixo pode ser utilizada para mostrar onde estes arquivos foram gerados e salvos. Basta informarmos o id da solicitação (id do concorrente), representado na QUERY por “&request”.

select 'Request id: '||request_id ,
       'Trace   id: '||oracle_Process_id,
       'Trace Flag: '||req.enable_trace,
       'Trace Name: '||dest.value||'/'||lower(dbnm.value)||'_ora_'||oracle_process_id||'.trc',
       'Prog. Name: '||prog.user_concurrent_program_name,
       'File  Name: '||execname.execution_file_name|| execname.subroutine_name ,
       'Status    : '||decode(phase_code,'R','Running') ||'-'||decode(status_code,'R','Normal'),
       'SID Serial: '||ses.sid||','|| ses.serial#,
       'Module    : '||ses.module
from   fnd_concurrent_requests req
      ,v$session               ses
      ,v$process               proc
      ,v$parameter dest
      ,v$parameter dbnm
      ,fnd_concurrent_programs_vl prog
      ,fnd_executables execname
where  req.request_id             = &request
and    req.oracle_process_id      = proc.spid(+)
and    proc.addr                  = ses.paddr(+)
and    dest.name                  = 'user_dump_dest'
and    dbnm.name                  = 'db_name'
and    req.concurrent_program_id  = prog.concurrent_program_id
and    req.program_application_id = prog.application_id
and    prog.application_id        = execname.application_id
and    prog.executable_id         = execname.executable_id


Embora, nosso exemplo esteja sendo focado para o Oracle Application, o comando TRACE pode ser utilizado para outros programas e comandos SQL que não fazem parte desta suíte de aplicativos.
 

Forte abraço!

Como extrair números de uma String de Caracteres

Bem pessoal,
Estes dias recebi esta dica de um amigo e achei muito interessante. Às vezes você precisa, dentro de um programa, extrair tudo que é número de uma string de caracteres e acha que para isto é necessário fazer um PL. Veja no exemplo abaixo, que com um simples SELECT foi possível fazer isto através do comando TRANSLATE.

select  translate(endereco, '1234567890', ' ') so_letras
       ,ltrim(translate(endereco, translate(endereco, '1234567890', ' ') , ' ')) so_numeros
from   (select '65 HG5IS 258 KS34 LKJ4 AS 21DF G AÇ K43 ' endereco
        from dual)


O comando TRANSLATE, pra quem não lembra, tem o objetivo de substituir ocorrências de um determinado conjunto, com relação a um segundo conjunto de caracteres. E é isso que acontece neste exemplo. Note que, na primeira coluna do SELECT o comando substitui tudo que é número, varrendo cada caracter da string contida na coluna ENDERECO, por espaço em branco. Com isto temos o resultado mostrando apenas os caracteres que não são números. Depois aplicamos novamente o comando TRANSLATE em cima deste resultado, mas agora, substituindo tudo que não é numérico, também por espaços em branco. No resultado final você tem números de um lado e os caracteres que não são números de outro.

É isso.
Abraço!

sexta-feira, 19 de março de 2010

Olá, Pessoal!


Infelizmente, com a experiência também vem a velhice e a memória vai ficando mais lenta. Para resolver este problema criei este blog... pra que mesmo? Ah! Lembrei...rs! Para postar dicas, truques e outros assuntos relacionados a tecnologia Oracle. Além de uma forma de consulta, também servirá para ajudar os amigos que se interessam por este assunto. Nos próximo dias estarei postando algo aqui. Fiquem a vontade para mandar sugestões de assuntos, críticas, ou seja, ajudar no crescimento do conhecimento. Forte abraço.

Eduardo Gonçalves