DBA Data[Home] [Help]

PACKAGE BODY: APPS.PO_PDOI_MAINPROC_PVT

Source


1 PACKAGE BODY PO_PDOI_MAINPROC_PVT AS
2 /* $Header: PO_PDOI_MAINPROC_PVT.plb 120.21.12010000.2 2008/08/04 08:39:03 rramasam ship $ */
3 
4 d_pkg_name CONSTANT VARCHAR2(50) :=
5   PO_LOG.get_package_base('PO_PDOI_MAINPROC_PVT');
6 
7 g_snap_shot_too_old       EXCEPTION;
8 PRAGMA EXCEPTION_INIT(g_snap_shot_too_old, -1555);
9 
10 --------------------------------------------------------------------------
11 ---------------------- PRIVATE PROCEDURES PROTOTYPE ----------------------
12 --------------------------------------------------------------------------
13 PROCEDURE process_headers;
14 
15 PROCEDURE process_lines;
16 
17 PROCEDURE process_lines_add
18 (
19   p_data_set_type IN NUMBER  -- choice on data set to be processed
20 );
21 
22 PROCEDURE process_lines_sync
23 (
24   p_data_set_type IN NUMBER  -- choice on data set to be processed
25 );
26 
27 PROCEDURE process_create_lines_in_group
28 (
29   p_group_num           IN NUMBER,
30   p_expire_line_id_tbl  IN DBMS_SQL.NUMBER_TABLE,
31   x_lines               IN OUT NOCOPY PO_PDOI_TYPES.lines_rec_type
32 );
33 
34 PROCEDURE process_update_lines_in_group
35 (
36   p_group_num           IN NUMBER,
37   x_lines               IN OUT NOCOPY PO_PDOI_TYPES.lines_rec_type
38 );
39 
40 PROCEDURE process_line_locations;
41 
42 PROCEDURE process_distributions;
43 
44 PROCEDURE process_price_diffs;
45 
46 PROCEDURE process_attributes;
47 
48 PROCEDURE process_attr_values;
49 
50 PROCEDURE process_attr_values_tlp;
51 --------------------------------------------------------------------------
52 ---------------------- PUBLIC PROCEDURES ---------------------------------
53 --------------------------------------------------------------------------
54 
55 --------------------------------------------------------------------------
56 --Start of Comments
57 --Name: process
58 --Pre-reqs: None
59 --Modifies:
60 --Locks:
61 --  None
62 --Function:
63 --  perform derive, default, validate and insert/update logic on all records
64 --  in interface tables
65 --Parameters:
66 --IN: None
67 --IN OUT: None
68 --OUT: None
69 --Returns: None
70 --Notes:
71 --Testing:
72 --End of Comments
73 --------------------------------------------------------------------------
74 PROCEDURE process IS
75 
76   d_api_name CONSTANT VARCHAR2(30) := 'process';
77   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
78   d_position NUMBER;
79 
80 BEGIN
81   d_position := 0;
82 
83   IF (PO_LOG.d_proc) THEN
84     PO_LOG.proc_begin(d_module, 'start main process for header group',
85                       PO_PDOI_PARAMS.g_current_round_num);
86   END IF;
87 
88   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_MAIN_PROCESSING);
89 
90   -- clean up cache before each group processing
91   PO_PDOI_MAINPROC_UTL_PVT.cleanup;
92 
93   d_position := 10;
94 
95   -- process each entity from upper to lower level
96   process_headers;
97 
98   d_position := 10;
99 
100   process_lines;
101 
102   d_position := 20;
103 
104   IF (PO_PDOI_PARAMS.g_request.document_type IN
105        (PO_PDOI_CONSTANTS.g_DOC_TYPE_BLANKET, PO_PDOI_CONSTANTS.g_DOC_TYPE_QUOTATION)) THEN
106     process_attributes;
107   END IF;
108 
109   d_position := 30;
110 
111   process_line_locations;
112 
113   d_position := 40;
114 
115   IF (PO_PDOI_PARAMS.g_request.document_type =
116        PO_PDOI_CONSTANTS.g_DOC_TYPE_STANDARD) THEN
117     process_distributions;
118   END IF;
119 
120   d_position := 50;
121 
122   process_price_diffs;
123 
124   d_position := 60;
125 
126   -- Bug 5215781:
127   -- Remove all unprocessed records if error threshold is hit for CATALOG UPLOAD
128   IF (PO_PDOI_PARAMS.g_request.calling_module =
129         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
130       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
131         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
132     IF (PO_LOG.d_stmt) THEN
133       PO_LOG.stmt(d_module, d_position, 'Unprocessed records will be removed for header ',
134                   PO_PDOI_PARAMS.g_request.interface_header_id);
135     END IF;
136 
137     PO_PDOI_UTL.reject_unprocessed_intf
138     (
139       p_intf_header_id => PO_PDOI_PARAMS.g_request.interface_header_id
140     );
141   END IF;
142 
143   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_MAIN_PROCESSING);
144 
145   IF (PO_LOG.d_proc) THEN
146     PO_LOG.proc_end(d_module);
147   END IF;
148 
149 EXCEPTION
150   WHEN OTHERS THEN
151     PO_MESSAGE_S.add_exc_msg
152     (
153       p_pkg_name => d_pkg_name,
154       p_procedure_name => d_api_name || '.' || d_position
155     );
156     RAISE;
157 END process;
158 
159 -------------------------------------------------------------------------
160 --------------------- PRIVATE PROCEDURES --------------------------------
161 -------------------------------------------------------------------------
162 
163 -------------------------------------------------------------------------
164 --Start of Comments
165 --Name: process_headers
166 --Pre-reqs: None
167 --Modifies:
168 --Locks:
169 --  None
170 --Function:
171 --  handle the logic to derive, default, validate and insert records
172 --  from po_headers_interface table
173 --Parameters:
174 --IN: None
175 --IN OUT: None
176 --OUT: None
177 --Returns:
178 --Notes:
179 --Testing:
180 --End of Comments
181 ------------------------------------------------------------------------
182 PROCEDURE process_headers IS
183 
184   d_api_name CONSTANT VARCHAR2(30) := 'process_headers';
185   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
186   d_position NUMBER;
187 
188   -- cursor variable to point to currently processing row
189   l_headers_csr        PO_PDOI_TYPES.intf_cursor_type;
190 
191   -- all header attribute values within a batch
192   l_headers PO_PDOI_TYPES.headers_rec_type;
193 
194   -- variable to track the largest intf_header_id processed so far
195   l_max_intf_header_id NUMBER := -1;
196 
197   -- variables to track the records that need to be rejected due
198   -- to errors in the processing
199   l_count  NUMBER := 0;
200   l_rej_intf_header_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
201 
202 BEGIN
203   d_position := 0;
204 
205   IF (PO_LOG.d_proc) THEN
206     PO_LOG.proc_begin(d_module);
207   END IF;
208 
209   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_HEADER_PROCESS);
210 
211   -- open cursor for the query which retrieve the header info
212   PO_PDOI_HEADER_PROCESS_PVT.open_headers
213   (
214     p_max_intf_header_id   => l_max_intf_header_id,
215     x_headers_csr          => l_headers_csr
216   );
217 
218   d_position := 10;
219 
220   -- fetch records from header interface table and process the records
221   LOOP
222     BEGIN
223       -- fetch one batch of header records from query result
224       PO_PDOI_HEADER_PROCESS_PVT.fetch_headers
225       (
226         x_headers_csr   => l_headers_csr,
227         x_headers       => l_headers
228       );
229 
230       d_position := 20;
231 
232       -- number of records read in current batch
233       l_headers.rec_count := l_headers.intf_header_id_tbl.COUNT;
234 
235       IF (PO_LOG.d_stmt) THEN
236         PO_LOG.stmt(d_module, d_position, 'header count within batch',
237                     l_headers.rec_count);
238       END IF;
239 
240       EXIT WHEN l_headers.rec_count = 0;
241 
242       -- set up hashtable between interface_header_id and index
243       l_headers.intf_id_index_tbl.DELETE;
244 
245       FOR i IN 1..l_headers.rec_count
246       LOOP
247         l_headers.intf_id_index_tbl(l_headers.intf_header_id_tbl(i)) := i;
248       END LOOP;
249 
250       -- derive logic
251       PO_PDOI_HEADER_PROCESS_PVT.derive_headers
252       (
253         x_headers     => l_headers
254       );
255 
256       d_position := 30;
257 
258       -- default logic
259       PO_PDOI_HEADER_PROCESS_PVT.default_headers
260       (
261         x_headers     => l_headers
262       );
263 
264       d_position := 40;
265 
266       -- validate logic
267       PO_PDOI_HEADER_PROCESS_PVT.validate_headers
268       (
269         x_headers     => l_headers
270       );
271 
272       d_position := 50;
273 
274       -- insert valid header records into draft tables
275       PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_headers
276       (
277         p_headers     => l_headers
278       );
279 
280       d_position := 60;
281 
282       -- Rejected header records with errors
283       l_rej_intf_header_id_tbl.EXTEND(l_headers.rec_count);
284       FOR i IN 1..l_headers.rec_count
285       LOOP
286         IF (l_headers.error_flag_tbl(i) = FND_API.g_TRUE) THEN
287           IF (PO_LOG.d_stmt) THEN
288             PO_LOG.stmt(d_module, d_position, 'rejected intf header id',
289                         l_headers.intf_header_id_tbl(i));
290           END IF;
291 
292           l_count := l_count + 1;
293           l_rej_intf_header_id_tbl(l_count) := l_headers.intf_header_id_tbl(i);
294         END IF;
295       END LOOP;
296       PO_PDOI_UTL.reject_headers_intf
297       (
298         p_id_param_type    => PO_PDOI_CONSTANTS.g_INTERFACE_HEADER_ID,
299         p_id_tbl           => l_rej_intf_header_id_tbl,
300         p_cascade          => FND_API.g_TRUE
301       );
302       l_rej_intf_header_id_tbl.DELETE;
303 
304       d_position := 70;
305 
306       -- conditional commit
307       PO_PDOI_UTL.commit_work;
308 
309       -- set maximal intf_header_id read so far(used in next batch read)
310       l_max_intf_header_id := l_headers.intf_header_id_tbl(l_headers.rec_count);
311 
312   -- exit if this is the last batch
313       IF (l_headers.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
314         EXIT;
315       END IF;
316     EXCEPTION
317       WHEN g_snap_shot_too_old THEN
318         d_position := 80;
319 
320         PO_MESSAGE_S.add_exc_msg
321         (
322           p_pkg_name => d_pkg_name,
323           p_procedure_name => d_api_name || '.' || d_position
324         );
325 
326         -- commit changes
327         PO_PDOI_UTL.commit_work;
328 
329         IF (l_headers_csr%ISOPEN) THEN
330           CLOSE l_headers_csr;
331           PO_PDOI_HEADER_PROCESS_PVT.open_headers
332           (
333             p_max_intf_header_id   => l_max_intf_header_id,
334             x_headers_csr          => l_headers_csr
335           );
336         END IF;
337     END;
338   END LOOP;
339 
340   d_position := 90;
341 
342   -- close cursor
343   IF (l_headers_csr%ISOPEN) THEN
344     CLOSE l_headers_csr;
345   END IF;
346 
347   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_HEADER_PROCESS);
348 
349   IF (PO_LOG.d_proc) THEN
350     PO_LOG.proc_end(d_module);
351   END IF;
352 
353 EXCEPTION
354   WHEN OTHERS THEN
355     PO_MESSAGE_S.add_exc_msg
356     (
357       p_pkg_name => d_pkg_name,
358       p_procedure_name => d_api_name || '.' || d_position
359     );
360     RAISE;
361 END process_headers;
362 
363 -------------------------------------------------------------------------
364 --Start of Comments
365 --Name: process_lines
366 --Pre-reqs: None
367 --Modifies:
368 --Locks:
369 --  None
370 --Function:
371 --  process the records in po_lines_interface table;
372 --  the records in the interface table will be divided into four sets
373 --  according to their header and line level actions:
374 --  First set: all the lines with header action equal to 'ORIGINAL'or
375 --             'REPLACE'; If header action is 'UPDATE', the document
376 --             must be Standard PO
377 --  Second Set: Header level action is 'UPDATE' and document type is
378 --              'BLANKET' or 'QUOTATION'; And line level action is 'ADD'
379 --  Third Set: Header level action is 'UPDATE' and document type is
380 --             'BLANKET' or 'QUOTATION'; And line level action is 'SYNC'
381 --             or Null; And either of the following criteria is true:
382 --             1. one of attributes {item, vendor_product_num, job} is not null
383 --             2. if {item, vendor_product_num, job) are all null, then
384 --                description must be null
385 --  Fourth Set: Header level action is 'UPDATE' and document type is
386 --             'BLANKET' or 'QUOTATION'; And line level action is 'SYNC'
387 --             or Null; {item, vendor_product_num, job) are all null and
388 --             description is not null
389 --Parameters:
390 --IN: None
391 --IN OUT: None
392 --OUT: None
393 --Returns:
394 --Notes:
395 --Testing:
396 --End of Comments
397 ------------------------------------------------------------------------
398 PROCEDURE process_lines IS
399 
400   d_api_name CONSTANT VARCHAR2(30) := 'process_lines';
401   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
402   d_position NUMBER;
403 
404 BEGIN
405   d_position := 0;
406 
407   IF (PO_LOG.d_proc) THEN
408     PO_LOG.proc_begin(d_module);
409   END IF;
410 
411   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_LINE_PROCESS);
412 
413   -- reject lines with existing line_num when updating standard PO
414   IF (PO_PDOI_PARAMS.g_request.document_type =
415       PO_PDOI_CONSTANTS.g_DOC_TYPE_STANDARD) THEN
416     PO_PDOI_LINE_PROCESS_PVT.reject_dup_lines_for_spo;
417   END IF;
418 
419   -- reject lines with invalid line level action.
420   -- line level action can only be NULL or 'ADD';
421   -- the only exception for this is when we re-process
422   -- the notified lines, the system has set the line
423   -- level action to either 'ADD' or 'UPADTE', we don't
424   -- need to check line level action for NOTOFIED lines
425   IF (PO_PDOI_PARAMS.g_request.process_code <>
426        PO_PDOI_CONSTANTS.g_PROCESS_CODE_NOTIFIED) THEN
427     PO_PDOI_LINE_PROCESS_PVT.reject_invalid_action_lines;
428   END IF;
429 
430   d_position := 10;
431 
432   -- first data set
433   process_lines_add
434   (
435     p_data_set_type     => PO_PDOI_CONSTANTS.g_LINE_CSR_ADD
436   );
437 
438   d_position := 20;
439 
440   -- second data set
441   process_lines_add
442   (
443     p_data_set_type     => PO_PDOI_CONSTANTS.g_LINE_CSR_FORCE_ADD
444   );
445 
446   d_position := 30;
447 
448   -- third data set
449   process_lines_sync
450   (
451     p_data_set_type     => PO_PDOI_CONSTANTS.g_LINE_CSR_SYNC
452   );
453 
454   d_position := 40;
455 
456   -- Fourth data set
457   process_lines_sync
458   (
459     p_data_set_type     => PO_PDOI_CONSTANTS.g_LINE_CSR_SYNC_ON_DESC
460   );
461 
462   d_position := 50;
463 
464   -- delete all locations from po_line_locations_interface that are obsoleted
465   DELETE FROM po_line_locations_interface
466   WHERE process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_OBSOLETE
467   AND   processing_id = PO_PDOI_PARAMS.g_processing_id;
468 
469   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_LINE_PROCESS);
470 
471   IF (PO_LOG.d_proc) THEN
472     PO_LOG.proc_end(d_module);
473   END IF;
474 
475 EXCEPTION
476   WHEN OTHERS THEN
477     PO_MESSAGE_S.add_exc_msg
478     (
479       p_pkg_name => d_pkg_name,
480       p_procedure_name => d_api_name || '.' || d_position
481     );
482     RAISE;
483 END process_lines;
484 
485 -----------------------------------------------------------------------
486 --Start of Comments
487 --Name: process_lines_add
488 --Function: This procedure will deal with two kinds of data set:
489 --  First set: all the lines with header action equal to 'ORIGINAL'or
490 --             'REPLACE'; If header action is 'UPDATE', the document
491 --             must be Standard PO
492 --  Second Set: Header level action is 'UPDATE' and document type is
493 --              'BLANKET' or 'QUOTATION'; And line level action is 'ADD'
494 --  The two data set share similiar processing logic except for the data
495 --  to be processed. There is also an extra matching logic for First Set.
496 --Parameters:
497 --IN:
498 --p_data_set_type
499 --  the value determines which data set is going to be processed:
500 --  PO_PDOI_CONSTANTS.g_LINE_CSR_ADD: first data set
501 --  PO_PDOI_CONSTANTS.g_LINE_CSR_FORCE_ADD: second data set
502 --IN OUT:
503 --OUT:
504 --End of Comments
505 ------------------------------------------------------------------------
506 PROCEDURE process_lines_add
507 (
508   p_data_set_type IN NUMBER  -- choice on data set to be processed
509 ) IS
510 
511   d_api_name CONSTANT VARCHAR2(30) := 'process_lines_add';
512   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
513   d_position NUMBER;
514 
515   -- cursor variable defined for the query
516   l_lines_csr PO_PDOI_TYPES.intf_cursor_type;
517 
518   -- all line attribute values within a batch
519   l_lines PO_PDOI_TYPES.lines_rec_type;
520 
521   -- variable to track the largest intf_line_id processed so far
522   l_max_intf_line_id NUMBER := -1;
523 
524   -- variables to track the records that need to be rejected due
525   -- to errors in the processing
526   l_rej_intf_line_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
527 
528 BEGIN
529   d_position := 0;
530 
531   IF (PO_LOG.d_proc) THEN
532     PO_LOG.proc_begin(d_module, 'p_data_set_type', p_data_set_type);
533   END IF;
534 
535   /*
536   -- code added for debugging purpose
537   select interface_header_id
538   into PO_PDOI_PARAMS.g_request.interface_header_id
539   from po_headers_interface
540   where processing_id = PO_PDOI_PARAMS.g_processing_id
541   and   processing_round_num = 1;
542   */
543 
544   -- Bug 5215781:
545   -- exit immediately if error threshold is hit for CATALOG UPLOAD
546   IF (PO_PDOI_PARAMS.g_request.calling_module =
547         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
548       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
549         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
550     IF (PO_LOG.d_stmt) THEN
551       PO_LOG.stmt(d_module, d_position, 'Exit from process_lines_add since' ||
552                   ' error threshold is hit for header ',
553                   PO_PDOI_PARAMS.g_request.interface_header_id);
554     END IF;
555 
556     RETURN;
557   END IF;
558 
559   d_position := 5;
560 
561   -- open cursor for the correct query
562   PO_PDOI_LINE_PROCESS_PVT.open_lines
563   (
564     p_data_set_type      => p_data_set_type,
565     p_max_intf_line_id   => l_max_intf_line_id,
566     x_lines_csr          => l_lines_csr
567   );
568 
569   d_position := 10;
570 
571   -- fetch records from line interface table and process the records
572   LOOP
573     -- Bug 5215781:
574     -- check whether num of error lines exceeds the error
575     -- threshold for each batch
576     IF (PO_PDOI_PARAMS.g_request.calling_module =
577           PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
578         PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
579           .err_tolerance_exceeded = FND_API.g_TRUE) THEN
580       IF (PO_LOG.d_stmt) THEN
581         PO_LOG.stmt(d_module, d_position, 'error tolerance exceeded for',
582                     PO_PDOI_PARAMS.g_request.interface_header_id);
583       END IF;
584 
585       -- no need to process remaining lines if error threshold is reached
586       EXIT;
587     END IF;
588 
589     BEGIN
590       -- fetch one batch of line records from query result
591       PO_PDOI_LINE_PROCESS_PVT.fetch_lines
592       (
593         x_lines_csr   => l_lines_csr,
594         x_lines       => l_lines
595       );
596 
597       d_position := 20;
598 
599       -- number of records read in current batch
600       l_lines.rec_count := l_lines.intf_line_id_tbl.COUNT;
601 
602       IF (PO_LOG.d_stmt) THEN
603         PO_LOG.stmt(d_module, d_position, 'line count in batch',
604                     l_lines.rec_count);
605       END IF;
606 
607       EXIT WHEN l_lines.rec_count = 0;
608 
609       -- set up hashtable between interface_line_id and index
610       l_lines.intf_id_index_tbl.DELETE;
611 
612       FOR i IN 1..l_lines.rec_count
613       LOOP
614         l_lines.intf_id_index_tbl(l_lines.intf_line_id_tbl(i)) := i;
615       END LOOP;
616 
617       -- calculate max_line_num for all document in this batch
618       -- the result is saved and used in line processing
619       PO_PDOI_MAINPROC_UTL_PVT.calculate_max_line_num
620       (
621         p_po_header_id_tbl    => l_lines.hd_po_header_id_tbl,
622         p_draft_id_tbl        => l_lines.draft_id_tbl
623       );
624 
625       d_position := 30;
626 
627       -- derive logic
628       PO_PDOI_LINE_PROCESS_PVT.derive_lines
629       (
630         x_lines               => l_lines
631       );
632 
633       d_position := 40;
634 
635       -- default logic
636       PO_PDOI_LINE_PROCESS_PVT.default_lines
637       (
638         x_lines               => l_lines
639       );
640 
641       d_position := 50;
642 
643       -- match related lines based on line_num/item info
644       PO_PDOI_LINE_PROCESS_PVT.match_lines
645       (
646         p_data_set_type    => p_data_set_type, -- bug5129752
647         x_lines            => l_lines
648       );
649 
650 
651       d_position := 60;
652 
653       -- bug5129752
654       -- After doing match line action, l_lines may become empty (this is the
655       -- case if all the lines can be matched to lines in the draft table
656 
657 
658       -- validate lines
659       PO_PDOI_LINE_PROCESS_PVT.validate_lines
660       (
661         x_lines               => l_lines
662       );
663 
664       d_position := 70;
665 
666       -- create items if necessary
667       IF (PO_PDOI_PARAMS.g_request.create_items = 'Y') THEN
668         IF (PO_LOG.d_stmt) THEN
669           PO_LOG.stmt(d_module, d_position, 'create items for lines');
670         END IF;
671 
672         PO_PDOI_ITEM_PROCESS_PVT.create_items
673         (
674           x_lines               => l_lines
675         );
676       END IF;
677 
678       d_position := 80;
679 
680       -- insert lines into line draft table
681       PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_lines
682       (
683         x_lines              => l_lines
684       );
685 
686       d_position := 90;
687 
688       -- update po_lines_interface with po_line_id and line level action
689       PO_PDOI_LINE_PROCESS_PVT.update_line_intf_tbl
690       (
691         x_lines               => l_lines
692       );
693 
694       d_position := 100;
695 
696       -- reject lines with errors
697       FOR i IN 1..l_lines.rec_count
698       LOOP
699         IF (l_lines.error_flag_tbl(i) = FND_API.g_TRUE OR
700             l_lines.need_to_reject_flag_tbl(i) = FND_API.g_TRUE) THEN
701           IF (PO_LOG.d_stmt) THEN
702             PO_LOG.stmt(d_module, d_position, 'error flag',
703                         l_lines.error_flag_tbl(i));
704             PO_LOG.stmt(d_module, d_position, 'reject flag',
705                         l_lines.need_to_reject_flag_tbl(i));
706             PO_LOG.stmt(d_module, d_position, 'rejected intf line id',
707                         l_lines.intf_line_id_tbl(i));
708           END IF;
709 
710           l_rej_intf_line_id_tbl.EXTEND;
711           l_rej_intf_line_id_tbl(l_rej_intf_line_id_tbl.COUNT) := l_lines.intf_line_id_tbl(i);
712         END IF;
713       END LOOP;
714       PO_PDOI_UTL.reject_lines_intf
715       (
716         p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_ID,
717         p_id_tbl          => l_rej_intf_line_id_tbl,
718         p_cascade         => FND_API.g_TRUE
719       );
720       l_rej_intf_line_id_tbl.DELETE;
721 
722       d_position := 110;
723 
724       -- commit changes
725       PO_PDOI_UTL.commit_work;
726 
727       -- set the maximal interface_line_id processed in this batch
728       l_max_intf_line_id := l_lines.intf_line_id_tbl(l_lines.rec_count);
729 
730       IF (l_lines.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
731         EXIT;
732       END IF;
733     EXCEPTION
734       WHEN g_snap_shot_too_old THEN
735         d_position := 120;
736 
737         -- log errors
738         PO_MESSAGE_S.add_exc_msg
739         (
740           p_pkg_name => d_pkg_name,
741           p_procedure_name => d_api_name || '.' || d_position
742         );
743 
744         -- commit changes
745         PO_PDOI_UTL.commit_work;
746 
747         IF (l_lines_csr%ISOPEN) THEN
748           CLOSE l_lines_csr;
749           PO_PDOI_LINE_PROCESS_PVT.open_lines
750           (
751             p_data_set_type      => p_data_set_type,
752             p_max_intf_line_id   => l_max_intf_line_id,
753             x_lines_csr          => l_lines_csr
754           );
755         END IF;
756     END;
757   END LOOP;
758 
759   d_position := 130;
760 
761   -- close the cursor
762   IF (l_lines_csr%ISOPEN) THEN
763     CLOSE l_lines_csr;
764   END IF;
765 
766   d_position := 140;
767 
768   -- reject lines that are price breaks if main po line failed
769   SELECT interface_line_id
770   BULK COLLECT INTO l_rej_intf_line_id_tbl
771   FROM   po_lines_interface intf_line1
772   WHERE  price_break_flag = 'Y'
773   AND    processing_id = PO_PDOI_PARAMS.g_processing_id
774   AND    EXISTS(
775            SELECT 'Y'
776            FROM   po_lines_interface intf_line2
777            WHERE  intf_line1.interface_header_id = intf_line2.interface_header_id
778            AND    intf_line1.po_line_id = intf_line2.po_line_id
779            AND    NVL(intf_line2.process_code, PO_PDOI_CONSTANTS.g_PROCESS_CODE_PENDING)
780 		            = PO_PDOI_CONSTANTS.g_PROCESS_CODE_REJECTED
781            AND    NVL(intf_line2.price_break_flag, 'N') = 'N');
782   d_position := 150;
783   PO_PDOI_UTL.reject_lines_intf
784   (
785     p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_ID,
786     p_id_tbl          => l_rej_intf_line_id_tbl,
787     p_cascade         => FND_API.g_TRUE
788   );
789 
790   d_position := 160;
791 
792   -- set status to NOTIFIED for price break lines if main po line is NOTIFIED
793   UPDATE po_lines_interface intf_line1
794   SET    intf_line1.process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_NOTIFIED
795   WHERE  intf_line1.processing_id = PO_PDOI_PARAMS.g_processing_id
796   AND    intf_line1.price_break_flag = 'Y'
797   AND    EXISTS(
798            SELECT 'Y'
799            FROM   po_lines_interface intf_line2
800            WHERE  intf_line2.interface_header_id = intf_line1.interface_header_id
801            AND    intf_line2.po_line_id = intf_line1.po_line_id
802            AND    NVL(intf_line2.process_code, PO_PDOI_CONSTANTS.g_PROCESS_CODE_PENDING)
803 		            = PO_PDOI_CONSTANTS.g_PROCESS_CODE_NOTIFIED
804            AND    NVL(intf_line2.price_break_flag, 'N') = 'N');
805 
806   IF (PO_LOG.d_proc) THEN
807     PO_LOG.proc_end(d_module);
808   END IF;
809 
810 EXCEPTION
811   WHEN OTHERS THEN
812     PO_MESSAGE_S.add_exc_msg
813     (
814       p_pkg_name => d_pkg_name,
815       p_procedure_name => d_api_name || '.' || d_position
816     );
817     RAISE;
818 END process_lines_add;
819 
820 -----------------------------------------------------------------------
821 --Start of Comments
822 --Name: process_lines_sync
823 --Function: This procedure will deal with two kinds of data set from
824 --          calling procedure:
825 --  Third Set: Header level action is 'UPDATE' and document type is
826 --             'BLANKET' or 'QUOTATION'; And line level action is 'SYNC'
827 --             or Null; And either of the following criteria is true:
828 --             1. one of attributes {item, vendor_product_num, job} is not null
829 --             2. if {item, vendor_product_num, job) are all null, then
830 --                description must be null
831 --  Fourth Set: Header level action is 'UPDATE' and document type is
832 --             'BLANKET' or 'QUOTATION'; And line level action is 'SYNC'
833 --             or Null; {item, vendor_product_num, job) are all null and
834 --             description is not null
835 --
836 --Parameters:
837 --IN:
838 --  p_data_set_type
839 --  the value determines which data set is going to be processed:
840 --  PO_PDOI_CONSTANTS.g_LINE_CSR_SYNC: third data set
841 --  PO_PDOI_CONSTANTS.g_LINE_CSR_SYNC_ON_DESC: fourth data set
842 --IN OUT:
843 --OUT:
844 --End of Comments
845 ------------------------------------------------------------------------
846 PROCEDURE process_lines_sync
847 (
848   p_data_set_type IN NUMBER
849 ) IS
850 
851   d_api_name CONSTANT VARCHAR2(30) := 'process_lines_sync';
852   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
853   d_position NUMBER;
854 
855   -- cursor variable defined for the query
856   l_lines_csr            PO_PDOI_TYPES.intf_cursor_type;
857 
858   -- all line attribute values within a batch
859   l_lines                PO_PDOI_TYPES.lines_rec_type;
860 
861   -- variable to track the largest intf_line_id processed so far
862   l_max_intf_line_id     NUMBER := -1;
863 
864   -- lines that are going to be created/updated
865   l_create_lines         PO_PDOI_TYPES.lines_rec_type;
866   l_update_lines         PO_PDOI_TYPES.lines_rec_type;
867 
868   /*  bug 6926550 Added the following variable to null the
869   l_create_lines and l_update_lines inside the procedure*/
870   l_null_lines         PO_PDOI_TYPES.lines_rec_type;
871 
872   -- line grouping num
873   l_group_num            NUMBER := 0;
874 
875   -- variable to track records that have not been processed
876   l_processing_row_tbl   DBMS_SQL.NUMBER_TABLE;
877 
878   -- variable to track lines that need to be expired
879   l_expire_line_id_tbl   DBMS_SQL.NUMBER_TABLE;
880 
881   l_rej_intf_line_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
882   l_notified_intf_line_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
883 
884 BEGIN
885   d_position := 0;
886 
887   IF (PO_LOG.d_proc) THEN
888     PO_LOG.proc_begin(d_module, 'p_data_set_type', p_data_set_type);
889   END IF;
890 
891   -- Bug 5215781:
892   -- exit immediately if error threshold is hit for CATALOG UPLOAD
893   IF (PO_PDOI_PARAMS.g_request.calling_module =
894         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
895       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
896         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
897     IF (PO_LOG.d_stmt) THEN
898       PO_LOG.stmt(d_module, d_position, 'Exit from process_lines_sync since' ||
899                   ' error threshold is hit for header ',
900                   PO_PDOI_PARAMS.g_request.interface_header_id);
901     END IF;
902 
903     RETURN;
904   END IF;
905 
906   d_position := 5;
907 
908   -- open cursor for the correct query
909   PO_PDOI_LINE_PROCESS_PVT.open_lines
910   (
911     p_data_set_type      => p_data_set_type,
912     p_max_intf_line_id   => l_max_intf_line_id,
913     x_lines_csr          => l_lines_csr
914   );
915 
916   d_position := 10;
917 
918   -- fetch records from line interface table and process the records
919   LOOP
920     -- Bug 5215781:
921     -- check whether num of error lines exceeds the error
922     -- threshold for the previous batch
923     IF (PO_PDOI_PARAMS.g_request.calling_module =
924           PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
925         PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
926           .err_tolerance_exceeded = FND_API.g_TRUE) THEN
927       d_position := 20;
928 
929       IF (PO_LOG.d_stmt) THEN
930         PO_LOG.stmt(d_module, d_position, 'error tolerance exceeded for',
931                     PO_PDOI_PARAMS.g_request.interface_header_id);
932       END IF;
933 
934       EXIT;
935     END IF;
936 
937     BEGIN
938       -- fetch one batch of line records from query result
939       PO_PDOI_LINE_PROCESS_PVT.fetch_lines
940       (
941         x_lines_csr   => l_lines_csr,
942         x_lines       => l_lines
943       );
944 
945       d_position := 30;
946 
947       -- number of records read in current batch
948       l_lines.rec_count := l_lines.intf_line_id_tbl.COUNT;
949 
950       IF (PO_LOG.d_stmt) THEN
951         PO_LOG.stmt(d_module, d_position, 'line count in batch',
952                     l_lines.rec_count);
953       END IF;
954 
955       EXIT WHEN l_lines.rec_count = 0;
956 
957       /* <bug 6926550> null the l_create_lines and l_update_lines
958          before calling split lines procedure in the inner loop*/
959           l_create_lines  := l_null_lines;
960           l_update_lines  := l_null_lines;
961 
962       -- set up hashtable between interface_line_id and index
963       l_lines.intf_id_index_tbl.DELETE;
964 
965       FOR i IN 1..l_lines.rec_count
966       LOOP
967         l_lines.intf_id_index_tbl(l_lines.intf_line_id_tbl(i)) := i;
968       END LOOP;
969 
970       -- calculate max_line_num for all document in this batch
971       -- the result is saved and used in line processing
972       PO_PDOI_MAINPROC_UTL_PVT.calculate_max_line_num
973       (
974         p_po_header_id_tbl    => l_lines.hd_po_header_id_tbl,
975         p_draft_id_tbl        => l_lines.draft_id_tbl
976       );
977 
978       d_position := 40;
979 
980       -- check whether provided line_num is unique across interface,
981       -- draft and txn tables
982       PO_PDOI_MAINPROC_UTL_PVT.check_line_num_unique
983       (
984         p_po_header_id_tbl    => l_lines.hd_po_header_id_tbl,
985         p_draft_id_tbl        => l_lines.draft_id_tbl,
986         p_intf_line_id_tbl    => l_lines.intf_line_id_tbl,
987         p_line_num_tbl        => l_lines.line_num_tbl,
988         x_line_num_unique_tbl => l_lines.line_num_unique_tbl
989       );
990 
991       d_position := 50;
992 
993       -- setup table to track rows that have not been processed
994       PO_PDOI_UTL.generate_ordered_num_list
995       (
996         p_size      => l_lines.rec_count,
997         x_num_list  => l_processing_row_tbl
998       );
999 
1000       -- inner loop to process line records in groups
1001       -- If same line is created and updated within the same batch,
1002       -- they must be processed in separate groups
1003       LOOP
1004         -- exit when all rows are processed
1005         IF (l_processing_row_tbl.COUNT = 0) THEN
1006           d_position := 60;
1007 
1008           IF (PO_LOG.d_stmt) THEN
1009             PO_LOG.stmt(d_module, d_position, 'exit after all lines are processed');
1010           END IF;
1011 
1012           EXIT;
1013         END IF;
1014 
1015         -- increment group number
1016         l_group_num := l_group_num + 1;
1017 
1018         IF (PO_LOG.d_stmt) THEN
1019           PO_LOG.stmt(d_module, d_position, 'group_num', l_group_num);
1020         END IF;
1021 
1022         -- perform uniqueness check on all the records and
1023         -- mark the group number on the records that can be processed
1024         -- within a group
1025         PO_PDOI_LINE_PROCESS_PVT.uniqueness_check
1026         (
1027           p_type                  => p_data_set_type,
1028           p_group_num             => l_group_num,
1029           x_processing_row_tbl    => l_processing_row_tbl,
1030           x_lines                 => l_lines,
1031           x_expire_line_id_tbl    => l_expire_line_id_tbl
1032         );
1033 
1034         d_position := 70;
1035 
1036         -- separate data records into two set, one for create and one for update
1037         PO_PDOI_LINE_PROCESS_PVT.split_lines
1038         (
1039           p_group_num             => l_group_num,
1040           p_lines                 => l_lines,
1041           x_create_lines          => l_create_lines,
1042           x_update_lines          => l_update_lines
1043         );
1044 
1045         d_position := 80;
1046 
1047         -- process all rows that needs to be created
1048         process_create_lines_in_group
1049         (
1050           p_group_num             => l_group_num,
1051           p_expire_line_id_tbl    => l_expire_line_id_tbl,
1052           x_lines                 => l_create_lines
1053         );
1054 
1055         d_position := 90;
1056 
1057         -- process all the lines that need to be updated
1058         process_update_lines_in_group
1059         (
1060           p_group_num            => l_group_num,
1061           x_lines                => l_update_lines
1062         );
1063       END LOOP;
1064 
1065       PO_PDOI_UTL.commit_work;
1066 
1067       -- set the maximal interface_line_id processed in this batch
1068       l_max_intf_line_id := l_lines.intf_line_id_tbl(l_lines.rec_count);
1069 
1070       IF (l_lines.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
1071         EXIT;
1072       END IF;
1073     EXCEPTION
1074       WHEN g_snap_shot_too_old THEN
1075         d_position := 100;
1076 
1077         -- log error
1078         PO_MESSAGE_S.add_exc_msg
1079         (
1080           p_pkg_name => d_pkg_name,
1081           p_procedure_name => d_api_name || '.' || d_position
1082         );
1083 
1084         -- commit changes
1085         PO_PDOI_UTL.commit_work;
1086 
1087         IF (l_lines_csr%ISOPEN) THEN
1088           CLOSE l_lines_csr;
1089           PO_PDOI_LINE_PROCESS_PVT.open_lines
1090           (
1091             p_data_set_type      => p_data_set_type,
1092             p_max_intf_line_id   => l_max_intf_line_id,
1093             x_lines_csr          => l_lines_csr
1094           );
1095         END IF;
1096     END;
1097   END LOOP;
1098 
1099   d_position := 110;
1100 
1101   -- close the cursor
1102   IF (l_lines_csr%ISOPEN) THEN
1103     CLOSE l_lines_csr;
1104   END IF;
1105 
1106   d_position := 120;
1107 
1108   -- reject lines that are price breaks if main po line failed
1109   SELECT v.interface_line_id
1110   BULK COLLECT INTO l_rej_intf_line_id_tbl
1111   FROM   po_lines_interface intf_line1,
1112          (SELECT intf_line2.interface_line_id, max(intf_line3.interface_line_id) AS match_intf_line_id
1113           FROM   po_lines_interface intf_line2, po_lines_interface intf_line3,
1114                  po_headers_interface intf_headers
1115           WHERE  intf_line2.interface_header_id = intf_headers.interface_header_id
1116           AND    intf_headers.processing_id = PO_PDOI_PARAMS.g_processing_id
1117           AND    intf_headers.processing_round_num = PO_PDOI_PARAMS.g_current_round_num
1118           AND    intf_line2.price_break_flag = 'Y'
1119           AND    intf_line2.processing_id = PO_PDOI_PARAMS.g_processing_id
1120           AND    intf_line2.interface_header_id = intf_line3.interface_header_id
1121           AND    intf_line2.po_line_id = intf_line3.po_line_id
1122           AND    NVL(intf_line3.price_break_flag, 'N') = 'N'
1123           AND    intf_line3.interface_line_id < intf_line2.interface_line_id
1124           GROUP BY intf_line2.interface_line_id) v
1125   WHERE   intf_line1.interface_line_id = v.match_intf_line_id
1126   AND     NVL(intf_line1.process_code, PO_PDOI_CONSTANTS.g_PROCESS_CODE_PENDING)
1127             = PO_PDOI_CONSTANTS.g_PROCESS_CODE_REJECTED;
1128 
1129   d_position := 130;
1130 
1131   PO_PDOI_UTL.reject_lines_intf
1132   (
1133     p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_ID,
1134     p_id_tbl          => l_rej_intf_line_id_tbl,
1135     p_cascade         => FND_API.g_TRUE
1136   );
1137 
1138   d_position := 140;
1139 
1140   -- set status to NOTIFIED for price break lines if main po line is NOTIFIED
1141   SELECT v.interface_line_id
1142   BULK COLLECT INTO l_notified_intf_line_id_tbl
1143   FROM   po_lines_interface intf_line1,
1144          (SELECT intf_line2.interface_line_id, max(intf_line3.interface_line_id) AS match_intf_line_id
1145           FROM   po_lines_interface intf_line2, po_lines_interface intf_line3,
1146                  po_headers_interface intf_headers
1147           WHERE  intf_line2.interface_header_id = intf_headers.interface_header_id
1148           AND    intf_headers.processing_id = PO_PDOI_PARAMS.g_processing_id
1149           AND    intf_headers.processing_round_num = PO_PDOI_PARAMS.g_current_round_num
1150           AND    intf_line2.price_break_flag = 'Y'
1151           AND    intf_line2.processing_id = PO_PDOI_PARAMS.g_processing_id
1152           AND    intf_line2.interface_header_id = intf_line3.interface_header_id
1153           AND    intf_line2.po_line_id = intf_line3.po_line_id
1154           AND    NVL(intf_line3.price_break_flag, 'N') = 'N'
1155           AND    intf_line3.interface_line_id < intf_line2.interface_line_id
1156           GROUP BY intf_line2.interface_line_id) v
1157   WHERE   intf_line1.interface_line_id = v.match_intf_line_id
1158   AND     NVL(intf_line1.process_code, PO_PDOI_CONSTANTS.g_PROCESS_CODE_PENDING)
1159             = PO_PDOI_CONSTANTS.g_PROCESS_CODE_NOTIFIED;
1160 
1161   d_position := 150;
1162 
1163   FORALL i IN 1..l_notified_intf_line_id_tbl.COUNT
1164     UPDATE po_lines_interface
1165     SET    process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_NOTIFIED
1166     WHERE  interface_line_id = l_notified_intf_line_id_tbl(i);
1167 
1168   d_position := 160;
1169 
1170   IF (PO_LOG.d_proc) THEN
1171     PO_LOG.proc_end(d_module);
1172   END IF;
1173 
1174 EXCEPTION
1175   WHEN OTHERS THEN
1176     PO_MESSAGE_S.add_exc_msg
1177     (
1178       p_pkg_name => d_pkg_name,
1179       p_procedure_name => d_api_name || '.' || d_position
1180     );
1181     RAISE;
1182 END process_lines_sync;
1183 
1184 -----------------------------------------------------------------------
1185 --Start of Comments
1186 --Name: process_create_lines_in_group
1187 --Function: Data set 3 and 4 contains lines of mixed actions. After the
1188 --          action is determined by uniqueness logic, lines with same
1189 --          actions will be grouped together and processed separately
1190 --          from lines with different actions.
1191 --          This procedure is to deal with lines whose action is 'ADD'.
1192 --Parameters:
1193 --IN:
1194 --  p_group_num
1195 --    the current processing group number. Only lines belonging to
1196 --    current group will be processed.
1197 --  p_expire_line_id_tbl
1198 --    The lines that need to be expired
1199 --IN OUT:
1200 --  x_lines
1201 --    contains all lines within the batch
1202 --OUT:
1203 --End of Comments
1204 ------------------------------------------------------------------------
1205 PROCEDURE process_create_lines_in_group
1206 (
1207   p_group_num          IN NUMBER,
1208   p_expire_line_id_tbl IN DBMS_SQL.NUMBER_TABLE,
1209   x_lines              IN OUT NOCOPY PO_PDOI_TYPES.lines_rec_type
1210 ) IS
1211 
1212   d_api_name CONSTANT VARCHAR2(30) := 'process_create_lines_in_group';
1213   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
1214   d_position NUMBER;
1215 
1216   -- variables to track the records that need to be rejected due
1217   -- to errors in the processing
1218   l_count  NUMBER := 0;
1219   l_rej_intf_line_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
1220 
1221 BEGIN
1222   d_position := 0;
1223 
1224   IF (PO_LOG.d_proc) THEN
1225     PO_LOG.proc_begin(d_module, 'p_group_num', p_group_num);
1226     PO_LOG.proc_begin(d_module, 'count of lines', x_lines.rec_count);
1227   END IF;
1228 
1229   -- return if there is no line to be processed
1230   IF (x_lines.rec_count = 0) THEN
1231     IF (PO_LOG.d_proc) THEN
1232       PO_LOG.proc_end(d_module);
1233     END IF;
1234 
1235     RETURN;
1236   END IF;
1237 
1238   -- derive logic
1239   PO_PDOI_LINE_PROCESS_PVT.derive_lines
1240   (
1241     x_lines    => x_lines
1242   );
1243 
1244   d_position := 10;
1245 
1246   -- default logic
1247   PO_PDOI_LINE_PROCESS_PVT.default_lines
1248   (
1249     x_lines    => x_lines
1250   );
1251 
1252   d_position := 20;
1253 
1254   -- validate lines
1255   PO_PDOI_LINE_PROCESS_PVT.validate_lines
1256   (
1257     x_lines    => x_lines
1258   );
1259 
1260   d_position := 30;
1261 
1262   -- check whether line location needs to be created for the line
1263   PO_PDOI_LINE_PROCESS_PVT.check_line_locations
1264   (
1265     x_lines    => x_lines
1266   );
1267 
1268   d_position := 40;
1269 
1270   -- create items if necessary
1271   IF (PO_PDOI_PARAMS.g_request.create_items = 'Y') THEN
1272     IF (PO_LOG.d_stmt) THEN
1273       PO_LOG.stmt(d_module, d_position, 'create items from line info');
1274     END IF;
1275 
1276     PO_PDOI_ITEM_PROCESS_PVT.create_items
1277     (
1278       x_lines         => x_lines
1279     );
1280   END IF;
1281 
1282   d_position := 50;
1283 
1284   -- insert lines into draft table
1285   PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_lines
1286   (
1287     x_lines    => x_lines
1288   );
1289 
1290   d_position := 60;
1291 
1292   -- update po_lines_interface with po_line_id and line level action
1293   PO_PDOI_LINE_PROCESS_PVT.update_line_intf_tbl
1294   (
1295     x_lines    => x_lines
1296   );
1297 
1298   d_position := 70;
1299 
1300   -- reject lines with errors
1301   l_rej_intf_line_id_tbl.EXTEND(x_lines.rec_count);
1302   FOR i IN 1..x_lines.rec_count
1303   LOOP
1304     IF (x_lines.error_flag_tbl(i) = FND_API.g_TRUE OR
1305         x_lines.need_to_reject_flag_tbl(i) = FND_API.g_TRUE) THEN
1306       IF (PO_LOG.d_stmt) THEN
1307         PO_LOG.stmt(d_module, d_position, 'error flag',
1308                     x_lines.error_flag_tbl(i));
1309         PO_LOG.stmt(d_module, d_position, 'reject flag',
1310                     x_lines.need_to_reject_flag_tbl(i));
1311         PO_LOG.stmt(d_module, d_position, 'rejected intf line id',
1312                     x_lines.intf_line_id_tbl(i));
1313       END IF;
1314 
1315       l_count := l_count + 1;
1316       l_rej_intf_line_id_tbl(l_count) := x_lines.intf_line_id_tbl(i);
1317     END IF;
1318   END LOOP;
1319   PO_PDOI_UTL.reject_lines_intf
1320   (
1321     p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_ID,
1322     p_id_tbl          => l_rej_intf_line_id_tbl,
1323     p_cascade         => FND_API.g_TRUE
1324   );
1325   l_rej_intf_line_id_tbl.DELETE;
1326 
1327   d_position := 80;
1328 
1329   -- expire blanket lines being replaced. They are replaced since it has
1330   -- release shipment and uom is changed in the new request
1331   FORALL i IN 1..p_expire_line_id_tbl.COUNT
1332   UPDATE po_lines_all
1333   SET expiration_date = TRUNC(sysdate - 1)
1334   WHERE po_line_id = p_expire_line_id_tbl(i);
1335 
1336   IF (PO_LOG.d_proc) THEN
1337     PO_LOG.proc_end(d_module);
1338   END IF;
1339 
1340 EXCEPTION
1341   WHEN OTHERS THEN
1342     PO_MESSAGE_S.add_exc_msg
1343     (
1344       p_pkg_name => d_pkg_name,
1345       p_procedure_name => d_api_name || '.' || d_position
1346     );
1347     RAISE;
1348 END process_create_lines_in_group;
1349 
1350 -----------------------------------------------------------------------
1351 --Start of Comments
1352 --Name: process_update_lines_in_group
1353 --Function: Data set 3 and 4 contains lines of mixed actions. After the
1354 --          action is determined by uniqueness logic, lines with same
1355 --          actions will be grouped together and processed separately
1356 --          from lines with different actions.
1357 --          This procedure is to deal with lines whose action is 'UPDATE'
1358 --Parameters:
1359 --  p_group_num
1360 --    the current processing group number. Only lines belonging to
1361 --    current group will be processed.
1362 --IN OUT:
1363 --  x_lines
1364 --    contains all lines within the batch
1365 --OUT:
1366 --End of Comments
1367 ------------------------------------------------------------------------
1368 PROCEDURE process_update_lines_in_group
1369 (
1370   p_group_num           IN NUMBER,
1371   x_lines               IN OUT NOCOPY PO_PDOI_TYPES.lines_rec_type
1372 ) IS
1373 
1374   d_api_name CONSTANT VARCHAR2(30) := 'process_update_lines_in_group';
1375   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
1376   d_position NUMBER;
1377 
1378   -- variables to track the records that need to be rejected due
1379   -- to errors in the processing
1380   l_count  NUMBER := 0;
1381   l_rej_intf_line_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
1382 
1383 BEGIN
1384   d_position := 0;
1385 
1386   IF (PO_LOG.d_proc) THEN
1387     PO_LOG.proc_begin(d_module, 'p_group_num', p_group_num);
1388     PO_LOG.proc_begin(d_module, 'count of lines', x_lines.rec_count);
1389   END IF;
1390 
1391   -- return if there is no line to be processed
1392   IF (x_lines.rec_count = 0) THEN
1393     IF (PO_LOG.d_proc) THEN
1394       PO_LOG.proc_end(d_module);
1395     END IF;
1396 
1397     RETURN;
1398   END IF;
1399 
1400   -- derive internal identifier for updatable attributes
1401   PO_PDOI_LINE_PROCESS_PVT.derive_lines_for_update
1402   (
1403     x_lines    => x_lines
1404   );
1405 
1406   -- default certain attributes for processing purpose
1407   PO_PDOI_LINE_PROCESS_PVT.default_lines_for_update
1408   (
1409     x_lines    => x_lines
1410   );
1411 
1412   -- validate lines
1413   PO_PDOI_LINE_PROCESS_PVT.validate_lines
1414   (
1415     p_action   => 'UPDATE',
1416     x_lines    => x_lines
1417   );
1418 
1419   d_position := 10;
1420 
1421   -- check whether line location needs to be created for the line
1422   PO_PDOI_LINE_PROCESS_PVT.check_line_locations
1423   (
1424     x_lines    => x_lines
1425   );
1426 
1427   d_position := 20;
1428 
1429   -- update lines on draft table
1430   PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.update_lines
1431   (
1432     x_lines    => x_lines
1433   );
1434 
1435   d_position := 30;
1436 
1437   -- update po_lines_interface with po_line_id and line level action
1438   PO_PDOI_LINE_PROCESS_PVT.update_line_intf_tbl
1439   (
1440     x_lines    => x_lines
1441   );
1442 
1443   d_position := 40;
1444 
1445   -- set rejected status to lines and lower levels
1446   l_rej_intf_line_id_tbl.EXTEND(x_lines.rec_count);
1447   FOR i IN 1..x_lines.rec_count
1448   LOOP
1449     IF (x_lines.error_flag_tbl(i) = FND_API.g_TRUE OR
1450         x_lines.need_to_reject_flag_tbl(i) = FND_API.g_TRUE) THEN
1451       IF (PO_LOG.d_stmt) THEN
1452         PO_LOG.stmt(d_module, d_position, 'error flag',
1453                     x_lines.error_flag_tbl(i));
1454         PO_LOG.stmt(d_module, d_position, 'reject flag',
1455                     x_lines.need_to_reject_flag_tbl(i));
1456         PO_LOG.stmt(d_module, d_position, 'rejected intf line id',
1457                     x_lines.intf_line_id_tbl(i));
1458       END IF;
1459 
1460       l_count := l_count + 1;
1461       l_rej_intf_line_id_tbl(l_count) := x_lines.intf_line_id_tbl(i);
1462     END IF;
1463   END LOOP;
1464   PO_PDOI_UTL.reject_lines_intf
1465   (
1466     p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_ID,
1467     p_id_tbl          => l_rej_intf_line_id_tbl,
1468     p_cascade         => FND_API.g_TRUE
1469   );
1470   l_rej_intf_line_id_tbl.DELETE;
1471 
1472   IF (PO_LOG.d_proc) THEN
1473     PO_LOG.proc_end(d_module);
1474   END IF;
1475 
1476 EXCEPTION
1477   WHEN OTHERS THEN
1478     PO_MESSAGE_S.add_exc_msg
1479     (
1480       p_pkg_name => d_pkg_name,
1481       p_procedure_name => d_api_name || '.' || d_position
1482     );
1483     RAISE;
1484 END process_update_lines_in_group;
1485 
1486 -------------------------------------------------------------------------
1487 --Start of Comments
1488 --Name: process_line_locations
1489 --Pre-reqs: None
1490 --Modifies:
1491 --Locks:
1492 --  None
1493 --Function:
1494 --  handle the logic to derive, default, validate and insert records
1495 --  from po_line_locations_interface table
1496 --Parameters:
1497 --IN: None
1498 --IN OUT: None
1499 --OUT: None
1500 --Returns:
1501 --Notes:
1502 --Testing:
1503 --End of Comments
1504 ------------------------------------------------------------------------
1505 PROCEDURE process_line_locations IS
1506 
1507   d_api_name CONSTANT VARCHAR2(30) := 'process_line_locations';
1508   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
1509   d_position NUMBER;
1510 
1511   -- cursor variable defined for the query
1512   l_line_locs_csr PO_PDOI_TYPES.intf_cursor_type;
1513 
1514   -- all line location attribute values within a batch
1515   l_line_locs PO_PDOI_TYPES.line_locs_rec_type;
1516 
1517   -- variables to track the records that need to be rejected due
1518   -- to errors in the processing
1519   l_rej_intf_line_loc_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
1520 
1521   -- keep record of lines processed in this request
1522   -- the record will be used in post line location processing
1523   l_processed_line_id_tbl  DBMS_SQL.number_table;
1524   l_processed_draft_id_tbl DBMS_SQL.number_table;
1525   l_line_ref_tbl           DBMS_SQL.number_table;
1526 
1527   -- maximal interface_line_location_id_processed
1528   l_max_intf_line_loc_id   NUMBER := -1;
1529 
1530   l_count NUMBER;
1531 BEGIN
1532   d_position := 0;
1533 
1534   IF (PO_LOG.d_proc) THEN
1535     PO_LOG.proc_begin(d_module);
1536   END IF;
1537 
1538   -- Bug 5215781:
1539   -- exit immediately if error threshold is hit for CATALOG UPLOAD
1540   IF (PO_PDOI_PARAMS.g_request.calling_module =
1541         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
1542       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
1543         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
1544     IF (PO_LOG.d_stmt) THEN
1545       PO_LOG.stmt(d_module, d_position, 'Exit from process_line_locations since' ||
1546                   ' error threshold is hit for header ',
1547                   PO_PDOI_PARAMS.g_request.interface_header_id);
1548     END IF;
1549 
1550     RETURN;
1551   END IF;
1552 
1553   d_position := 5;
1554 
1555   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_LINE_LOC_PROCESS);
1556 
1557   -- open cursor for the correct query
1558   PO_PDOI_LINE_LOC_PROCESS_PVT.open_line_locs
1559   (
1560     p_max_intf_line_loc_id   => l_max_intf_line_loc_id,
1561     x_line_locs_csr          => l_line_locs_csr
1562   );
1563 
1564   d_position := 10;
1565 
1566   -- fetch records from line location interface table and process the records
1567   LOOP
1568     -- Bug 5215781:
1569     -- check whether num of error lines exceeds the error
1570     -- threshold for the previous batch
1571     IF (PO_PDOI_PARAMS.g_request.calling_module =
1572           PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
1573         PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
1574           .err_tolerance_exceeded = FND_API.g_TRUE) THEN
1575       d_position := 20;
1576 
1577       IF (PO_LOG.d_stmt) THEN
1578         PO_LOG.stmt(d_module, d_position, 'error tolerance exceeded for',
1579                     PO_PDOI_PARAMS.g_request.interface_header_id);
1580       END IF;
1581 
1582       EXIT;
1583     END IF;
1584 
1585     BEGIN
1586       -- fetch one batch of line location records from query result
1587       PO_PDOI_LINE_LOC_PROCESS_PVT.fetch_line_locs
1588       (
1589         x_line_locs_csr   => l_line_locs_csr,
1590         x_line_locs       => l_line_locs
1591       );
1592 
1593       d_position := 20;
1594 
1595       -- number of records read in current batch
1596       l_line_locs.rec_count := l_line_locs.intf_line_loc_id_tbl.COUNT;
1597 
1598       IF (PO_LOG.d_stmt) THEN
1599         PO_LOG.stmt(d_module, d_position, 'loc count in batch',
1600                     l_line_locs.rec_count);
1601       END IF;
1602 
1603       EXIT WHEN l_line_locs.rec_count = 0;
1604 
1605       -- set up hashtable between interface_line_location_id and index
1606       l_line_locs.intf_id_index_tbl.DELETE;
1607 
1608       FOR i IN 1..l_line_locs.rec_count
1609       LOOP
1610         l_line_locs.intf_id_index_tbl(l_line_locs.intf_line_loc_id_tbl(i)) := i;
1611       END LOOP;
1612 
1613       -- calculate max_shipment_num for each line in this batch
1614       -- the result is saved and used in line location processing
1615       PO_PDOI_MAINPROC_UTL_PVT.calculate_max_shipment_num
1616       (
1617         p_po_line_id_tbl     => l_line_locs.ln_po_line_id_tbl,
1618         p_draft_id_tbl       => l_line_locs.draft_id_tbl
1619       );
1620 
1621       d_position := 30;
1622 
1623       -- check whether provided shipment_num is unqiue across interface,
1624       -- draft and txn tables.
1625       -- logic is performed for Standard PO only
1626       IF (PO_PDOI_PARAMS.g_request.document_type =
1627           PO_PDOI_CONSTANTS.g_DOC_TYPE_STANDARD) THEN
1628         PO_PDOI_MAINPROC_UTL_PVT.check_shipment_num_unique
1629         (
1630           p_po_line_id_tbl            => l_line_locs.ln_po_line_id_tbl,
1631           p_draft_id_tbl              => l_line_locs.draft_id_tbl,
1632           p_intf_line_loc_id_tbl      => l_line_locs.intf_line_loc_id_tbl,
1633           p_shipment_num_tbl          => l_line_locs.shipment_num_tbl,
1634           x_shipment_num_unique_tbl   => l_line_locs.shipment_num_unique_tbl
1635         );
1636       END IF;
1637 
1638       d_position := 40;
1639 
1640       -- derive logic
1641       PO_PDOI_LINE_LOC_PROCESS_PVT.derive_line_locs
1642       (
1643         x_line_locs               => l_line_locs
1644       );
1645 
1646       d_position := 50;
1647 
1648       -- default logic
1649       PO_PDOI_LINE_LOC_PROCESS_PVT.default_line_locs
1650       (
1651         x_line_locs               => l_line_locs
1652       );
1653 
1654       d_position := 60;
1655 
1656       -- validate logic
1657       PO_PDOI_LINE_LOC_PROCESS_PVT.validate_line_locs
1658       (
1659         x_line_locs               => l_line_locs
1660       );
1661 
1662       d_position := 70;
1663 
1664       -- insert line locations into line location draft table
1665       PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_line_locs
1666       (
1667         p_line_locs              => l_line_locs
1668       );
1669 
1670       d_position := 80;
1671 
1672       -- update po_line_locations_interface with line_location_id
1673       PO_PDOI_LINE_LOC_PROCESS_PVT.update_line_loc_interface
1674       (
1675         p_intf_line_loc_id_tbl   => l_line_locs.intf_line_loc_id_tbl,
1676         p_line_loc_id_tbl        => l_line_locs.line_loc_id_tbl,
1677         p_error_flag_tbl         => l_line_locs.error_flag_tbl
1678       );
1679 
1680       d_position := 90;
1681 
1682       -- set rejected status to line locations and lower levels
1683       FOR i IN 1..l_line_locs.rec_count
1684       LOOP
1685         IF (l_line_locs.error_flag_tbl(i) = FND_API.G_TRUE) THEN
1686           l_rej_intf_line_loc_id_tbl.EXTEND;
1687           l_rej_intf_line_loc_id_tbl(l_rej_intf_line_loc_id_tbl.COUNT) := l_line_locs.intf_line_loc_id_tbl(i);
1688 
1689           -- bug 5215781:
1690           -- remove the logic here, same logic is moved to PO_PDOI_LINE_LOC_PROCESS_PVT
1691           /*
1692           -- bug4662687 START
1693           -- Report the lines that have shipment/price break errors
1694           IF (NOT PO_PDOI_PARAMS.g_errored_lines.EXISTS(l_line_locs.intf_line_id_tbl(i))) THEN
1695             PO_PDOI_PARAMS.g_errored_lines(l_line_locs.intf_line_id_tbl(i)) := 'Y';
1696             PO_PDOI_PARAMS.g_docs_info(l_line_locs.intf_header_id_tbl(i)).number_of_errored_lines
1697               := PO_PDOI_PARAMS.g_docs_info(l_line_locs.intf_header_id_tbl(i)).number_of_errored_lines +1;
1698 
1699           END IF;
1700           -- bug4662687 END
1701           */
1702         END IF;
1703       END LOOP;
1704 
1705       IF (PO_LOG.d_stmt) THEN
1706         PO_LOG.stmt(d_module, d_position, 'to-be-rejected locs',
1707                     l_rej_intf_line_loc_id_tbl);
1708       END IF;
1709 
1710       PO_PDOI_UTL.reject_line_locations_intf
1711       (
1712         p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_LINE_LOCATION_ID,
1713         p_id_tbl          => l_rej_intf_line_loc_id_tbl,
1714         p_cascade         => FND_API.g_TRUE
1715       );
1716       l_rej_intf_line_loc_id_tbl.DELETE;
1717 
1718       d_position := 100;
1719 
1720       -- keep track of lines that have location records processed
1721       l_count := 0;
1722       FOR i IN 1..l_line_locs.rec_count
1723       LOOP
1724         IF (NOT l_line_ref_tbl.EXISTS(l_line_locs.ln_po_line_id_tbl(i)) AND
1725 		    l_line_locs.error_flag_tbl(i) = FND_API.g_FALSE) THEN
1726           l_count := l_count + 1;
1727           l_processed_line_id_tbl(l_count) := l_line_locs.ln_po_line_id_tbl(i);
1728           l_processed_draft_id_tbl(l_count) := l_line_locs.draft_id_tbl(i);
1729           l_line_ref_tbl(l_line_locs.ln_po_line_id_tbl(i)) := i;
1730         END IF;
1731       END LOOP;
1732 
1733       -- commit
1734       PO_PDOI_UTL.commit_work;
1735 
1736       IF (l_line_locs.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
1737         EXIT;
1738       END IF;
1739 
1740       l_max_intf_line_loc_id := l_line_locs.intf_line_loc_id_tbl(l_line_locs.rec_count);
1741     EXCEPTION
1742       WHEN g_snap_shot_too_old THEN
1743         d_position := 110;
1744 
1745         -- log error
1746         PO_MESSAGE_S.add_exc_msg
1747         (
1748           p_pkg_name => d_pkg_name,
1749           p_procedure_name => d_api_name || '.' || d_position
1750         );
1751 
1752         -- commit changes
1753         PO_PDOI_UTL.commit_work;
1754 
1755         IF (l_line_locs_csr%ISOPEN) THEN
1756           CLOSE l_line_locs_csr;
1757           PO_PDOI_LINE_LOC_PROCESS_PVT.open_line_locs
1758           (
1759             p_max_intf_line_loc_id   => l_max_intf_line_loc_id,
1760             x_line_locs_csr          => l_line_locs_csr
1761           );
1762         END IF;
1763     END;
1764   END LOOP;
1765 
1766   d_position := 120;
1767 
1768   -- close the cursor
1769   IF (l_line_locs_csr%ISOPEN) THEN
1770     CLOSE l_line_locs_csr;
1771   END IF;
1772 
1773   -- line location post processing
1774   IF (PO_PDOI_PARAMS.g_request.document_type =
1775       PO_PDOI_CONSTANTS.g_DOC_TYPE_STANDARD) THEN
1776     d_position := 130;
1777 
1778     -- update amount or quantity value on po_lines_draft_all based
1779     -- on the values on shipment for Standard PO.
1780     PO_PDOI_LINE_LOC_PROCESS_PVT.update_amount_quantity_on_line
1781     (
1782       p_po_line_id_tbl      => l_processed_line_id_tbl,
1783       p_draft_id_tbl        => l_processed_draft_id_tbl
1784     );
1785   ELSIF (PO_PDOI_PARAMS.g_request.document_type =
1786          PO_PDOI_CONSTANTS.g_DOC_TYPE_QUOTATION) THEN
1787     d_position := 140;
1788 
1789     -- delete all existing price breaks for quotation update
1790     PO_PDOI_LINE_LOC_PROCESS_PVT.delete_exist_price_breaks
1791     (
1792       p_po_line_id_tbl      => l_processed_line_id_tbl,
1793       p_draft_id_tbl        => l_processed_draft_id_tbl
1794     );
1795   ELSE -- document_type = blanket
1796     d_position := 150;
1797 
1798     -- In previous implementation, price discount is updated based
1799     -- on price and price break. The logic is removed in R12.
1800     NULL;
1801   END IF;
1802 
1803   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_LINE_LOC_PROCESS);
1804 
1805   IF (PO_LOG.d_proc) THEN
1806     PO_LOG.proc_end(d_module);
1807   END IF;
1808 
1809 EXCEPTION
1810   WHEN OTHERS THEN
1811     PO_MESSAGE_S.add_exc_msg
1812     (
1813       p_pkg_name => d_pkg_name,
1814       p_procedure_name => d_api_name || '.' || d_position
1815     );
1816     RAISE;
1817 END process_line_locations;
1818 
1819 -------------------------------------------------------------------------
1820 --Start of Comments
1821 --Name: process_distributions
1822 --Pre-reqs: None
1823 --Modifies:
1824 --Locks:
1825 --  None
1826 --Function:
1827 --  handle the logic to derive, default, validate and insert records
1828 --  from po_distributions_interface table
1829 --Parameters:
1830 --IN: None
1831 --IN OUT: None
1832 --OUT: None
1833 --Returns:
1834 --Notes:
1835 --Testing:
1836 --End of Comments
1837 ------------------------------------------------------------------------
1838 PROCEDURE process_distributions IS
1839 
1840   d_api_name CONSTANT VARCHAR2(30) := 'process_distributions';
1841   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
1842   d_position NUMBER;
1843 
1844   -- record to hold distribution values read within a batch
1845   l_dists            PO_PDOI_TYPES.distributions_rec_type;
1846 
1847   -- cursor variable to point to currently processing row
1848   l_dists_csr         PO_PDOI_TYPES.intf_cursor_type;
1849 
1850   -- variables to track the records that need to be rejected due
1851   -- to errors in the processing
1852   l_rej_intf_dist_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
1853 
1854   -- maximal interface_line_location_id_processed
1855   l_max_intf_dist_id   NUMBER := -1;
1856 
1857 BEGIN
1858   d_position := 0;
1859 
1860   IF (PO_LOG.d_proc) THEN
1861     PO_LOG.proc_begin(d_module);
1862   END IF;
1863 
1864   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_DIST_PROCESS);
1865 
1866   -- open cursor for the correct query
1867   PO_PDOI_DIST_PROCESS_PVT.open_dists
1868   (
1869     p_max_intf_dist_id   => l_max_intf_dist_id,
1870     x_dists_csr          => l_dists_csr
1871   );
1872 
1873   d_position := 10;
1874 
1875   -- fetch records from distribution interface table and process the records
1876   LOOP
1877     BEGIN
1878       -- fetch one batch of distribution records from query result
1879       PO_PDOI_DIST_PROCESS_PVT.fetch_dists
1880       (
1881         x_dists_csr   => l_dists_csr,
1882         x_dists       => l_dists
1883       );
1884 
1885       d_position := 20;
1886 
1887       -- number of records read in current batch
1888       l_dists.rec_count := l_dists.intf_dist_id_tbl.COUNT;
1889 
1890       IF (PO_LOG.d_stmt) THEN
1891         PO_LOG.stmt(d_module, d_position, 'dist count in batch',
1892                     l_dists.rec_count);
1893       END IF;
1894 
1895       EXIT WHEN l_dists.rec_count = 0;
1896 
1897       -- calculate max distribution num for each line location
1898       -- in this batch
1899       -- the result is saved and used in distribution processing
1900       PO_PDOI_MAINPROC_UTL_PVT.calculate_max_dist_num
1901       (
1902         p_line_loc_id_tbl     => l_dists.loc_line_loc_id_tbl,
1903         p_draft_id_tbl        => l_dists.draft_id_tbl
1904       );
1905 
1906       d_position := 30;
1907 
1908       -- check whether the distribution num is unique per line location
1909       PO_PDOI_MAINPROC_UTL_PVT.check_dist_num_unique
1910       (
1911         p_line_loc_id_tbl     => l_dists.loc_line_loc_id_tbl,
1912         p_draft_id_tbl        => l_dists.draft_id_tbl,
1913         p_intf_dist_id_tbl    => l_dists.intf_dist_id_tbl,
1914         p_dist_num_tbl        => l_dists.dist_num_tbl,
1915         x_dist_num_unique_tbl => l_dists.dist_num_unique_tbl
1916       );
1917 
1918       d_position := 40;
1919 
1920       -- derive logic
1921       PO_PDOI_DIST_PROCESS_PVT.derive_dists
1922       (
1923         x_dists               => l_dists
1924       );
1925 
1926       d_position := 50;
1927 
1928       -- default logic
1929       PO_PDOI_DIST_PROCESS_PVT.default_dists
1930       (
1931         x_dists               => l_dists
1932       );
1933 
1934       d_position := 60;
1935 
1936       -- validate logic
1937       PO_PDOI_DIST_PROCESS_PVT.validate_dists
1938       (
1939         x_dists               => l_dists
1940       );
1941 
1942       d_position := 70;
1943 
1944       -- insert distributions into draft table
1945       PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_dists
1946       (
1947         p_dists               => l_dists
1948       );
1949 
1950       d_position := 80;
1951 
1952       -- set rejected status to distributions
1953       FOR i IN 1..l_dists.rec_count
1954       LOOP
1955         IF (l_dists.error_flag_tbl(i) = FND_API.G_TRUE) THEN
1956           l_rej_intf_dist_id_tbl.EXTEND;
1957           l_rej_intf_dist_id_tbl(l_rej_intf_dist_id_tbl.COUNT) := l_dists.intf_dist_id_tbl(i);
1958         END IF;
1959       END LOOP;
1960 
1961       IF (PO_LOG.d_stmt) THEN
1962         PO_LOG.stmt(d_module, d_position, 'to-be-rejected dists',
1963                     l_rej_intf_dist_id_tbl);
1964       END IF;
1965 
1966       d_position := 90;
1967 
1968       PO_PDOI_UTL.reject_distributions_intf
1969       (
1970         p_id_param_type   => PO_PDOI_CONSTANTS.g_INTERFACE_DISTRIBUTION_ID,
1971         p_id_tbl          => l_rej_intf_dist_id_tbl
1972       );
1973       l_rej_intf_dist_id_tbl.DELETE;
1974 
1975       d_position := 100;
1976 
1977       -- set status to ACCEPTED for records without errors on intf table
1978       FORALL i IN 1..l_dists.intf_dist_id_tbl.COUNT
1979       UPDATE po_distributions_interface
1980       SET    process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_ACCEPTED
1981       WHERE  interface_distribution_id = l_dists.intf_dist_id_tbl(i)
1982       AND    l_dists.error_flag_tbl(i) = FND_API.g_FALSE;
1983 
1984       d_position := 110;
1985 
1986       PO_PDOI_UTL.commit_work;
1987 
1988       IF (l_dists.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
1989         EXIT;
1990       END IF;
1991 
1992       l_max_intf_dist_id := l_dists.intf_dist_id_tbl(l_dists.rec_count);
1993     EXCEPTION
1994       WHEN g_snap_shot_too_old THEN
1995         d_position := 120;
1996 
1997         -- log error
1998         PO_MESSAGE_S.add_exc_msg
1999         (
2000           p_pkg_name => d_pkg_name,
2001           p_procedure_name => d_api_name || '.' || d_position
2002         );
2003 
2004         -- commit changes
2005         PO_PDOI_UTL.commit_work;
2006 
2007         IF (l_dists_csr%ISOPEN) THEN
2008           CLOSE l_dists_csr;
2009           PO_PDOI_DIST_PROCESS_PVT.open_dists
2010           (
2011             p_max_intf_dist_id   => l_max_intf_dist_id,
2012             x_dists_csr          => l_dists_csr
2013           );
2014         END IF;
2015     END;
2016   END LOOP;
2017 
2018   d_position := 130;
2019 
2020   -- close the cursor
2021   IF (l_dists_csr%ISOPEN) THEN
2022     CLOSE l_dists_csr;
2023   END IF;
2024 
2025   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_DIST_PROCESS);
2026 
2027   IF (PO_LOG.d_proc) THEN
2028     PO_LOG.proc_end(d_module);
2029   END IF;
2030 
2031 EXCEPTION
2032   WHEN OTHERS THEN
2033     PO_MESSAGE_S.add_exc_msg
2034     (
2035       p_pkg_name => d_pkg_name,
2036       p_procedure_name => d_api_name || '.' || d_position
2037     );
2038     RAISE;
2039 END process_distributions;
2040 
2041 -------------------------------------------------------------------------
2042 --Start of Comments
2043 --Name: process_price_diffs
2044 --Pre-reqs: None
2045 --Modifies:
2046 --Locks:
2047 --  None
2048 --Function:
2049 --  handle the logic to validate and insert records
2050 --  from po_price_diffs_interface table
2051 --Parameters:
2052 --IN: None
2053 --IN OUT: None
2054 --OUT: None
2055 --Returns:
2056 --Notes:
2057 --Testing:
2058 --End of Comments
2059 ------------------------------------------------------------------------
2060 PROCEDURE process_price_diffs IS
2061 
2062   d_api_name CONSTANT VARCHAR2(30) := 'process_price_diffs';
2063   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
2064   d_position NUMBER;
2065 
2066   -- record to hold price differential values read within a batch
2067   l_price_diffs            PO_PDOI_TYPES.price_diffs_rec_type;
2068 
2069   -- cursor variable to point to currently processing row
2070   l_price_diffs_csr        PO_PDOI_TYPES.intf_cursor_type;
2071 
2072   -- variables to track the records that need to be rejected due
2073   -- to errors in the processing
2074   l_rej_intf_price_diff_id_tbl PO_TBL_NUMBER := PO_TBL_NUMBER();
2075 
2076   -- maximal interface_price_diff_id_processed
2077   l_max_intf_price_diff_id   NUMBER := -1;
2078 
2079 BEGIN
2080   d_position := 0;
2081 
2082   IF (PO_LOG.d_proc) THEN
2083     PO_LOG.proc_begin(d_module);
2084   END IF;
2085 
2086   -- Bug 5215781:
2087   -- exit immediately if error threshold is hit for CATALOG UPLOAD
2088   IF (PO_PDOI_PARAMS.g_request.calling_module =
2089         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
2090       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
2091         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
2092     IF (PO_LOG.d_stmt) THEN
2093       PO_LOG.stmt(d_module, d_position, 'Exit from process_price_diffs since' ||
2094                   ' error threshold is hit for header ',
2095                   PO_PDOI_PARAMS.g_request.interface_header_id);
2096     END IF;
2097 
2098     RETURN;
2099   END IF;
2100 
2101   d_position := 5;
2102 
2103   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_PRICE_DIFF_PROCESS);
2104 
2105   -- open cursor for the correct query
2106   PO_PDOI_PRICE_DIFF_PROCESS_PVT.open_price_diffs
2107   (
2108     p_max_intf_price_diff_id   => l_max_intf_price_diff_id,
2109     x_price_diffs_csr          => l_price_diffs_csr
2110   );
2111 
2112   d_position := 10;
2113 
2114   -- fetch records from price differential interface table and process the records
2115   LOOP
2116     -- Bug 5215781:
2117     -- check whether num of error lines exceeds the error
2118     -- threshold for the previous batch
2119     IF (PO_PDOI_PARAMS.g_request.calling_module =
2120           PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
2121         PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
2122           .err_tolerance_exceeded = FND_API.g_TRUE) THEN
2123       d_position := 20;
2124 
2125       IF (PO_LOG.d_stmt) THEN
2126         PO_LOG.stmt(d_module, d_position, 'error tolerance exceeded for',
2127                     PO_PDOI_PARAMS.g_request.interface_header_id);
2128       END IF;
2129 
2130       EXIT;
2131     END IF;
2132 
2133     BEGIN
2134       -- fetch one batch of records from query result
2135       PO_PDOI_PRICE_DIFF_PROCESS_PVT.fetch_price_diffs
2136       (
2137         x_price_diffs_csr   => l_price_diffs_csr,
2138         x_price_diffs       => l_price_diffs
2139       );
2140 
2141       d_position := 30;
2142 
2143       -- number of records read in current batch
2144       l_price_diffs.rec_count := l_price_diffs.intf_price_diff_id_tbl.COUNT;
2145 
2146       IF (PO_LOG.d_stmt) THEN
2147         PO_LOG.stmt(d_module, d_position, 'price diffs in batch',
2148                     l_price_diffs.rec_count);
2149       END IF;
2150 
2151       EXIT WHEN l_price_diffs.rec_count = 0;
2152 
2153       PO_PDOI_PRICE_DIFF_PROCESS_PVT.default_price_diffs
2154       (
2155         x_price_diffs         => l_price_diffs
2156       );
2157 
2158       d_position := 40;
2159 
2160       -- validate logic
2161       PO_PDOI_PRICE_DIFF_PROCESS_PVT.validate_price_diffs
2162       (
2163         x_price_diffs         => l_price_diffs
2164       );
2165 
2166       d_position := 50;
2167 
2168       -- insert into draft table
2169       PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.insert_price_diffs
2170       (
2171         p_price_diffs         => l_price_diffs
2172       );
2173 
2174       d_position := 60;
2175 
2176       -- set rejected status
2177       FOR i IN 1..l_price_diffs.rec_count
2178       LOOP
2179         IF (l_price_diffs.error_flag_tbl(i) = FND_API.G_TRUE) THEN
2180           l_rej_intf_price_diff_id_tbl.EXTEND;
2181           l_rej_intf_price_diff_id_tbl(l_rej_intf_price_diff_id_tbl.COUNT) := l_price_diffs.intf_price_diff_id_tbl(i);
2182         END IF;
2183       END LOOP;
2184 
2185       IF (PO_LOG.d_stmt) THEN
2186         PO_LOG.stmt(d_module, d_position, 'to-be-rejected price diffs',
2187                     l_rej_intf_price_diff_id_tbl);
2188       END IF;
2189 
2190       PO_PDOI_UTL.reject_price_diff_intf
2191       (
2192         p_id_param_type   => PO_PDOI_CONSTANTS.g_PRICE_DIFF_INTERFACE_ID,
2193         p_id_tbl          => l_rej_intf_price_diff_id_tbl
2194       );
2195       l_rej_intf_price_diff_id_tbl.DELETE;
2196 
2197       d_position := 70;
2198 
2199       -- set status to ACCEPTED for records without errors on intf table
2200       FORALL i IN 1..l_price_diffs.intf_price_diff_id_tbl.COUNT
2201       UPDATE po_price_diff_interface
2202       SET    process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_ACCEPTED
2203       WHERE  price_diff_interface_id = l_price_diffs.intf_price_diff_id_tbl(i)
2204       AND    l_price_diffs.error_flag_tbl(i) = FND_API.g_FALSE;
2205 
2206       PO_PDOI_UTL.commit_work;
2207 
2208       IF (l_price_diffs.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
2209         EXIT;
2210       END IF;
2211 
2212       l_max_intf_price_diff_id := l_price_diffs.intf_price_diff_id_tbl(l_price_diffs.rec_count);
2213     EXCEPTION
2214       WHEN g_snap_shot_too_old THEN
2215         d_position := 80;
2216 
2217         -- log error
2218         PO_MESSAGE_S.add_exc_msg
2219         (
2220           p_pkg_name => d_pkg_name,
2221           p_procedure_name => d_api_name || '.' || d_position
2222         );
2223 
2224         -- commit changes
2225         PO_PDOI_UTL.commit_work;
2226 
2227         IF (l_price_diffs_csr%ISOPEN) THEN
2228           CLOSE l_price_diffs_csr;
2229           PO_PDOI_PRICE_DIFF_PROCESS_PVT.open_price_diffs
2230           (
2231             p_max_intf_price_diff_id   => l_max_intf_price_diff_id,
2232             x_price_diffs_csr          => l_price_diffs_csr
2233           );
2234         END IF;
2235     END;
2236   END LOOP;
2237 
2238   d_position := 90;
2239 
2240   -- close the cursor
2241   IF (l_price_diffs_csr%ISOPEN) THEN
2242     CLOSE l_price_diffs_csr;
2243   END IF;
2244 
2245   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_PRICE_DIFF_PROCESS);
2246 
2247   IF (PO_LOG.d_proc) THEN
2248     PO_LOG.proc_end(d_module);
2249   END IF;
2250 
2251 EXCEPTION
2252   WHEN OTHERS THEN
2253     PO_MESSAGE_S.add_exc_msg
2254     (
2255       p_pkg_name => d_pkg_name,
2256       p_procedure_name => d_api_name || '.' || d_position
2257     );
2258     RAISE;
2259 END process_price_diffs;
2260 
2261 -------------------------------------------------------------------------
2262 --Start of Comments
2263 --Name: process_attributes
2264 --Pre-reqs: None
2265 --Modifies:
2266 --Locks:
2267 --  None
2268 --Function:
2269 --  handle the logic to validate and insert records
2270 --  from po_attr_values_interface table and
2271 --  po_attr_values_tlp_interface table
2272 --Parameters:
2273 --IN: None
2274 --IN OUT: None
2275 --OUT: None
2276 --Returns:
2277 --Notes:
2278 --Testing:
2279 --End of Comments
2280 ------------------------------------------------------------------------
2281 PROCEDURE process_attributes IS
2282 
2283   d_api_name CONSTANT VARCHAR2(30) := 'process_attributes';
2284   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
2285   d_position NUMBER;
2286 
2287 BEGIN
2288   d_position := 0;
2289 
2290   IF (PO_LOG.d_proc) THEN
2291     PO_LOG.proc_begin(d_module);
2292   END IF;
2293 
2294   -- Bug 5215781:
2295   -- exit immediately if error threshold is hit for CATALOG UPLOAD
2296   IF (PO_PDOI_PARAMS.g_request.calling_module =
2297         PO_PDOI_CONSTANTS.g_CALL_MOD_CATALOG_UPLOAD AND
2298       PO_PDOI_PARAMS.g_docs_info(PO_PDOI_PARAMS.g_request.interface_header_id)
2299         .err_tolerance_exceeded = FND_API.g_TRUE) THEN
2300     IF (PO_LOG.d_stmt) THEN
2301       PO_LOG.stmt(d_module, d_position, 'Exit from process_attributes since' ||
2302                   ' error threshold is hit for header ',
2303                   PO_PDOI_PARAMS.g_request.interface_header_id);
2304     END IF;
2305 
2306     RETURN;
2307   END IF;
2308 
2309   d_position := 10;
2310 
2311   PO_TIMING_UTL.start_time(PO_PDOI_CONSTANTS.g_T_ATTR_PROCESS);
2312 
2313   -- process all lines in po_attr_values_interface table
2314   process_attr_values;
2315 
2316   d_position := 20;
2317 
2318   -- process all lines in po_attr_values_tlp_interface table
2319   process_attr_values_tlp;
2320 
2321   d_position := 30;
2322 
2323   -- add default attr_values and attr_values_tlp if not provided
2324   PO_PDOI_ATTR_PROCESS_PVT.add_default_attrs;
2325 
2326   d_position := 40;
2327 
2328   PO_TIMING_UTL.stop_time(PO_PDOI_CONSTANTS.g_T_ATTR_PROCESS);
2329 
2330   IF (PO_LOG.d_proc) THEN
2331     PO_LOG.proc_end(d_module);
2332   END IF;
2333 
2334 EXCEPTION
2335   WHEN OTHERS THEN
2336     PO_MESSAGE_S.add_exc_msg
2337     (
2338       p_pkg_name => d_pkg_name,
2339       p_procedure_name => d_api_name || '.' || d_position
2340     );
2341     RAISE;
2342 END process_attributes;
2343 
2344 -------------------------------------------------------------------------
2345 --Start of Comments
2346 --Name: process_attr_values
2347 --Pre-reqs: None
2348 --Modifies:
2349 --Locks:
2350 --  None
2351 --Function:
2352 --  process records in po_attr_values_interface table;
2353 --  currently, there is only validation logic, no
2354 --  derivation and defaulting logic
2355 --Parameters:
2356 --IN: None
2357 --IN OUT: None
2358 --OUT: None
2359 --Returns:
2360 --Notes:
2361 --Testing:
2362 --End of Comments
2363 ------------------------------------------------------------------------
2364 PROCEDURE process_attr_values IS
2365 
2366   d_api_name CONSTANT VARCHAR2(30) := 'process_attr_values';
2367   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
2368   d_position NUMBER;
2369 
2370   -- record to hold attribute values read within a batch
2371   l_attr_values            PO_PDOI_TYPES.attr_values_rec_type;
2372 
2373   -- cursor variable to point to currently processing row
2374   l_attr_values_csr        PO_PDOI_TYPES.intf_cursor_type;
2375 
2376   -- pl/sql table to track rows that needs to be created or updated
2377   l_merge_row_tbl          DBMS_SQL.NUMBER_TABLE;
2378 
2379   -- pl/sql table to track rows that need to be synced from txn
2380   -- table to draft table
2381   l_sync_attr_id_tbl       PO_TBL_NUMBER;
2382   l_sync_draft_id_tbl      PO_TBL_NUMBER;
2383 
2384   -- maximal interface_attr_values_id_processed
2385   l_max_intf_attr_values_id     NUMBER := -1;
2386 
2387   -- index for the loop
2388   l_index NUMBER;
2389 
2390   l_processing_row_tbl          DBMS_SQL.NUMBER_TABLE;
2391 
2392 BEGIN
2393   d_position := 0;
2394 
2395   IF (PO_LOG.d_proc) THEN
2396     PO_LOG.proc_begin(d_module);
2397   END IF;
2398 
2399   -- open cursor for query to retrieve attr value records
2400   PO_PDOI_ATTR_PROCESS_PVT.open_attr_values
2401   (
2402     p_max_intf_attr_values_id   => l_max_intf_attr_values_id,
2403     x_attr_values_csr           => l_attr_values_csr
2404   );
2405 
2406   d_position := 10;
2407 
2408   -- fetch records from attr values interface table and process the records
2409   LOOP
2410     BEGIN
2411       -- fetch one batch of records from query result
2412       PO_PDOI_ATTR_PROCESS_PVT.fetch_attr_values
2413       (
2414         x_attr_values_csr   => l_attr_values_csr,
2415         x_attr_values       => l_attr_values
2416       );
2417 
2418       d_position := 20;
2419 
2420       -- number of records read in current batch
2421       l_attr_values.rec_count := l_attr_values.intf_attr_values_id_tbl.COUNT;
2422 
2423       IF (PO_LOG.d_stmt) THEN
2424         PO_LOG.stmt(d_module, d_position, 'attr values in batch',
2425                     l_attr_values.rec_count);
2426       END IF;
2427 
2428       EXIT WHEN l_attr_values.rec_count = 0;
2429 
2430       -- process each record to determine the action;
2431       -- if multiple records are pointing to same
2432       -- po_line_id, the record will be processed
2433       -- in different groups
2434 
2435       -- first setup table to track rows that have not been processed
2436       PO_PDOI_UTL.generate_ordered_num_list
2437       (
2438         p_size      => l_attr_values.rec_count,
2439         x_num_list  => l_processing_row_tbl
2440       );
2441 
2442       -- second, process records in groups
2443       LOOP
2444         d_position := 30;
2445 
2446         -- exit when all rows are processed
2447         IF (l_processing_row_tbl.COUNT = 0) THEN
2448           IF (PO_LOG.d_stmt) THEN
2449             PO_LOG.stmt(d_module, d_position, 'exit after all rows are processed');
2450           END IF;
2451 
2452           EXIT;
2453         END IF;
2454 
2455         -- determine the action for each attr value record
2456         PO_PDOI_ATTR_PROCESS_PVT.check_attr_actions
2457         (
2458           x_processing_row_tbl => l_processing_row_tbl,
2459           x_attr_values        => l_attr_values,
2460           x_merge_row_tbl      => l_merge_row_tbl,
2461           x_sync_attr_id_tbl   => l_sync_attr_id_tbl,
2462           x_sync_draft_id_tbl  => l_sync_draft_id_tbl
2463         );
2464 
2465         d_position := 40;
2466 
2467         -- insert records into draft table
2468         PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.merge_attr_values
2469         (
2470           p_processing_row_tbl => l_merge_row_tbl,
2471           p_sync_attr_id_tbl   => l_sync_attr_id_tbl,
2472           p_sync_draft_id_tbl  => l_sync_draft_id_tbl,
2473           p_attr_values        => l_attr_values
2474         );
2475       END LOOP;
2476 
2477       d_position := 50;
2478 
2479       -- set status to ACCEPTED for all records
2480       FORALL i IN 1..l_attr_values.intf_attr_values_id_tbl.COUNT
2481       UPDATE po_attr_values_interface
2482       SET    process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_ACCEPTED
2483       WHERE  interface_attr_values_id = l_attr_values.intf_attr_values_id_tbl(i)
2484       AND    l_attr_values.error_flag_tbl(i) = FND_API.g_FALSE;
2485 
2486       PO_PDOI_UTL.commit_work;
2487 
2488       IF (l_attr_values.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
2489         EXIT;
2490       END IF;
2491 
2492       l_max_intf_attr_values_id := l_attr_values.intf_attr_values_id_tbl(l_attr_values.rec_count);
2493     EXCEPTION
2494       WHEN g_snap_shot_too_old THEN
2495         d_position := 60;
2496 
2497         -- log error
2498         PO_MESSAGE_S.add_exc_msg
2499         (
2500           p_pkg_name => d_pkg_name,
2501           p_procedure_name => d_api_name || '.' || d_position
2502         );
2503 
2504         -- commit changes
2505         PO_PDOI_UTL.commit_work;
2506 
2507         IF (l_attr_values_csr%ISOPEN) THEN
2508           CLOSE l_attr_values_csr;
2509           PO_PDOI_ATTR_PROCESS_PVT.open_attr_values
2510           (
2511             p_max_intf_attr_values_id   => l_max_intf_attr_values_id,
2512             x_attr_values_csr           => l_attr_values_csr
2513           );
2514         END IF;
2515     END;
2516   END LOOP;
2517 
2518   d_position := 70;
2519 
2520   -- close the cursor
2521   IF (l_attr_values_csr%ISOPEN) THEN
2522     CLOSE l_attr_values_csr;
2523   END IF;
2524 
2525   IF (PO_LOG.d_proc) THEN
2526     PO_LOG.proc_end(d_module);
2527   END IF;
2528 
2529 EXCEPTION
2530   WHEN OTHERS THEN
2531     PO_MESSAGE_S.add_exc_msg
2532     (
2533       p_pkg_name => d_pkg_name,
2534       p_procedure_name => d_api_name || '.' || d_position
2535     );
2536     RAISE;
2537 END process_attr_values;
2538 
2539 -------------------------------------------------------------------------
2540 --Start of Comments
2541 --Name: process_attr_values_tlp
2542 --Pre-reqs: None
2543 --Modifies:
2544 --Locks:
2545 --  None
2546 --Function:
2547 --  handle the logic on records from po_attr_values_tlp_interface table
2548 --Parameters:
2549 --IN: None
2550 --IN OUT: None
2551 --OUT: None
2552 --Returns:
2553 --Notes:
2554 --Testing:
2555 --End of Comments
2556 ------------------------------------------------------------------------
2557 PROCEDURE process_attr_values_tlp IS
2558 
2559   d_api_name CONSTANT VARCHAR2(30) := 'process_attr_values_tlp';
2560   d_module   CONSTANT VARCHAR2(255) := d_pkg_name || d_api_name || '.';
2561   d_position NUMBER;
2562 
2563   -- record to hold attribute tlp values read within a batch
2564   l_attr_values_tlp            PO_PDOI_TYPES.attr_values_tlp_rec_type;
2565 
2566   -- cursor variable to point to currently processing row
2567   l_attr_values_tlp_csr        PO_PDOI_TYPES.intf_cursor_type;
2568 
2569   -- pl/sql table to track rows that needs to be created or updated
2570   l_merge_row_tbl          DBMS_SQL.NUMBER_TABLE;
2571 
2572   -- pl/sql table to track rows that need to be synced from txn
2573   -- table to draft table
2574   l_sync_attr_tlp_id_tbl   PO_TBL_NUMBER;
2575   l_sync_draft_id_tbl      PO_TBL_NUMBER;
2576 
2577   -- maximal interface_attr_values_tlp_id_processed
2578   l_max_intf_attr_values_tlp_id   NUMBER := -1;
2579 
2580   l_processing_row_tbl            DBMS_SQL.NUMBER_TABLE;
2581   l_index                         NUMBER;
2582 
2583 BEGIN
2584   d_position := 0;
2585 
2586   IF (PO_LOG.d_proc) THEN
2587     PO_LOG.proc_begin(d_module);
2588   END IF;
2589 
2590   -- open cursor for query to retrieve attr value records
2591   PO_PDOI_ATTR_PROCESS_PVT.open_attr_values_tlp
2592   (
2593     p_max_intf_attr_values_tlp_id   => l_max_intf_attr_values_tlp_id,
2594     x_attr_values_tlp_csr           => l_attr_values_tlp_csr
2595   );
2596 
2597   d_position := 10;
2598 
2599   -- fetch records from attr values tlp interface table and process the records
2600   LOOP
2601     BEGIN
2602       -- fetch one batch of records from query result
2603       PO_PDOI_ATTR_PROCESS_PVT.fetch_attr_values_tlp
2604       (
2605         x_attr_values_tlp_csr   => l_attr_values_tlp_csr,
2606         x_attr_values_tlp       => l_attr_values_tlp
2607       );
2608 
2609       d_position := 20;
2610 
2611       -- number of records read in current batch
2612       l_attr_values_tlp.rec_count := l_attr_values_tlp.intf_attr_values_tlp_id_tbl.COUNT;
2613 
2614       IF (PO_LOG.d_stmt) THEN
2615         PO_LOG.stmt(d_module, d_position, 'attr values tlp in batch',
2616                     l_attr_values_tlp.rec_count);
2617       END IF;
2618 
2619       EXIT WHEN l_attr_values_tlp.rec_count = 0;
2620 
2621       -- process each record to determine the action;
2622       -- if multiple records are pointing to same
2623       -- po_line_id and language, the record will be processed
2624       -- in different groups
2625 
2626       -- first setup table to track rows that have not been processed
2627       PO_PDOI_UTL.generate_ordered_num_list
2628       (
2629         p_size      => l_attr_values_tlp.rec_count,
2630         x_num_list  => l_processing_row_tbl
2631       );
2632 
2633       -- second, process records in groups
2634       LOOP
2635         d_position := 20;
2636 
2637         -- exit when all rows are processed
2638         IF (l_processing_row_tbl.COUNT = 0) THEN
2639           IF (PO_LOG.d_stmt) THEN
2640             PO_LOG.stmt(d_module, d_position, 'exit after all rows are processed');
2641           END IF;
2642 
2643           EXIT;
2644         END IF;
2645 
2646         -- determine the action for each attr value tlp record
2647         PO_PDOI_ATTR_PROCESS_PVT.check_attr_tlp_actions
2648         (
2649           x_processing_row_tbl     => l_processing_row_tbl,
2650           x_attr_values_tlp        => l_attr_values_tlp,
2651           x_merge_row_tbl          => l_merge_row_tbl,
2652           x_sync_attr_tlp_id_tbl   => l_sync_attr_tlp_id_tbl,
2653           x_sync_draft_id_tbl      => l_sync_draft_id_tbl
2654         );
2655 
2656         d_position := 30;
2657 
2658         -- merge records into draft table
2659         PO_PDOI_MOVE_TO_DRAFT_TABS_PVT.merge_attr_values_tlp
2660         (
2661           p_processing_row_tbl     => l_merge_row_tbl,
2662           p_sync_attr_tlp_id_tbl   => l_sync_attr_tlp_id_tbl,
2663           p_sync_draft_id_tbl      => l_sync_draft_id_tbl,
2664           p_attr_values_tlp        => l_attr_values_tlp
2665         );
2666       END LOOP;
2667 
2668       d_position := 40;
2669 
2670       -- set status to ACCEPTED for all records
2671       FORALL i IN 1..l_attr_values_tlp.intf_attr_values_tlp_id_tbl.COUNT
2672       UPDATE po_attr_values_tlp_interface
2673       SET    process_code = PO_PDOI_CONSTANTS.g_PROCESS_CODE_ACCEPTED
2674       WHERE  interface_attr_values_tlp_id = l_attr_values_tlp.intf_attr_values_tlp_id_tbl(i)
2675       AND    l_attr_values_tlp.error_flag_tbl(i) = FND_API.g_FALSE;
2676 
2677       PO_PDOI_UTL.commit_work;
2678 
2679       IF (l_attr_values_tlp.rec_count < PO_PDOI_CONSTANTS.g_DEF_BATCH_SIZE) THEN
2680         EXIT;
2681       END IF;
2682 
2683       l_max_intf_attr_values_tlp_id := l_attr_values_tlp.intf_attr_values_tlp_id_tbl(l_attr_values_tlp.rec_count);
2684     EXCEPTION
2685       WHEN g_snap_shot_too_old THEN
2686         d_position := 50;
2687 
2688         -- log error
2689         PO_MESSAGE_S.add_exc_msg
2690         (
2691           p_pkg_name => d_pkg_name,
2692           p_procedure_name => d_api_name || '.' || d_position
2693         );
2694 
2695         -- commit changes
2696         PO_PDOI_UTL.commit_work;
2697 
2698         IF (l_attr_values_tlp_csr%ISOPEN) THEN
2699           CLOSE l_attr_values_tlp_csr;
2700           PO_PDOI_ATTR_PROCESS_PVT.open_attr_values_tlp
2701           (
2702             p_max_intf_attr_values_tlp_id   => l_max_intf_attr_values_tlp_id,
2703             x_attr_values_tlp_csr           => l_attr_values_tlp_csr
2704           );
2705         END IF;
2706     END;
2707   END LOOP;
2708 
2709   d_position := 60;
2710 
2711   -- close the cursor
2712   IF (l_attr_values_tlp_csr%ISOPEN) THEN
2713     CLOSE l_attr_values_tlp_csr;
2714   END IF;
2715 
2716   IF (PO_LOG.d_proc) THEN
2717     PO_LOG.proc_end(d_module);
2718   END IF;
2719 
2720 EXCEPTION
2721   WHEN OTHERS THEN
2722     PO_MESSAGE_S.add_exc_msg
2723     (
2724       p_pkg_name => d_pkg_name,
2725       p_procedure_name => d_api_name || '.' || d_position
2726     );
2727     RAISE;
2728 END process_attr_values_tlp;
2729 
2730 END PO_PDOI_MAINPROC_PVT;