PO SHIPMENT LINE UPDATE USING API
Objective:
The purpose of this document is to provide a comprehensive guide on how to update or split Purchase Order (PO) shipment lines using the relevant API. This includes a detailed explanation of the API endpoints, required and optional parameters, data structures, and sample requests and responses. The goal is to enable developers and system integrators to efficiently and accurately manage PO shipment lines within their applications line using API.
Scenario:
- To achieve the goal of splitting the existing PO shipment lines into multiple lines via an API in Oracle, here’s a step-by-step outline of the process. This will include the general approach and considerations needed for splitting the shipment lines as described
- Currently below is the PO shipment line available in oracle, we would like to split the first shipment as 2 lines and second shipment line as 3 lines.
PO Number | PO Line Number | Item Number | Shipment Line number | Org | Quantity | Promised Date | Need by Date |
100001 | 1 | ABC1 | 1 | USA | 50 | 01-JUL-2022 | |
100001 | 2 | DCG2 | 2 | USA | 50 | 01-JUL-2022 |
Sample Data File to be prepare and load in to staging table
PO_NUMBER | PO_LINE_NUMBER | PO_SHIPMENT_NUMBER | QUANTITY | NEED_BY_DATE |
100001 | 1 | 1 | 25 | 1-Jul-22 |
100001 | 1 | 2 | 25 | 30-Jul-22 |
100001 | 2 | 1 | 20 | 1-Jul-22 |
100001 | 2 | 2 | 20 | 15-Jul-22 |
100001 | 2 | 3 | 10 | 30-Jul-22 |
Steps:
ü Compile the data base objects.
ü Load the prepared data into staging table.
ü Run the Main procedure.
Objects:
CREATE TABLE XX_PO_SHIPMENT_INT_STG (
PO_NUMBER VARCHAR2(200),
PO_LINE_NUMBER NUMBER,
PO_SHIPMENT_NUMBER NUMBER,
QUANTITY NUMBER,
NEED_BY_DATE DATE ,
PROCESS_FLAG VARCHAR2(50),
LAST_UPDATE_DATE DATE,
LAST_UPDATED_BY NUMBER,
CREATION_DATE DATE,
CREATED_BY NUMBER,
UPLOAD_ID NUMBER,
ERR_MSG VARCHAR2(4000))
PROCEDURE main (
errbuf OUT VARCHAR2,
retcode OUT NUMBER,
p_email_address VARCHAR2
)
IS
CURSOR cur_hdr
IS
SELECT DISTINCT po_number, upload_id
FROM bolinf.xx_po_shipment_int_stg
WHERE process_flag = ‘N’;
CURSOR cur_lne (p_po_number VARCHAR2)
IS
SELECT DISTINCT po_number, po_line_number, upload_id
FROM bolinf.xx_po_shipment_int_stg
WHERE process_flag = ‘N’ AND po_number = p_po_number;
CURSOR cur (p_po_num VARCHAR2, p_po_line_number NUMBER)
IS
SELECT xps.*, xps.ROWID
FROM bolinf.xx_po_shipment_int_stg xps
WHERE xps.process_flag = ‘N’
AND xps.po_number = p_po_num
AND xps.po_line_number = p_po_line_number
ORDER BY po_line_number, po_shipment_number;
CURSOR crpt (p_upload_id NUMBER)
IS
SELECT *
FROM bolinf.xx_po_shipment_int_stg
WHERE upload_id = p_upload_id;
l_ship_to_location_id NUMBER;
l_ship_to_organization_id NUMBER;
l_po_header_id NUMBER;
l_po_line_id NUMBER;
l_line_location_id NUMBER;
l_err_flag VARCHAR2 (1);
l_err_msg VARCHAR2 (4000);
l_new_line VARCHAR2 (1);
l_user_id NUMBER
:= NVL (fnd_profile.VALUE (‘USER_ID’),
-1);
l_revision_number NUMBER (4, 2);
l_line_qty NUMBER;
l_ship_qty NUMBER;
l_po_line_loc po_line_locations_all%ROWTYPE;
l_po_line_loc1 po_line_locations_all%ROWTYPE;
l_result NUMBER;
l_errors apps.po_api_errors_rec_type;
l_upload_id NUMBER;
l_cancel_flag VARCHAR2 (10);
l_closed_date DATE;
l_lne_cancel_flag VARCHAR2 (10);
l_lne_closed_date DATE;
l_cnt NUMBER := 0;
l_rct_cnt NUMBER;
l_drp_ship NUMBER;
l_chg apps.po_changes_rec_type;
l_chg1 apps.po_changes_rec_type;
l_return_status VARCHAR2 (30);
l_agent_id NUMBER;
l_parent_loc_location_id NUMBER;
v_item_key VARCHAR2 (100);
l_shipment_qty NUMBER := NULL;
l_vendor_id NUMBER;
l_vnd_exists VARCHAR2 (10);
l_org_id NUMBER;
BEGIN
SELECT fnd_profile.VALUE (‘CONC_REQUEST_ID’)
INTO l_upload_id
FROM DUAL;
fnd_file.put_line (fnd_file.LOG, ‘ Upload ID ‘ || l_upload_id);
UPDATE bolinf.xx_po_shipment_int_stg
SET upload_id = l_upload_id –xx_po_ship_seq.nextval
WHERE process_flag = ‘N’;
COMMIT;
FOR rec_hdr IN cur_hdr
LOOP
l_po_header_id := NULL;
l_revision_number := NULL;
l_err_flag := ‘N’;
l_drp_ship := 0;
l_chg := l_chg1;
l_agent_id := 0;
l_err_msg := NULL;
l_vendor_id := NULL;
l_vnd_exists := ‘N’;
l_org_id := NULL;
BEGIN
SELECT po_header_id, revision_num, NVL (cancel_flag, ‘N’),
closed_date, agent_id, vendor_id, org_id
INTO l_po_header_id, l_revision_number, l_cancel_flag,
l_closed_date, l_agent_id, l_vendor_id, l_org_id
FROM po_headers_all
WHERE segment1 = rec_hdr.po_number
AND authorization_status = ‘APPROVED’
AND type_lookup_code = ‘STANDARD’;
EXCEPTION
WHEN OTHERS
THEN
l_err_flag := ‘E’;
l_err_msg := ‘Invalid Purchase Order Number’;
END;
IF l_cancel_flag = ‘Y’ OR l_closed_date IS NOT NULL
THEN
l_err_flag := ‘E’;
l_err_msg := ‘Purchase Order is cancelled or closed’;
END IF;
IF l_err_flag != ‘E’
THEN
l_chg :=
apps.po_changes_rec_type.create_object
(p_po_header_id => l_po_header_id,
p_po_release_id => NULL
);
FOR rec_po IN cur_lne (rec_hdr.po_number)
LOOP
l_ship_to_location_id := NULL;
l_ship_to_organization_id := NULL;
l_po_line_id := NULL;
l_line_location_id := NULL;
l_err_flag := NULL;
l_err_msg := NULL;
l_new_line := ‘N’;
l_line_qty := NULL;
l_ship_qty := NULL;
l_po_line_loc := l_po_line_loc1;
l_err_flag := ‘N’;
l_lne_cancel_flag := NULL;
l_lne_closed_date := NULL;
l_cnt := 0;
l_rct_cnt := 0;
l_shipment_qty := NULL;
SELECT COUNT (1)
INTO l_cnt
FROM bolinf.xx_po_shipment_int_stg
WHERE po_number = rec_po.po_number
AND po_line_number = rec_po.po_line_number
AND upload_id = rec_po.upload_id
AND process_flag = ‘E’;
IF l_cnt > 0
THEN
l_err_flag := ‘E’;
l_err_msg := l_err_msg || ‘, One of the PO Line is in error’;
END IF;
BEGIN
SELECT po_line_id, quantity, cancel_flag,
closed_date
INTO l_po_line_id, l_line_qty, l_lne_cancel_flag,
l_lne_closed_date
FROM po_lines_all
WHERE po_header_id = l_po_header_id
AND line_num = rec_po.po_line_number;
EXCEPTION
WHEN OTHERS
THEN
l_err_flag := ‘E’;
l_err_msg :=
l_err_msg || ‘, Invalid Purchase order line Number’;
END;
IF l_lne_cancel_flag = ‘Y’ OR l_lne_closed_date IS NOT NULL
THEN
l_err_flag := ‘E’;
l_err_msg :=
l_err_msg
|| ‘, Purchase Order line has cancelled or closed’;
END IF;
l_lne_cancel_flag := ‘N’;
l_lne_closed_date := NULL;
SELECT COUNT (1)
INTO l_rct_cnt
FROM po_line_locations_all
WHERE po_header_id = l_po_header_id
AND po_line_id = l_po_line_id
AND (quantity_received > 0 OR quantity_billed > 0);
IF l_rct_cnt > 0
THEN
l_err_flag := ‘E’;
l_err_msg :=
l_err_msg
|| ‘, Purchase Order line quantity has received or billed’;
END IF;
SELECT SUM (quantity)
INTO l_ship_qty
FROM bolinf.xx_po_shipment_int_stg
WHERE po_number = rec_po.po_number
AND po_line_number = rec_po.po_line_number
AND upload_id = rec_po.upload_id;
l_parent_loc_location_id := NULL;
l_line_location_id := NULL;
IF l_err_flag != ‘E’
THEN
FOR rec_cur IN cur (rec_po.po_number, rec_po.po_line_number)
LOOP
l_err_flag := ‘N’;
l_err_msg := NULL;
IF l_line_location_id IS NOT NULL
THEN
l_parent_loc_location_id := l_line_location_id;
END IF;
BEGIN
SELECT line_location_id, ship_to_location_id,
quantity, ship_to_organization_id,
cancel_flag, closed_date
INTO l_line_location_id, l_ship_to_location_id,
l_shipment_qty, l_ship_to_organization_id,
l_lne_cancel_flag, l_lne_closed_date
FROM po_line_locations_all
WHERE po_header_id = l_po_header_id
AND po_line_id = l_po_line_id
AND shipment_num = rec_cur.po_shipment_number;
EXCEPTION
WHEN OTHERS
THEN
l_new_line := ‘Y’;
END;
IF l_lne_cancel_flag = ‘Y’ OR l_lne_closed_date IS NOT NULL
THEN
l_err_flag := ‘E’;
l_err_msg :=
l_err_msg
|| ‘, Purchase Order shipment line is cancelled or closed’;
END IF;
IF l_shipment_qty <> l_ship_qty
THEN
l_err_flag := ‘E’;
l_err_msg :=
l_err_msg
|| ‘, PO Line Quantity and new Shipment lines Quantity is not matching’;
END IF;
DBMS_OUTPUT.put_line ( ‘l_new_line ‘
|| l_new_line
|| ‘l_err_flag ‘
|| l_err_flag
);
IF l_err_flag != ‘E’
THEN
IF l_new_line != ‘Y’
THEN
l_chg.shipment_changes.add_change
(p_po_line_location_id => l_line_location_id,
p_quantity => rec_cur.quantity,
p_need_by_date => rec_cur.need_by_date
);
ELSE
l_chg.shipment_changes.add_change
(p_po_line_location_id => NULL,
p_quantity => rec_cur.quantity,
p_split_shipment_num => rec_cur.po_shipment_number,
p_need_by_date => rec_cur.need_by_date,
p_parent_line_location_id => l_parent_loc_location_id
);
END IF;
— commit;
ELSE
ROLLBACK;
UPDATE bolinf.xx_po_shipment_int_stg
SET process_flag = ‘E’,
err_msg = l_err_msg
WHERE ROWID = rec_cur.ROWID;
COMMIT;
fnd_file.put_line (fnd_file.LOG,
‘After error update: ‘ || l_err_msg
);
END IF;
END LOOP;
END IF;
END LOOP;
IF l_err_flag != ‘E’
THEN
apps.po_document_update_grp.update_document
(p_api_version => 1.0,
— pass this as 1.0
p_init_msg_list => fnd_api.g_true,
— pass this as TRUE
x_return_status => l_return_status,
— returns the result of execution
p_changes => l_chg,
— changes obj. contains all changes intended to be made on document
p_run_submission_checks => fnd_api.g_false,
— set to TRUE if want to perform submission check
p_launch_approvals_flag => fnd_api.g_false,
— set to TRUE if want to launch approval work flow after making the changes
p_buyer_id => l_agent_id,
— buyer id
p_update_source => NULL,
p_override_date => NULL,
x_api_errors => l_errors,
p_mass_update_releases => NULL
);
IF l_errors IS NOT NULL
THEN
ROLLBACK;
FOR i IN 1 .. l_errors.MESSAGE_TEXT.COUNT
LOOP
l_err_flag := ‘E’;
l_err_msg := l_err_msg || ‘, ‘ || l_errors.MESSAGE_TEXT (i);
DBMS_OUTPUT.put_line ( ‘ Error is ‘
|| l_errors.MESSAGE_TEXT (i)
|| ‘ – name’
|| l_errors.message_name (i)
);
END LOOP;
END IF;
END IF;
IF l_err_flag = ‘E’
THEN
ROLLBACK;
UPDATE bolinf.xx_po_shipment_int_stg
SET process_flag = ‘E’,
err_msg = l_err_msg
WHERE po_number = rec_hdr.po_number
AND upload_id = rec_hdr.upload_id;
COMMIT;
ELSE
fnd_file.put_line (fnd_file.LOG,
‘Before error update: ‘ || l_err_msg
);
UPDATE bolinf.xx_po_shipment_int_stg
SET process_flag = ‘P’,
err_msg = ‘Successfully Processed’
WHERE po_number = rec_hdr.po_number
AND upload_id = rec_hdr.upload_id;
COMMIT;
END IF;
ELSE
ROLLBACK;
UPDATE bolinf.xx_po_shipment_int_stg
SET process_flag = ‘E’,
err_msg = l_err_msg
WHERE po_number = rec_hdr.po_number
AND upload_id = rec_hdr.upload_id;
COMMIT;
END IF;
SELECT l_po_header_id || ‘-‘ || TO_CHAR (po_wf_itemkey_s.NEXTVAL)
INTO v_item_key
FROM DUAL;
po_reqapproval_init1.start_wf_process
(itemtype => ‘POAPPRV’,
itemkey => v_item_key,
workflowprocess => ‘POAPPRV_TOP’,
actionoriginatedfrom => ‘PO_FORM’,
documentid => l_po_header_id
— po_header_id
,
documentnumber => rec_hdr.po_number
— Purchase Order Number
,
preparerid => l_agent_id
— Buyer/Preparer_id
,
documenttypecode => ‘PO’,
documentsubtype => ‘STANDARD’,
submitteraction => ‘APPROVE’,
forwardtoid => NULL,
forwardfromid => NULL,
defaultapprovalpathid => NULL,
note => NULL,
printflag => ‘N’,
faxflag => ‘N’,
faxnumber => NULL,
emailflag => ‘N’,
emailaddress => NULL,
createsourcingrule => ‘N’,
releasegenmethod => ‘N’,
updatesourcingrule => ‘N’,
massupdatereleases => ‘N’,
retroactivepricechange => ‘N’,
orgassignchange => ‘N’,
communicatepricechange => ‘N’,
p_background_flag => ‘N’
);
COMMIT;
END LOOP;
fnd_file.put_line (fnd_file.output,
RPAD (‘po_number’, 15, ‘ ‘)
|| RPAD (‘po_line_number’, 20, ‘ ‘)
|| RPAD (‘po_shipment_number’, 20, ‘ ‘)
|| ‘Message ‘
);
FOR rpt IN crpt (l_upload_id)
LOOP
— commit;
fnd_file.put_line (fnd_file.output,
RPAD (rpt.po_number, 15, ‘ ‘)
|| RPAD (rpt.po_line_number, 20, ‘ ‘)
|| RPAD (rpt.po_shipment_number, 20, ‘ ‘)
|| rpt.err_msg
);
END LOOP;
fnd_file.put_line (fnd_file.LOG, ‘ l_err_msg :’ || l_err_msg);
DBMS_OUTPUT.put_line (‘ l_err_msg :’ || l_err_msg);
IF p_email_address IS NOT NULL
THEN
/* Calling procedure to send a report output as an attachment to user */
xx_po_shipment_excl_rpt (l_upload_id, p_email_address);
–‘srujan.k@ealliancecorp.com’
END IF;
EXCEPTION
WHEN OTHERS
THEN
fnd_file.put_line (fnd_file.LOG, ‘Unexpected Error ‘ || SQLERRM);
DBMS_OUTPUT.put_line (‘Unexpected Error ‘ || SQLERRM);
END;