Fala galera!

Esse é mais um dos meus clássicos posts sobre APIs do Oracle. Chamei de clássicos pois não é o primeiro, hahá! Acho que é o segundo sobre APIs. Um clássico.

Enfim, hoje vamos ver uma API que já utilizei em muitos lugares onde trabalhei, pois sempre existe a necessidade de aplicar e/ou remover alguma retenção em alguns pedidos, de forma automática e através de customização.

Neste post vou abordar apenas como remover a retenção, usando a API abaixo:

-- Faz a chamada da API para liberação das retenções
OE_HOLDS_PUB.Release_Holds(p_api_version       => 1.0
                         , p_init_msg_list     => FND_API.G_TRUE
                         , p_commit            => FND_API.G_FALSE
                         , p_validation_level  => FND_API.G_VALID_LEVEL_NONE
                         , p_hold_source_rec   => r_hold_source_rec
                         , p_hold_release_rec  => r_hold_release_rec
                         , x_return_status     => w_return_status
                         , x_msg_count         => w_msg_count
                         , x_msg_data          => w_msg_data);

A Api é bem simples de usar. Para ficar ainda mais fácil, criei um script pronto para rodar, bastando apenas informar qual é o pedido. O programa irá buscar todas as retenções que o pedido possui e irá liberar uma por uma.

No exemplo, foi necessário setar o contexto para que funcione corretamente ao rodar fora do ambiente do EBS, inclusive tendo que setar, além da organização, também a responsabilidade e usuário logado. Conforme abaixo:

fnd_global.apps_initialize(15992, 50663, 660);
mo_global.set_policy_context(p_access_mode => 'S', p_org_id => 81);

Porém quando rodando dentro do EBS, não precisa nada disso acima.

Segue abaixo o código fonte do exemplo:

DECLARE
  
  w_return_status VARCHAR2(1);
  w_message_error VARCHAR2(4000);

  -------------------------------------------------------------------
  -- Gera um log no concorrente 
  -------------------------------------------------------------------
  PROCEDURE gera_log(p_log IN VARCHAR2) IS
  BEGIN
    --Fnd_File.Put_Line(Fnd_File.Output, to_char(SYSDATE, 'DD/MM/RRRR HH24:MI:SS')||': '||p_log);
    dbms_output.put_line(to_char(SYSDATE, 'DD/MM/RRRR HH24:MI:SS')||': '||p_log);
  END gera_log;

  -------------------------------------------------------------------
  -- Libera todas as retenções de uma Ordem, caso a ordem possua
  -- origem como SALDO OP
  -------------------------------------------------------------------
  PROCEDURE Libera_Retencoes_Pedido(p_header_id      IN NUMBER
                                  , x_return_status OUT VARCHAR2
                                  , x_message_error OUT VARCHAR2) IS
    
    -- Busca informações do pedido
    CURSOR c_header IS
    SELECT oeoh.order_number
         , oeos.name order_source_name
      FROM oe_order_headers_all oeoh
         , oe_order_sources     oeos
     WHERE oeoh.order_source_id = oeos.order_source_id
       AND oeoh.header_id       = p_header_id;
    
    -- Busca todas as retenções do pedido
    CURSOR c_holds IS
    SELECT hd.hold_id
         , hs.hold_entity_code
         , oh.header_id
         , hs.hold_source_id
         , hd.name hold_name
      FROM oe_order_holds_all  oh
         , oe_hold_sources_all hs
         , oe_hold_definitions hd
     WHERE oh.hold_source_id = hs.hold_source_id
       AND hs.hold_id        = hd.hold_id
       AND oh.released_flag  = 'N'
       AND oh.line_id        IS NULL
       AND oh.header_id      = p_header_id;
    
    r_header            c_header%ROWTYPE;
    r_hold_source_rec   OE_HOLDS_PVT.HOLD_SOURCE_REC_TYPE;
    r_hold_release_rec  OE_HOLDS_PVT.HOLD_RELEASE_REC_TYPE;
    w_count             NUMBER;
    
    w_return_status     VARCHAR2(1);
    w_msg_count         NUMBER;
    w_msg_data          VARCHAR2(32767);
    w_index             BINARY_INTEGER;
    
    E_ERROR             EXCEPTION;
    
  BEGIN
    
    x_return_status := 'S';
    x_message_error := NULL;
  
    -- Busca informações do pedido
    OPEN c_header;
    FETCH c_header INTO r_header;
    CLOSE c_header;
    
    -- Verifica se o pedido foi encontrado
    IF r_header.order_number IS NULL THEN
      x_return_status := 'E';
      x_message_error := 'Pedido com #ID '||p_header_id||' não foi encontrado';
      RETURN;
    END IF;
  
    -- Verifica se o pedido é elegível para o processo
    IF r_header.order_source_name != 'SALDO OP' THEN
      x_return_status := 'E';
      x_message_error := 'Pedido deve possuir origem "SALDO OP". O pedido informado ('||r_header.order_number||') possui origem "'||r_header.order_source_name||'"';
      RETURN;
    END IF;
    
    gera_log(RPAD('-', 100, '-'));
    gera_log('Iniciando processo de liberação de retenções para o pedido '||r_header.order_number);
    gera_log(RPAD('-', 100, '-'));
    
    w_count := 0;
    -- Percorre todas as retenções do pedido e libera todas elas
    FOR r_hold IN c_holds LOOP

      w_count := w_count + 1;
      
      BEGIN
        
        r_hold_source_rec := NULL;
        r_hold_source_rec.hold_id              := r_hold.hold_id;
        r_hold_source_rec.hold_entity_code     := r_hold.hold_entity_code;
        r_hold_source_rec.hold_entity_id       := r_hold.header_id;
        --
        r_hold_release_rec := NULL;
        r_hold_release_rec.hold_source_id      := r_hold.hold_source_id;
        r_hold_release_rec.release_reason_code := 'VALID_CONFIG'; -- FIXO
        r_hold_release_rec.release_comment     := 'Liberado pois SALDO OP não deve ter retenções aplicadas';
        
        gera_log('Liberando Retenção "'||r_hold.hold_name||'"');
        
        OE_MSG_PUB.Initialize ();
        
        -- Faz a chamada da API para liberação das retenções
        OE_HOLDS_PUB.Release_Holds(p_api_version       => 1.0
                                 , p_init_msg_list     => FND_API.G_TRUE
                                 , p_commit            => FND_API.G_FALSE
                                 , p_validation_level  => FND_API.G_VALID_LEVEL_NONE
                                 , p_hold_source_rec   => r_hold_source_rec
                                 , p_hold_release_rec  => r_hold_release_rec
                                 , x_return_status     => w_return_status
                                 , x_msg_count         => w_msg_count
                                 , x_msg_data          => w_msg_data);

        -- Verifica se a retencao foi liberada
        IF w_return_status = FND_API.G_RET_STS_SUCCESS THEN
          gera_log('  -> Retenção "'||r_hold.hold_name||'" liberada com sucesso');
        ELSE
          
          x_return_status := 'E';
          x_message_error := 'Erro ao liberar retenção "'||r_hold.hold_name||'" do Pedido "'||r_header.order_number||'". Erro ('||w_msg_count||'): ';
          
          gera_log('  -> '||x_message_error);
          
          -- Busca mensagens de erro
          IF w_msg_count > 0 THEN
            FOR w_index IN 1..w_msg_count LOOP
              w_msg_data := OE_MSG_PUB.get(p_msg_index => w_index
                                         , p_encoded   => 'F');
              
              gera_log('  -> '||w_index||' - '||w_msg_data);
              
              -- Valida para nao estourar o campo
              IF Length(x_message_error||w_msg_data) <= 4000 THEN
                x_message_error := x_message_error || w_msg_data;
              END IF;

            END LOOP;
          END IF;
          
          RAISE E_ERROR;
        END IF;
        
      EXCEPTION
        WHEN E_ERROR THEN
          RAISE E_ERROR;
        WHEN OTHERS THEN
          x_return_status := 'E';
          x_message_error := 'Erro ao liberar retenção "'||r_hold.hold_name||'" do Pedido "'||r_header.order_number||'". Erro: '||SQLERRM;
          gera_log(x_message_error);
          RAISE E_ERROR;
      END;
    
    END LOOP;
    
    gera_log(RPAD('-', 100, '-'));
    IF w_count > 0 THEN
      COMMIT;
      gera_log('Liberadas '||w_count||' retenções para o pedido "'||r_header.order_number||'"');
    ELSE
      gera_log('Nenhuma retenção encontrada para o pedido "'||r_header.order_number||'"');
    END IF;
    
  EXCEPTION
    WHEN E_ERROR THEN
      ROLLBACK;
    WHEN OTHERS THEN
      x_return_status := 'E';
      x_message_error := 'Erro ao liberar retenções do Pedido com #ID '||p_header_id||'. Erro: '||SQLERRM;
  END Libera_Retencoes_Pedido;
  
BEGIN
  
  -- IMPORTANTE APENAS QUANDO RODANDO FORA DO EBS
  fnd_global.apps_initialize(15992, 50663, 660);
  mo_global.set_policy_context(p_access_mode => 'S', p_org_id => 81);
  --
 
  -- Libera todas as retenções do pedido
  Libera_Retencoes_Pedido(p_header_id     => 2748543 -- HEADER_ID do Pedido
                        , x_return_status => w_return_status
                        , x_message_error => w_message_error);
  
  IF w_return_status != 'S' THEN
    gera_log(RPAD('-', 100, '-'));
    gera_log('FINALIZADO COM ERRO: '||w_message_error);
  END IF;
  
END;

Se foi útil, ou se você apenas gostou, peço que compartilhe com seus contatos, poderá ser muito útil para eles.
Qualquer dúvida comenta aqui no blog.

Grande Abraço