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
Depois vou precisar do seu help também para “aplicar um hold” automaticamente, vis script…. rs
Se puder me contatar pelo e-mail, te agradeço.
Opa, faz um certo tempo que não mexo mais muito com EBS. Mas se puder ajudar irei. Manda tua dúvida lá no contato do site mesmo que respondo o email.
Genilto, muito obrigado.
Você salvou a minha vida !!!! rs
Parabéns.
Conhecia a API mas não sabia muito bem como usá-la.
O seu script foi 1000
Parabens e mais uma vez Muito Obrigado pelo seu post
Boa!! Que bom que ajudou!
Pingback: Oracle EBS – Liberando Retenções – API do Oracle (OE_HOLDS_PUB.Release_Holds) – Fragmentoweb