DBA Data[Home] [Help]

PACKAGE BODY: APPS.AP_WEB_AUDIT_QUEUE_UTILS

Source


1 PACKAGE BODY AP_WEB_AUDIT_QUEUE_UTILS AS
2 /* $Header: apwaudqb.pls 120.10 2010/08/01 12:48:36 rveliche ship $ */
3 
4 /*=======================================================================+
5  |  Global Constants
6  +=======================================================================*/
7 
8 G_PKG_NAME      CONSTANT VARCHAR2(30)    := 'AP_WEB_AUDIT_QUEUE_UTILS';
9 
10 ------------------------------------------------------------------------
11 -- Local Procedure Signature
12 ------------------------------------------------------------------------
13 PROCEDURE open_auditors_cur_w(p_report_header_id IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE,
14                               p_auditor_info_cur OUT NOCOPY  GenRefCursor);
15 
16 PROCEDURE open_load_cur(p_auditor_id IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
17                               p_open_load_cur OUT NOCOPY  GenRefCursor);
18 
19 PROCEDURE validate_auditors;
20 
21 PROCEDURE open_orphaned_reports_cursor(p_expense_report_cur OUT NOCOPY  GenRefCursor);
22 
23 FUNCTION find_enqueue_auditor(p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
24   RETURN AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
25 
26 FUNCTION report_last_audited(p_report_id	IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
27 RETURN BOOLEAN;
28 
29 FUNCTION auditor_has_access(
30   p_auditor_id IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
31   p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
32   RETURN BOOLEAN;
33 
34 PROCEDURE transfer_report(p_auditor_id 		IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
35                           p_next_auditor_id 	IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
36                           p_expense_report_id 	IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE);
37 
38 ------------------------------------------------------------------------
39 -- Procedure Result Codes
40 ------------------------------------------------------------------------
41 
42 --------------------------------------------------------------------------
43 -- Registration Status Constants
44 --------------------------------------------------------------------------
45 
46 --------------------------------------------------------------------------
47 -- Access Domain Type Constants
48 --------------------------------------------------------------------------
49 
50 /*========================================================================
51  | PUBLIC FUNCTION report_weight
52  |
53  | DESCRIPTION
54  |   This function return high threshold for a given low value. Currently
55  | this is simply a function of the number of lines in the report.
56  |
57  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
58  |
59  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
60  |
61  | PARAMETERS
62  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
63  |
64  | MODIFICATION HISTORY
65  | Date                  Author            		Description of Changes
66  | 04-Sep-2002           Mohammad Shoaib Jamall       	Created
67  |
68  *=======================================================================*/
69 FUNCTION report_weight(p_report_header_id IN
70                        AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE) RETURN NUMBER
71 IS
72   l_report_weight NUMBER := 0;
73 BEGIN
74   SELECT count(1) INTO l_report_weight FROM ap_expense_report_lines_all
75   WHERE report_header_id = p_report_header_id
76     AND (itemization_parent_id is null OR itemization_parent_id <> -1);
77 
78   RETURN(l_report_weight);
79 END report_weight;
80 
81 /*========================================================================
82  | PUBLIC PROCEDURE assign_report_to_auditor
83  |
84  | DESCRIPTION
85  |   This procedure enqueus a report_header_id for audit:
86  |     - Takes in report_header_id and auditor_id
87  |     - If report already in the queue under this auditor do nothing
88  |     - If report not in the queue, enqueue it for this auditor if this
89  |       auditor is not owner of report.
90  |     - If report already in the queue under another auditor transfer
91  |       the report under this auditor if auditor is not owner of report.
92  |     - p_retcode is returned with:
93  |      'INVALID_ASSIGNMENT' -> if the auditor is the owner of report and
94  |                              cannot be assigned the report.
95  | 	'SUCCESS' -> if everything went ok.
96  |
97  | CALLED FROM PROCEDURES/FUNCTIONS (workflow/local to this package body)
98  |
99  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
100  |
101  | PARAMETERS
102  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
103  |   p_auditor_id   IN      AP_AUD_AUDITORS.AUDITOR_ID%TYPE
104  |
105  | MODIFICATION HISTORY
106  | Date                  Author            		Description of Changes
107  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
108  |
109  *=======================================================================*/
110 PROCEDURE assign_report_to_auditor(
111 	p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE,
112 	p_auditor_id IN	AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
113 	p_retcode OUT NOCOPY VARCHAR2)
114 IS
115   l_auditor_id AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
116   l_aud_queue_cur GenRefCursor;
117   l_scratch NUMBER := 0;
118 BEGIN
119   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start assign_report_to_auditor');
120   IF (p_report_header_id IS NOT NULL) AND (p_auditor_id IS NOT NULL) THEN
121     OPEN l_aud_queue_cur FOR
122       SELECT auditor_id FROM ap_aud_queues WHERE expense_report_id = p_report_header_id;
123     FETCH l_aud_queue_cur INTO l_auditor_id;
124 
125 -- is p_auditor_id the creator or employee for p_report_header_id; if yes then we should
126 -- return with INVALID_ASSIGNMENT; else proceed normally.
127     SELECT count(1) INTO l_scratch
128     FROM fnd_user u,
129          ap_expense_report_headers_all exp
130     WHERE u.user_id <> -1
131     AND   u.user_id = p_auditor_id
132 -- making sure auditor does not audit expense report owned by her OR filed by her
133     AND   exp.report_header_id = p_report_header_id
134     AND  (nvl(u.employee_id , -1) = nvl(exp.employee_id , -2) OR nvl(u.user_id , -1) = nvl(exp.created_by , -2));
135 
136     IF (l_scratch > 0) THEN
137       p_retcode := G_OIE_AUD_INVALID_ASSIGNMENT;
138       return;
139     END IF;
140 
141     IF l_aud_queue_cur%NOTFOUND THEN
142 -- report not in queue
143 --------------------------------------------------------------------------
144       INSERT INTO ap_aud_queues(expense_report_id,
145 				auditor_id,
146   				report_weight,
147   				creation_date,
148   				created_by,
149   				last_update_login,
150   				last_update_date,
151   				last_updated_by)
152       VALUES (			p_report_header_id,
153 				p_auditor_id,
154   				report_weight(p_report_header_id),
155   				sysdate,
156   				FND_GLOBAL.USER_ID,
157   				null,
158   				sysdate,
159 				FND_GLOBAL.USER_ID);
160 --------------------------------------------------------------------------
161     ELSIF (l_auditor_id <> p_auditor_id) THEN
162 -- report in queue but needs to be reassigned to p_auditor_id
163       transfer_report(l_auditor_id, p_auditor_id, p_report_header_id);
164 --------------------------------------------------------------------------
165 --------------------------------------------------------------------------
166     END IF;
167   END IF;
168 
169   p_retcode := G_OIE_AUD_SUCCESS;
170   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end assign_report_to_auditor');
171 END assign_report_to_auditor;
172 
173 /*========================================================================
174  | PUBLIC PROCEDURE assign_to_last_auditor
175  |
176  | DESCRIPTION
177  |   This procedure assigns a returned Report back to the same Auditor
178  |   who last Audited the report. Does not consider the Auditor Load
179  |
180  | CALLED FROM PROCEDURES/FUNCTIONS (workflow/local to this package body)
181  |
182  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
183  |
184  | PARAMETERS
185  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
186  |
187  | MODIFICATION HISTORY
188  | Date                  Author            		Description of Changes
189  | 22-Feb-2008           SaiKumar Talasila       	Created
190  |
191  *=======================================================================*/
192 PROCEDURE assign_to_last_auditor(p_report_header_id IN
193                            AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
194 IS
195   l_assignee         		NUMBER;
196   l_retcode             VARCHAR2(200);
197   invalid_assig_to_audit_q EXCEPTION;
198 BEGIN
199   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start assign_to_last_auditor');
200 
201   l_assignee := NULL;
202   IF report_last_audited(p_report_id => p_report_header_id) THEN
203     SELECT h.last_audited_by INTO l_assignee
204     FROM AP_EXPENSE_REPORT_HEADERS_ALL h
205     WHERE h.report_header_id = p_report_header_id;
206 
207     IF( nvl(l_assignee,-1) <> -1 AND
208             auditor_has_access(p_auditor_id => l_assignee,
209                              p_report_header_id => p_report_header_id) ) THEN
210       assign_report_to_auditor(p_report_header_id, l_assignee, l_retcode);
211       IF (G_OIE_AUD_INVALID_ASSIGNMENT = l_retcode) THEN
212         raise invalid_assig_to_audit_q;
213       END IF;
214     END IF;
215   END IF;
216 
217   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end assign_to_last_auditor');
218 
219 END assign_to_last_auditor;
220 
221 
222 /*========================================================================
223  | PUBLIC PROCEDURE enqueue_for_audit
224  |
225  | DESCRIPTION
226  |   This procedure enqueus a report_header_id for audit
227  |
228  | CALLED FROM PROCEDURES/FUNCTIONS (workflow/local to this package body)
229  |
230  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
231  |
232  | PARAMETERS
233  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
234  |
235  | MODIFICATION HISTORY
236  | Date                  Author            		Description of Changes
237  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
238  |
239  *=======================================================================*/
240 PROCEDURE enqueue_for_audit(p_report_header_id IN
241                             AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
242 IS
243   l_assignee         		NUMBER;
244   l_retcode                    	VARCHAR2(200);
245   invalid_assig_to_audit_q EXCEPTION;
246 BEGIN
247   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start enqueue_for_audit');
248   l_assignee := find_enqueue_auditor(p_report_header_id);
249   assign_report_to_auditor(p_report_header_id, l_assignee, l_retcode);
250   IF (G_OIE_AUD_INVALID_ASSIGNMENT = l_retcode) THEN
251     raise invalid_assig_to_audit_q;
252   END IF;
253   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end enqueue_for_audit');
254 
255 END enqueue_for_audit;
256 
257 /*========================================================================
258  | PUBLIC PROCEDURE rebalance_queue
259  |
260  | DESCRIPTION
261  |   This procedure enqueus a report_header_id for audit
262  |
263  | CALLED FROM PROCEDURES/FUNCTIONS (workflow/local to this package body)
264  |
265  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
266  |
267  | PARAMETERS
268  |   p_auditor_id   IN      AP_AUD_AUDITORS.AUDITOR_ID%TYPE
269  |
270  | MODIFICATION HISTORY
271  | Date                  Author            		Description of Changes
272  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
273  |
274  *=======================================================================*/
275 PROCEDURE rebalance_queue(p_auditor_id IN
276                            AP_AUD_AUDITORS.AUDITOR_ID%TYPE)
277 IS
278   l_next_auditor_id AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
279   l_expense_report_id NUMBER;
280   CURSOR c1 IS SELECT expense_report_id
281     FROM ap_aud_queues
282     WHERE auditor_id = p_auditor_id order by last_update_date desc;
283 BEGIN
284   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start rebalance_queue');
285   FOR rec IN c1 LOOP
286     l_expense_report_id := rec.expense_report_id;
287     EXIT WHEN l_expense_report_id IS NULL;
288     l_next_auditor_id := find_enqueue_auditor(l_expense_report_id);
289     -- If the report has not been audited previously, exit when the next
290     -- auditor found is the same as the current auditor we are rebalancing for.
291     IF NOT report_last_audited(p_report_id => l_expense_report_id) THEN
292       IF l_next_auditor_id <> p_auditor_id THEN
293         transfer_report(p_auditor_id, l_next_auditor_id, l_expense_report_id);
294       END IF;
295     ELSE
296       transfer_report(p_auditor_id, l_next_auditor_id, l_expense_report_id);
297     END IF;
298 
299   END LOOP;
300   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end rebalance_queue');
301 END rebalance_queue;
302 
303 
304 /*========================================================================
305  | PUBLIC PROCEDURE open_load_cur
306  |
307  | DESCRIPTION
308  |   This procedure opens cursor containing the open cursor for the
309  |   current entry in ap_aud_workloads for auditor_id. It should
310  |   return at most 1 row.
311  |
312  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
313  |
314  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
315  |
316  | PARAMETERS
317  |   p_auditor_id	IN      AP_AUD_AUDITORS.AUDITOR_ID%TYPE
318  |   p_open_load_cur   	IN      GenRefCursor
319  |
320  | MODIFICATION HISTORY
321  | Date                  Author            		Description of Changes
322  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
323  |
324  *=======================================================================*/
325 PROCEDURE open_load_cur(p_auditor_id IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
326                         p_open_load_cur OUT NOCOPY  GenRefCursor)
327 IS
328 
329 BEGIN
330   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start open_load_cur:' || p_auditor_id);
331   OPEN p_open_load_cur FOR
332     SELECT s.current_total_workload,
333            w.workload_percent
334     FROM
335            ap_aud_auditors a,
336            ap_aud_queue_summaries_v s,
337            ap_aud_workloads w
338     WHERE  a.auditor_id = p_auditor_id
339     AND    a.auditor_id = s.auditor_id(+)
340     AND    a.auditor_id = w.auditor_id
341     AND    w.start_date <= sysdate
342     AND    sysdate < nvl(w.end_date,sysdate+1);
343 
344 
345 END open_load_cur;
346 
347 /*========================================================================
348  | PUBLIC PROCEDURE open_auditors_cur_w
349  |
350  | DESCRIPTION
351  |   This procedure opens cursor containing auditor info for auditors
352  |   who can audit for the report header id
353  |
354  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
355  |
356  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
357  |
358  | PARAMETERS
359  |   p_report_header_id	IN      AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE
360  |   p_cust_acct_cur   	IN      GenRefCursor
361  |
362  | MODIFICATION HISTORY
363  | Date                  Author            		Description of Changes
364  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
365  |
366  *=======================================================================*/
367 PROCEDURE open_auditors_cur_w(p_report_header_id IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE,
368                               p_auditor_info_cur OUT NOCOPY  GenRefCursor)
369 IS
370   l_org_id 			AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE;
371 BEGIN
372   SELECT ORG_ID INTO l_org_id FROM ap_expense_report_headers_all
373   WHERE report_header_id = p_report_header_id;
374   open_auditors_info_cursor(p_report_header_id => p_report_header_id, p_org_id => l_org_id, p_auditor_info_cur => p_auditor_info_cur);
375 END open_auditors_cur_w;
376 
377 /*========================================================================
378  | PUBLIC PROCEDURE open_auditors_info_cursor
379  |
380  | DESCRIPTION
381  |   This procedure opens cursor containing auditor info for auditors
382  |   who can audit for the org_id. Customers can customize this for
383  |   their own business logic.
384  |
385  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
386  |
387  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
388  |
389  | PARAMETERS
390  |   p_report_header_id	IN      AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE
391  |   p_org_id   	IN      AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE
392  |   p_cust_acct_cur   	IN      GenRefCursor
393  |
394  | MODIFICATION HISTORY
395  | Date                  Author            		Description of Changes
396  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
397  |
398  *=======================================================================*/
399 PROCEDURE open_auditors_info_cursor(p_report_header_id IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE,
400                                     p_org_id        IN AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE,
401                                     p_auditor_info_cur OUT NOCOPY  GenRefCursor)
402 IS
403 
404 BEGIN
405   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start open_auditors_info_cursor:' || p_report_header_id || ' p_org_id:' || p_org_id);
406   OPEN p_auditor_info_cur FOR
407     SELECT a.auditor_id
408     FROM ap_aud_auditors a,
409          per_organization_list per,
410          hr_organization_information oi,
411          fnd_user u,
412          ap_expense_report_headers_all exp
413     WHERE a.security_profile_id = per.security_profile_id
414     AND   a.auditor_id <> -1
415     AND   per.organization_id = oi.organization_id
416     AND   oi.org_information_context = 'CLASS'
417     AND   oi.org_information1 = 'OPERATING_UNIT'
418     AND   oi.organization_id = p_org_id
419 -- making sure auditor does not audit expense report owned by her
420     AND   exp.report_header_id = p_report_header_id
421     AND   a.auditor_id = u.user_id
422     AND  nvl(u.employee_id , -1) <> nvl(exp.employee_id , -2)
423 -- making sure auditor does not audit expense report filed by her
424     AND  nvl(u.user_id , -1) <> nvl(exp.created_by , -2)
425 UNION
426 SELECT a.auditor_id
427     FROM ap_aud_auditors a,
428          per_security_profiles sec,
429          fnd_user u,
430          ap_expense_report_headers_all exp
431     WHERE a.security_profile_id = sec.security_profile_id
432     AND sec.view_all_organizations_flag = 'Y'
433     AND   a.auditor_id <> -1
434 -- making sure auditor does not audit expense report owned by her
435     AND   exp.report_header_id = p_report_header_id
436     AND   a.auditor_id = u.user_id
437     AND  nvl(u.employee_id , -1) <> nvl(exp.employee_id , -2)
438 -- making sure auditor does not audit expense report filed by her
439     AND  nvl(u.user_id , -1) <> nvl(exp.created_by , -2);
440 
441 END open_auditors_info_cursor;
442 
443 /*========================================================================
444  | PUBLIC PROCEDURE open_orphaned_reports_cursor
445  |
446  | DESCRIPTION
447  |   This procedure opens cursor containing (expense report ids, auditor ids) in
448  |   AP_AUD_QUEUES that have been orphaned. Meaning they belong to an auditor
449  |   who is not going to be able to view them because of his security_profile
450  |   setting.
451  |
452  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
453  |
454  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
455  |
456  | PARAMETERS
457  |   p_org_id   	IN      AP_EXPENSE_REPORT_HEADERS_ALL.ORG_ID%TYPE
458  |   p_cust_acct_cur   	IN      GenRefCursor
459  |
460  | MODIFICATION HISTORY
461  | Date                  Author            		Description of Changes
462  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
463  |
464  *=======================================================================*/
465 PROCEDURE open_orphaned_reports_cursor(p_expense_report_cur OUT NOCOPY  GenRefCursor)
466 IS
467 BEGIN
468 
469   OPEN p_expense_report_cur FOR
470     SELECT expense_report_id, auditor_id
471     FROM ap_aud_queues WHERE
472     expense_report_id NOT IN
473     ( SELECT q.expense_report_id
474       FROM ap_aud_queues q,
475            ap_expense_report_headers_all e,
476            ap_aud_auditors a,
477            per_organization_list per,
478            hr_organization_information oi
479       WHERE q.auditor_id = a.auditor_id
480       AND   q.expense_report_id = e.report_header_id
481       AND   a.security_profile_id = per.security_profile_id
482       AND   per.organization_id = oi.organization_id
483       AND   oi.org_information_context = 'CLASS'
484       AND   oi.org_information1 = 'OPERATING_UNIT'
485       AND   e.org_id = oi.organization_id);
486 
487 END open_orphaned_reports_cursor;
488 
489 /*========================================================================
490  | PUBLIC PROCEDURE find_enqueue_auditor
491  |
492  | DESCRIPTION
493  |   This function finds an auditor to enqueue an expense report
494  |
495  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
496  |
497  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
498  |
499  | PARAMETERS
500  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
501  |
502  | MODIFICATION HISTORY
503  | Date                  Author            		Description of Changes
504  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
505  |
506  *=======================================================================*/
507 FUNCTION find_enqueue_auditor(p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
508   RETURN AP_AUD_AUDITORS.AUDITOR_ID%TYPE
509 IS
510 -- preseeded auditor with no association with FND_USER
511   l_assignee         		NUMBER := -1;
512 -- an extremely large number
513   l_assignee_adjusted_workload 	NUMBER := 10E124;
514   l_auditor_info_cur 		GenRefCursor;
515   l_open_load_cur 		GenRefCursor;
516 
517   l_current_auditor_id          AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
518   l_current_workload            NUMBER;
519   l_current_adjusted_workload   NUMBER;
520   l_current_workload_percent	AP_AUD_WORKLOADS.WORKLOAD_PERCENT%TYPE;
521 -- temporary scratchpad variable
522   l_num           		NUMBER;
523   l_parent_auditor_id      	NUMBER;
524 BEGIN
525   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start find_enqueue_auditor');
526   l_parent_auditor_id := NULL;
527 
528 -- if report is shortpaid(or has been last audited) and there is a last auditor -> if last
529 -- auditor of parent  isn't 0 workload and auditor still has access to the org for this auditor,
530 -- then assign to that auditor; else assign to fallback auditor
531   IF report_last_audited(p_report_id => p_report_header_id) THEN
532     SELECT h.last_audited_by INTO l_parent_auditor_id
533     FROM AP_EXPENSE_REPORT_HEADERS_ALL h
534     WHERE h.report_header_id = p_report_header_id;
535     IF l_parent_auditor_id IS NOT NULL THEN
536       open_load_cur(p_auditor_id => l_parent_auditor_id,
537                     p_open_load_cur => l_open_load_cur);
538       FETCH l_open_load_cur INTO l_current_workload, l_current_workload_percent;
539       IF (auditor_has_access(p_auditor_id => l_parent_auditor_id,
540                              p_report_header_id => p_report_header_id) AND
541           l_current_workload_percent > 0) THEN
542         l_assignee := l_parent_auditor_id;
543       END IF;
544       IF (l_assignee <> -1) THEN
545         RETURN l_assignee;
546       END IF;
547     END IF;
548   END IF;
549 
550 
551   open_auditors_cur_w(	p_report_header_id => p_report_header_id,
552 			p_auditor_info_cur => l_auditor_info_cur);
553   LOOP
554     FETCH l_auditor_info_cur INTO l_current_auditor_id;
555     EXIT WHEN l_auditor_info_cur%NOTFOUND;
556     IF (l_current_auditor_id <> -1) THEN
557 
558       open_load_cur(p_auditor_id => l_current_auditor_id,
559                     p_open_load_cur => l_open_load_cur);
560 
561       FETCH l_open_load_cur INTO l_current_workload, l_current_workload_percent;
562       IF l_open_load_cur%FOUND THEN
563         EXIT WHEN l_assignee_adjusted_workload = 0;
564         IF (l_current_workload_percent IS NOT NULL) AND (l_current_workload_percent <> 0) THEN
565 
566           IF (l_current_workload IS NULL) THEN
567             l_current_workload := 0;
568           ELSE
569 -- if current auditor is already assigned this report then subtract report weight from l_current_workload
570          	  SELECT count(1) INTO l_num FROM ap_aud_queues WHERE expense_report_id = p_report_header_id AND auditor_id = l_current_auditor_id;
571             IF (l_num > 0) THEN
572               SELECT report_weight INTO l_num FROM ap_aud_queues WHERE expense_report_id = p_report_header_id;
573               l_current_workload := l_current_workload - l_num;
574             END IF;
575           END IF;
576           l_current_adjusted_workload := l_current_workload / l_current_workload_percent;
577           IF (l_current_adjusted_workload < l_assignee_adjusted_workload) THEN
578             l_assignee := l_current_auditor_id;
579             l_assignee_adjusted_workload := l_current_adjusted_workload;
580           END IF;
581 
582         END IF;
583       END IF;
584 
585     END IF;
586 
587   END LOOP;
588 
589   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end find_enqueue_auditor');
590 
591   RETURN l_assignee;
592 
593 END find_enqueue_auditor;
594 
595 /*========================================================================
596  | PUBLIC PROCEDURE report_shortpaid
597  |
598  | DESCRIPTION
599  |   is report shorpaid
600  |
601  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
602  |
603  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
604  |
605  | PARAMETERS
606  |   p_report_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
607  |
608  | MODIFICATION HISTORY
609  | Date                  Author            		Description of Changes
610  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
611  |
612  *=======================================================================*/
613 FUNCTION report_shortpaid(p_report_id		IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
614 RETURN BOOLEAN IS
615 l_shortpay_id		AP_EXPENSE_REPORT_HEADERS_ALL.SHORTPAY_PARENT_ID%TYPE := NULL;
616 BEGIN
617   SELECT shortpay_parent_id
618   INTO   l_shortpay_id
619   FROM   ap_expense_report_headers_all
620   WHERE  report_header_id = p_report_id;
621   IF (l_shortpay_id IS NULL) THEN
622     return FALSE;
623   ELSE
624     return TRUE;
625   END IF;
626 END report_shortpaid;
627 
628 /*========================================================================
629  | PUBLIC PROCEDURE report_last_audited
630  |
631  | DESCRIPTION
632  |   has report been last audited by someone
633  |
634  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
635  |
636  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
637  |
638  | PARAMETERS
639  |   p_report_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
640  |
641  | MODIFICATION HISTORY
642  | Date                  Author            		Description of Changes
643  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
644  |
645  *=======================================================================*/
646 FUNCTION report_last_audited(p_report_id		IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
647 RETURN BOOLEAN IS
648 l_last_audited_by	AP_EXPENSE_REPORT_HEADERS_ALL.LAST_AUDITED_BY%TYPE := NULL;
649 BEGIN
650   SELECT last_audited_by
651   INTO   l_last_audited_by
652   FROM   ap_expense_report_headers_all
653   WHERE  report_header_id = p_report_id;
654   IF (l_last_audited_by IS NULL) THEN
655     return FALSE;
656   ELSE
657     return TRUE;
658   END IF;
659 END report_last_audited;
660 
661 /*========================================================================
662  | PUBLIC PROCEDURE auditor_has_access
663  |
664  | DESCRIPTION
665  |   This function finds if an auditor can access a report
666  |
667  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
668  |
669  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
670  |
671  | PARAMETERS
672  |   p_auditor_id   IN      	  AP_AUD_AUDITORS.AUDITOR_ID%TYPE
673  |   p_report_header_id   IN      AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
674  |
675  | MODIFICATION HISTORY
676  | Date                  Author            		Description of Changes
677  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
678  |
679  *=======================================================================*/
680 FUNCTION auditor_has_access(
681   p_auditor_id IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
682   p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
683   RETURN BOOLEAN
684 IS
685   l_ret_val 		      	BOOLEAN := FALSE;
686   l_auditor_info_cur 		GenRefCursor;
687   l_current_auditor_id          AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
688 BEGIN
689   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start auditor_has_access');
690   open_auditors_cur_w(	p_report_header_id => p_report_header_id,
691 			p_auditor_info_cur => l_auditor_info_cur);
692 
693   LOOP
694     FETCH l_auditor_info_cur INTO l_current_auditor_id;
695     EXIT WHEN l_auditor_info_cur%NOTFOUND;
696     IF l_current_auditor_id = p_auditor_id THEN
697       l_ret_val := TRUE;
698       EXIT;
699     END IF;
700   END LOOP;
701 
702   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'end auditor_has_access');
703   RETURN l_ret_val;
704 
705 END auditor_has_access;
706 
707 /*========================================================================
708  | PUBLIC PROCEDURE transfer_report
709  |
710  | DESCRIPTION
711  |   This procedure transfers between auditors.
712  |
713  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
714  |
715  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
716  |
717  | PARAMETERS
718  | p_auditor_id 	IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
719  | p_next_auditor_id 	IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
720  | p_expense_report_id 	IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE
721  |
722  | MODIFICATION HISTORY
723  | Date                  Author            		Description of Changes
724  | 05-Sep-2002           Mohammad Shoaib Jamall       	Created
725  |
726  *=======================================================================*/
727 PROCEDURE transfer_report(p_auditor_id 		IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
728                           p_next_auditor_id 	IN AP_AUD_AUDITORS.AUDITOR_ID%TYPE,
729                           p_expense_report_id 	IN AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
730 IS
731   PRAGMA AUTONOMOUS_TRANSACTION;
732 
733 BEGIN
734   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start transfer_report');
735 
736   IF (p_auditor_id <> p_next_auditor_id) THEN
737 
738     UPDATE ap_aud_queues SET 	auditor_id = p_next_auditor_id,
739    				last_update_login = null,
740     				last_update_date = sysdate,
741     				last_updated_by = FND_GLOBAL.USER_ID
742     WHERE auditor_id = p_auditor_id AND expense_report_id = p_expense_report_id;
743     COMMIT;
744 
745   END IF;
746 
747   AP_WEB_UTILITIES_PKG.LogProcedure(G_PKG_NAME, 'start transfer_report');
748 
749 END transfer_report;
750 
751 /*========================================================================
752  | PUBLIC FUNCTION report_weight
753  |
754  | DESCRIPTION
755  |   Wrapper around FND_FUNCTION.IS_FUNCTION_ON_MENU() which returns 'Y' or
756  | 'N' instead of true/false
757  |
758  | CALLED FROM PROCEDURES/FUNCTIONS (local to this package body)
759  |
760  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
761  |
762  | PARAMETERS
763  |   p_menu_id     - menu to check
764  |   p_function_id - function to look for
765  |   p_check_grant_flag - if TRUE, then we won't return TRUE unless
766  |                        GRANT_FLAG = 'Y'.  Generally pass FALSE
767  |                        for Data Security and TRUE for Func Sec.
768  |
769  | MODIFICATION HISTORY
770  | Date                  Author            		Description of Changes
771  | 04-Sep-2002           Mohammad Shoaib Jamall       	Created
772  |
773  *=======================================================================*/
774 FUNCTION is_function_on_menu(p_menu_id     IN NUMBER,
775                              p_function_id IN NUMBER,
776                              p_check_grant_flag IN VARCHAR2) RETURN VARCHAR2
777 IS
778   l_ret_val BOOLEAN;
779   l_check_grant_flag BOOLEAN;
780 BEGIN
781   IF p_check_grant_flag IS NULL THEN
782     l_ret_val := fnd_function.is_function_on_menu(p_menu_id, p_function_id);
783   ELSE
784     IF p_check_grant_flag = 'Y' THEN
785       l_check_grant_flag := true;
786     ELSE
787       l_check_grant_flag := false;
788     END IF;
789     l_ret_val := fnd_function.is_function_on_menu(p_menu_id, p_function_id, l_check_grant_flag);
790   END IF;
791   IF l_ret_val THEN
792     RETURN 'Y';
793   ELSE
794     RETURN 'N';
795   END IF;
796 END is_function_on_menu;
797 
798 /*========================================================================
799  | PUBLIC PROCEDURE remove_from_queue
800  |
801  | DESCRIPTION
802  |   removes expense report from audit queues if it is in the queue.
803  |   if it isn't in the queue then simply return.
804  |
805  |
806  | CALLED FROM PROCEDURES/FUNCTIONS - Concurrent Program
807  |
808  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
809  |
810  | PARAMETERS
811  |   p_report_header_id	- report to remove
812  |
813  | MODIFICATION HISTORY
814  | Date                  Author            		Description of Changes
815  | 16-Oct-2002           Mohammad Shoaib Jamall       	Created
816  |
817  *=======================================================================*/
818 PROCEDURE remove_from_queue(
819 	p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE)
820 IS
821 BEGIN
822   DELETE FROM ap_aud_queues WHERE expense_report_id = p_report_header_id;
823 END remove_from_queue;
824 
825 /*========================================================================
826  | PUBLIC PROCEDURE auditor_for_report
827  |
828  | DESCRIPTION
829  |   returns auditor_id to which report is assigned as p_auditor_id.
830  |   if report is assigned to the fallback auditor returns -1.
831  |   if it isn't in the queue then returns null.
832  |
833  |
834  | CALLED FROM PROCEDURES/FUNCTIONS - Concurrent Program
835  |
836  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
837  |
838  | PARAMETERS
839  |   p_report_header_id	- report to remove
840  |   p_auditor_id       - auditor id returned
841  |
842  | MODIFICATION HISTORY
843  | Date                  Author            		Description of Changes
844  | 16-Oct-2002           Mohammad Shoaib Jamall       	Created
845  |
846  *=======================================================================*/
847 PROCEDURE auditor_for_report(
848 	p_report_header_id IN  AP_EXPENSE_REPORT_HEADERS_ALL.REPORT_HEADER_ID%TYPE,
849 	p_auditor_id OUT NOCOPY AP_AUD_AUDITORS.AUDITOR_ID%TYPE)
850 IS
851 BEGIN
852   p_auditor_id := null;
853   SELECT auditor_id INTO p_auditor_id FROM ap_aud_queues WHERE expense_report_id = p_report_header_id;
854 EXCEPTION
855   WHEN OTHERS THEN
856     p_auditor_id := null;
857 END auditor_for_report;
858 
859 /*========================================================================
860  | PUBLIC PROCEDURE reassign_orphaned_reports
861  |
862  | DESCRIPTION
863  |   the security_profile_id assigned to an auditor_id can be changed
864  |   OR orgs may be removed from the security_profile_id. In these
865  |   cases reports may be assigned to an auditor and whereas she doesn't have
866  |   access to the org_id to view the report. This procedure runs in a
867  |   concurrent program and reassigns orphaned reports.
868  |
869  |
870  | CALLED FROM PROCEDURES/FUNCTIONS - Concurrent Program
871  |
872  | CALLS PROCEDURES/FUNCTIONS (local to this package body)
873  |
874  | PARAMETERS
875  |   errbug        - standard Concurrent Program error output param
876  |   retcode       - standard Concurrent Program return code output param
877  |
878  | MODIFICATION HISTORY
879  | Date                  Author            		Description of Changes
880  | 10-Oct-2002           Mohammad Shoaib Jamall       	Created
881  |
882  *=======================================================================*/
883 PROCEDURE reassign_orphaned_reports(errbuf    OUT NOCOPY VARCHAR2,
884                                     retcode   OUT NOCOPY VARCHAR2)
885 IS
886   l_expense_report_cur 		GenRefCursor;
887   l_expense_report_id 		NUMBER;
888   l_auditor_id 			AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
889   l_next_auditor_id 		AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
890 
891   l_sqlerrm		VARCHAR2(2000);
892   l_subject		VARCHAR2(200);
893 BEGIN
894   fnd_file.put_line(fnd_file.log, 'starting AP_WEB_AUDIT_QUEUE_UTILS.reassign_orphaned_reports()');
895 
896   validate_auditors();
897 
898   open_orphaned_reports_cursor(p_expense_report_cur => l_expense_report_cur);
899   LOOP
900     FETCH l_expense_report_cur INTO l_expense_report_id, l_auditor_id;
901     EXIT WHEN l_expense_report_cur%NOTFOUND;
902 
903     l_next_auditor_id := find_enqueue_auditor(l_expense_report_id);
904     transfer_report(l_auditor_id, l_next_auditor_id, l_expense_report_id);
905 
906   END LOOP;
907   retcode := 0;    -- SUCCESS
908   fnd_file.put_line(fnd_file.log, 'ending AP_WEB_AUDIT_QUEUE_UTILS.reassign_orphaned_reports()');
909 
910   EXCEPTION
911     WHEN OTHERS THEN
912       l_sqlerrm := sqlerrm(sqlcode) || fnd_global.newline ||
913                    'Location: AP_WEB_AUDIT_QUEUE_UTILS.reassign_orphaned_reports()'||fnd_global.newline||
914                    'Time: '||to_char(sysdate, 'DD-MON-RRRR HH:MI:SS');
915       retcode := 2; -- ERROR
916       fnd_message.set_name('SQLAP','OIE_AUD_REASSIGN_ORPH_ERROR');
917       fnd_message.set_token('REQUEST_ID', fnd_global.conc_request_id);
918       l_subject := fnd_message.get;
919       fnd_file.put_line(fnd_file.log, 'AP_WEB_AUDIT_QUEUE_UTILS.reassign_orphaned_reports()EXCEPTION:'||l_sqlerrm);
920 
921 END reassign_orphaned_reports;
922 
923 PROCEDURE validate_auditors IS
924   l_auditor_id AP_AUD_AUDITORS.AUDITOR_ID%TYPE;
925   l_security_profile_id AP_AUD_AUDITORS.SECURITY_PROFILE_ID%TYPE;
926 -- scratch variable
927   l_num NUMBER;
928   CURSOR c1 IS SELECT auditor_id, security_profile_id
929     FROM ap_aud_auditors
930     WHERE auditor_id <> -1 AND security_profile_id IS NOT NULL;
931 BEGIN
932 
933   FOR rec IN c1 LOOP
934     l_auditor_id := rec.auditor_id;
935     l_security_profile_id := rec.security_profile_id;
936 
937     SELECT count(1) INTO l_num FROM
938     (SELECT
939     		u.user_id,
940     		FND_PROFILE.VALUE_SPECIFIC('XLA_MO_SECURITY_PROFILE_LEVEL', u.user_id, r.responsibility_id, 200/*SQLAP*/) security_profile_id
941     	FROM
942     		FND_USER u,
943     		FND_USER_RESP_GROUPS g,
944     		FND_RESPONSIBILITY r,
945     		FND_FORM_FUNCTIONS f
946     	WHERE
947 		u.user_id = l_auditor_id
948     		AND u.user_id = g.user_id
949     		AND g.responsibility_id = r.responsibility_id
950     		AND AP_WEB_AUDIT_QUEUE_UTILS.IS_FUNCTION_ON_MENU(r.menu_id, f.function_id, 'Y') = 'Y'
951     		AND f.function_name = 'OIE_AUD_AUDIT') sp
952     WHERE sp.security_profile_id = l_security_profile_id;
953 
954     IF (l_num = 0) THEN
955       UPDATE ap_aud_auditors SET security_profile_id = null WHERE auditor_id = l_auditor_id;
956     END IF;
957 
958   END LOOP;
959 
960 END validate_auditors;
961 
962 
963 END AP_WEB_AUDIT_QUEUE_UTILS;