Complete WIP Job via External Application (APEX Integration)

Introduction/ Issue:  Completing a WIP job in EBS usually involves multiple manual steps. Integrating with external systems like APEX requires an automated and reliable method to complete jobs programmatically.

A custom PL/SQL API was created to allow external applications to complete WIP jobs, including material transactions, operation-level completions, and inventory updates

Why we need to do / Cause of the issue:

  • Automate WIP completion from external systems
  • Ensure inventory and costing accuracy
  • Enable real-time updates without EBS manual intervention
  • Support bulk and high-volume operations

 

How do we solve:

APEX or other external systems can call this API to complete jobs in EBS automatically, making the entire WIP lifecycle seamless between external apps and Oracle EBS.

CREATE OR REPLACE PACKAGE APPS.xx_wip_job_pkg AS

 

PROCEDURE Complete_job (

p_org_code             IN       VARCHAR2,

p_job_name             IN       VARCHAR2,

p_assembly_item_code   IN       VARCHAR2,

p_subinventory_code   IN       VARCHAR2,

p_quantity            IN       NUMBER,

p_message              OUT      VARCHAR2

);

END xx_wip_job_pkg;

/

CREATE OR REPLACE PACKAGE BODY APPS.xx_wip_job_pkg

AS

 

PROCEDURE complete_job (

p_org_code             IN       VARCHAR2,

p_job_name             IN       VARCHAR2,

p_assembly_item_code   IN       VARCHAR2,

p_subinventory_code    IN       VARCHAR2,

p_quantity             IN       NUMBER,

p_message              OUT      VARCHAR2

)

IS

l_org_id               NUMBER;

l_rm_qty               NUMBER;

l_wip_entity_id        NUMBER;

l_rm_item_id           NUMBER;

l_assembly_item_id     NUMBER;

l_uom_code             VARCHAR2 (30);

l_interface_id         NUMBER;

—  := inv.mtl_transactions_interface_s.NEXTVAL;

l_request_id           NUMBER;

l_tot_qty              NUMBER;

l_user_id              NUMBER;                         —      := 7616;

— Replace with your actual user_id

l_resp_id              NUMBER;                          —    := 20560;

— Replace with your responsibility_id

l_appl_id              NUMBER;                           —     := 706;

— Replace with your application_id (usually WIP = 401)

l_transaction_type     NUMBER;

l_transaction_action   NUMBER;

l_source_code          VARCHAR2 (50);

l_phase                VARCHAR2 (100);

l_status               VARCHAR2 (100);

l_dev_phase            VARCHAR2 (100);

l_dev_status           VARCHAR2 (100);

l_message              VARCHAR2 (4000);

l_sleep_seconds        NUMBER          := 5;   — Check every 5 seconds

l_timeout_seconds      NUMBER          := 300;

— Timeout after 5 minutes (optional)

l_start_time           DATE            := SYSDATE;

l_success              BOOLEAN;

v_remaining_qty        NUMBER;

v_used_qty             NUMBER;

l_group_id             NUMBER          := TO_CHAR (SYSDATE, ‘ddhhmmss’);

l_first_operation      NUMBER;

l_exists               NUMBER;

l_item_id              NUMBER;

v_parent_req_id        NUMBER;

—         := 69157192;   — ITM request id

v_worker_req_id        NUMBER;

v_phase                VARCHAR2 (1);

v_status               VARCHAR2 (1);

v_counter              NUMBER          := 0;

v_max_wait_loops       NUMBER          := 120;

— 120 x 10s = 20 min max wait

l_shelf_life_days      NUMBER;

l_operation_seq_num    NUMBER;

l_scrap_qty            NUMBER;

BEGIN

DBMS_OUTPUT.put_line (‘Start ‘);

DBMS_OUTPUT.put_line (‘Inside IF ‘);

get_initialization (l_user_id, l_appl_id, l_resp_id, p_message);

–l_user_id := 7616;

 

IF p_message = ‘SUCCESS’

THEN

NULL;

ELSE

RETURN;

END IF;

 

— MAterial Issue

SELECT transaction_type_id

INTO l_transaction_type

FROM apps.mtl_transaction_types

WHERE (transaction_type_name) = ‘WIP Completion’;

 

l_transaction_action := 2;

l_source_code := ‘WIP Completion’;

 

/* ELSE

l_transaction_action := 3;          — Transaction Action ID: Return

 

SELECT transaction_type_id

INTO l_transaction_type

FROM apps.mtl_transaction_types

WHERE  (transaction_type_name) = ‘WIP Return’;

 

— Transaction Type ID: WIP Component Return

l_source_code := ‘WIP RM RETURN’;*/

BEGIN

— 1. Get Organization ID

SELECT organization_id

INTO l_org_id

FROM org_organization_definitions

WHERE organization_code = UPPER (TRIM (p_org_code));

EXCEPTION

WHEN NO_DATA_FOUND

THEN

p_message :=

‘Organization Not Exists Contact IT Team: organization Name=’

|| p_org_code;

RETURN;

WHEN OTHERS

THEN

p_message :=

‘Organization Unexpected issue: Contact IT Team: ‘ || SQLERRM;

RETURN;

END;

 

— 2. Get WIP Job ID

BEGIN

SELECT wip_entity_id, primary_item_id

INTO l_wip_entity_id, l_item_id

FROM wip_entities

WHERE UPPER (wip_entity_name) = UPPER (TRIM (p_job_name))

AND organization_id = l_org_id;

EXCEPTION

WHEN NO_DATA_FOUND

THEN

p_message :=

‘Organization and Job Not Exists Contact IT Team: organization Name=’

|| p_org_code

|| ‘ Job= ‘

|| p_job_name;

RETURN;

WHEN OTHERS

THEN

p_message :=

‘Organization and Job Unexpected issue: Contact IT Team: ‘

|| SQLERRM;

RETURN;

END;

 

BEGIN

— 1. Get Organization ID

SELECT primary_uom_code, shelf_life_days

INTO l_uom_code, l_shelf_life_days

FROM mtl_system_items_b

WHERE organization_id = l_org_id AND inventory_item_id = l_item_id;

EXCEPTION

WHEN NO_DATA_FOUND

THEN

p_message :=

‘Item Not Exists Contact IT Team: organization Name=’

|| p_org_code

|| ‘ item := ‘

|| p_assembly_item_code;

RETURN;

WHEN OTHERS

THEN

p_message :=

‘Item Unexpected issue: Contact IT Team: ‘ || SQLERRM;

RETURN;

END;

 

— 3. Get RM item ID and UOM

DBMS_OUTPUT.put_line (‘Loop Start ‘);

 

BEGIN

SELECT NVL (MAX (operation_seq_num), 0)

INTO l_operation_seq_num

FROM apps.wip_operations_v

WHERE wip_entity_id = l_wip_entity_id AND organization_id = l_org_id;

— AND operation_seq_num = p_to_operation_seq_num;

EXCEPTION

WHEN NO_DATA_FOUND

THEN

p_message := ‘Final Operation Not Found’;

RETURN;

WHEN OTHERS

THEN

p_message := ‘Resources Issue Contact IT Team=’ || SQLERRM;

RETURN;

END;

 

/*SELECT bic.component_quantity

INTO l_rm_qty

FROM apps.bom_bill_of_materials bom,

apps.bom_inventory_components_v bic

WHERE bom.bill_sequence_id = bic.bill_sequence_id

AND bom.organization_id = l_org_id

AND bom.assembly_item_id = l_assembly_item_id

AND bic.component_item_id = rm_item.inventory_item_id

AND supply_type = ‘Push’

AND NVL (bic.disable_date, TRUNC (SYSDATE)) >= TRUNC (SYSDATE);*/

SELECT inv.mtl_transactions_interface_s.NEXTVAL

INTO l_interface_id

FROM DUAL;

 

— 4. Insert into MTL_TRANSACTIONS_INTERFACE

INSERT INTO mtl_transactions_interface

(transaction_interface_id, source_code, source_line_id,

source_header_id,

–source_header_type_id,

process_flag, transaction_mode,

lock_flag, transaction_type_id,    –transaction_action_id,

transaction_quantity,

— primary_quantity,

transaction_uom, inventory_item_id, organization_id,

subinventory_code,

— locator_id,

transaction_date,

–wip_entity_id,

transaction_source_type_id, transaction_source_id,

creation_date, created_by, last_update_date,

last_updated_by, operation_seq_num, attribute1,

final_completion_flag

)

VALUES (l_interface_id, l_source_code, l_wip_entity_id,

l_wip_entity_id,

— NULL,

1,                                               — Pending

3,                                     — Background mode

2,                              — Lock flag (2 = unlocked)

l_transaction_type,

— Transaction Type: WIP Component Issue

—  l_transaction_action,

— Transaction Action: Issue

—      44,                            — Transaction Type ID: WIP Component Return

— 3,                             — Transaction Action ID: Return

p_quantity,

l_uom_code, l_item_id, l_org_id,

p_subinventory_code,                             –In-House

–p_subinventory_code,

— p_locator_id,

SYSDATE,

–l_wip_entity_id,

5,                                  — Source Type: WIP Job

l_wip_entity_id,

SYSDATE, l_user_id, SYSDATE,

l_user_id, l_operation_seq_num, l_group_id,

‘Y’

);

 

DBMS_OUTPUT.put_line (‘sequence ‘);

 

INSERT INTO mtl_transaction_lots_interface

(transaction_interface_id, lot_number,

— lot_number_id,

transaction_quantity,                   –primary_quantity,

last_update_date, last_updated_by,

creation_date, created_by, product_code,

product_transaction_id, process_flag,

lot_expiration_date

)

VALUES (l_interface_id,

— From your mtl_transactions_interface insert

p_job_name,

— Lot number from inventory data (loop variable)

— rec.lot_number_id,          — Lot number ID (optional but preferred)

p_quantity,

— Issue quantity (negative for issue)

–p_quantity,

— Primary quantity (same unless using secondary UOM)

SYSDATE, l_user_id,

— Your user ID

SYSDATE, l_user_id, ‘ODM’,

l_interface_id, 1,    –,l_org_id,rm_item.inventory_item_id

— Must match the transaction_interface_id above

SYSDATE

+ CASE

WHEN l_shelf_life_days IS NULL

OR l_shelf_life_days = 0

THEN 365 * 5

ELSE l_shelf_life_days

END

);

 

/*

insert into mtl_serial_numbers_interface

(TRANSACTION_INTERFACE_ID,

SOURCE_CODE,

SOURCE_LINE_ID,

LAST_UPDATE_DATE,

LAST_UPDATED_BY,

CREATION_DATE,

CREATED_BY,

LAST_UPDATE_LOGIN,

FM_SERIAL_NUMBER,

TO_SERIAL_NUMBER,

ERROR_CODE,

PROCESS_FLAG)

values(l_interface_id, l_source_code, l_wip_entity_id,

sysdate, –Last Update date

l_user_id, — Last updated by

sysdate, –Creastion date

l_user_id, –Created by

l_user_id, — Last update login

l_operation_seq_num, — Needs input

l_operation_seq_num, — Needs input

NULL, –Error code

1 –Process Flag

);      */

FOR l_opr_rec IN (SELECT *

FROM apps.wip_operations_v

WHERE wip_entity_id = l_wip_entity_id

AND organization_id = l_org_id)

LOOP

l_scrap_qty := NVL (l_opr_rec.quantity_scrapped, 0);

 

INSERT INTO cst_comp_snap_interface

(transaction_interface_id, wip_entity_id,

operation_seq_num, last_update_date, last_updated_by,

creation_date, created_by, quantity_completed,

primary_quantity

–,prior_scrap_quantity

)

VALUES (l_interface_id, l_wip_entity_id,                –Job id

l_opr_rec.operation_seq_num,          –Operatoin Seq No

SYSDATE,  –Last update date

l_user_id,

–Last updated by

SYSDATE,                                 –Creation date

l_user_id,                          –Created by

l_opr_rec.quantity_completed,

—  l_opr_rec.scheduled_quantity,  —

— l_opr_rec.quantity_completed       –Quantity Completed

p_quantity         –Priamry Quantity

 

–,l_opr_rec.quantity_scrapped

);

END LOOP;

 

DBMS_OUTPUT.put_line (‘after loop ‘);

COMMIT;

 

BEGIN

— Initialize apps context (if not already done)

apps.fnd_global.apps_initialize (user_id           => l_user_id,

— <your_user_id>,

resp_id           => l_resp_id,

— <your_resp_id>,

resp_appl_id      => l_appl_id

);            –<your_resp_appl_id>);

— Submit the Inventory Transaction Manager program

l_request_id :=

fnd_request.submit_request

(application      => ‘INV’,

— Inventory Application

program          => ‘INCTCM’,

— Short name of the program

description      => ‘Inventory Transaction Manager(Complete Job)’,

start_time       => NULL,

sub_request      => FALSE

);

COMMIT;

DBMS_OUTPUT.put_line (   ‘Request submitted. Request ID: ‘

|| l_request_id

);

END;

 

— Wait for completion

LOOP

— Check status

l_success :=

apps.fnd_concurrent.wait_for_request (request_id      => l_request_id,

INTERVAL        => 5,

max_wait        => 300,

phase           => l_phase,

status          => l_status,

dev_phase       => l_dev_phase,

dev_status      => l_dev_status,

MESSAGE         => l_message

);

 

IF l_success

THEN

DBMS_OUTPUT.put_line (‘Request Completed.’);

DBMS_OUTPUT.put_line (‘Phase: ‘ || l_dev_phase);

DBMS_OUTPUT.put_line (‘Status: ‘ || l_dev_status);

DBMS_OUTPUT.put_line (‘Message: ‘ || l_message);

ELSE

DBMS_OUTPUT.put_line

(‘Failed to wait for request or it timed out.’);

END IF;

 

EXIT WHEN l_dev_phase = ‘COMPLETE’;

 

— Optional: timeout check

IF (SYSDATE – l_start_time) * 86400 > l_timeout_seconds

THEN

raise_application_error (-20001,

‘Timeout waiting for request ‘

|| l_request_id

);

END IF;

 

DBMS_LOCK.sleep (l_sleep_seconds);

END LOOP;

 

— Output result

DBMS_OUTPUT.put_line (‘Request Completed. Status: ‘ || l_dev_status);

 

IF l_dev_status = ‘NORMAL’

THEN

p_message := ‘SUCCESS’;

 

FOR rec IN

(SELECT ERROR_CODE AS MESSAGE_TYPE,

error_explanation AS MESSAGE_TEXT

FROM apps.mtl_transactions_interface

WHERE transaction_interface_id IN (

SELECT transaction_interface_id

FROM mtl_transactions_interface

WHERE attribute1 = l_group_id

AND NVL (process_flag, 0) <> 1)

AND organization_id = l_org_id)

LOOP

DBMS_OUTPUT.put_line (‘Error Type: ‘ || rec.MESSAGE_TYPE);

p_message := rec.MESSAGE_TEXT;

END LOOP;

 

IF p_message = ” OR p_message IS NULL OR p_message = ‘SUCCESS’

THEN

p_message := ‘SUCCESS’;

DBMS_OUTPUT.put_line (‘p_message: ‘ || p_message);

RETURN;

END IF;

ELSE

FOR rec IN

(SELECT ERROR_CODE AS MESSAGE_TYPE,

error_explanation AS MESSAGE_TEXT

FROM apps.mtl_transactions_interface

WHERE transaction_interface_id IN (

SELECT transaction_interface_id

FROM mtl_transactions_interface

WHERE attribute1 = l_group_id)

AND organization_id = l_org_id)

LOOP

DBMS_OUTPUT.put_line (‘Error Type: ‘ || rec.MESSAGE_TYPE);

p_message := rec.MESSAGE_TEXT;

END LOOP;

END IF;

 

DBMS_OUTPUT.put_line (‘p_message1: ‘ || p_message);

—            — Delete interface record

—            DELETE FROM apps.wip_job_schedule_interface

—                  WHERE interface_id = l_interface_id;

COMMIT;                                               — Commit deletion

EXCEPTION

WHEN NO_DATA_FOUND

THEN

p_message := ‘Invalid organization, job, or item.’ || SQLERRM;

ROLLBACK;

WHEN OTHERS

THEN

p_message := ‘Error: ‘ || SQLERRM;

ROLLBACK;

END complete_job;

 

 

END xx_wip_job_pkg;

/

 

 

 

Recent Posts