DBA Data[Home] [Help]

PACKAGE BODY: APPS.HR_US_ACCRUAL_PLANS

Source


1 package body hr_us_accrual_plans as
2 /* $Header: pyusaccr.pkb 120.3 2006/07/31 07:39:13 risgupta noship $ */
3 /*
4 +======================================================================+
5 |                Copyright (c) 1994 Oracle Corporation                 |
6 |                   Redwood Shores, California, USA                    |
7 |                        All rights reserved.                          |
8 +======================================================================+
9 
10     Name        : hr_us_accrual_plans
11     Filename	: pyusudfs.sql
12     Change List
13     -----------
14     Date        Name          	Vers    Bug No	Description
15     ----        ----          	----	------	-----------
16     26-JAN-95	hparicha	40.0	G1565	Vacation/Sick correlation
17 						to Regular Pay - changes to
18 						Calc Period Earns.
19 						Also need separate fn to calc
20 						Vac/Sick Pay as well as a fn
21 						to check for entry of Vac/Sick
22 						Hours against an accrual plan.
23     09-JUL-95	hparicha	40.1	282299	Check accrual ineligibility.
24 						Currently only used from
25 						PayMIX.
26     04-OCT-95   ramurthy        40.3    312537  Added NO_DATA_FOUND
27 						exception in procedure
28 						get_accrual_ineligibility.
29     05-Jan-96   rfine           40.4    323214  Prevented TOO_MANY_ROWS error
30 						when > 1 Plan has the same
31 						absence element.
32     11-JAN-96   ramurthy	40.5	326766	Changed procedure
33 						get_accrual_ineligibility
34 						to handle accrual start rules
35 						'Hire Date' and 'Beginning
36 						of Year' when they do not
37 						have any period of
38 						ineligibility.  That is,
39 						the eligible dates are now
40 						set accordingly.
41     04-NOV-96	hparicha	40.6	408507	Changed accrual_time_taken
42 						function to sum entry values
43 						for vacation or sick time taken.
44     16-MAR-99   alogue         115.1            Support of new accrual functionality
45                                                 by use of ineligibility_formula_id.
46     07-APR-99   alogue         115.2            Canonical date support in ff
47                                                 pl sql engine call within
48                                                 get_accrual_ineligibility.
49     08-APR-99  djoshi          115.3            Verfied and converted for Canonical
50                                                 Complience of Date
51     15-APR-99  VMehta          115.4  764244    Accessing the
52 	per_periods_of_service through a
53 						date effective join
54 
55 
56     21-Apr-99   scgrant        115.5            Multi-radix changes.
57 --
58     26-FEB-02   Rmonge         115.6            Fix for bug 2006907
59 
60     03-SEP-03   rmonge         115.10           Removed NOCOPY from
61                                                 in arguments.
62      20-SEP-05   ghshanka      115.11            bug 4123194 deleted the functions
63 						calc_accrual_pay and accrual_time_taken .
64      29-Nov-05  irgonzal       115.12           Bug fix 4762608. Altered
65                                                 get_accrual_ineligibility procedure.
66                                                 Handled scenario when accrual plan
67                                                 does not have a "start date" rule.
68      31-AUG-06  risgupta       115.13  5405255 obsoleted functions being re-added on request
69                                                of US payroll
70     Description: User-Defined Functions required for US implementations.
71 */
72 --
73 -- **********************************************************************
74 
75 --
76 --  Procedure
77 --     get_accrual_ineligibility
78 --
79 --  Purpose
80 --     Check for accrual plan ineligibility period and indicate if the current
81 --     assignment is within the ineligible period - ie. the batch line entry
82 --     for time taken against the accrual should be invalidated.
83 --
84 --  Arguments
85 --     p_iv_id
86 --     p_bg_id
87 --     p_asg_id
88 --     p_sess_date
89 --
90 --  History
91 --     8th July 1995     Hankins Parichabutr	Created.
92 --     4th Oct  1995     Ranjana Murthy         Added NO_DATA_FOUND exception
93 --     05-Jan-96  rfine            323214  Prevented TOO_MANY_ROWS error when
94 --					   > 1 Plan has the same absence element
95 --     11-JAN-96  ramurthy	   326766  Set eligible dates properly for
96 --					   start rules 'Hire Date' and
97 --					   'Beginning of Year'.
98 --
99 PROCEDURE get_accrual_ineligibility(	p_iv_id    	IN NUMBER,
100 				      	p_bg_id  	IN NUMBER,
101 					p_asg_id 	IN NUMBER,
102 					p_sess_date	IN DATE,
103 					p_eligible   	OUT NOCOPY VARCHAR2
104 		              		) IS
105 
106 v_inel_length		NUMBER(2);
107 v_inel_period_type	VARCHAR2(30);
108 v_start_rule		VARCHAR2(30);
109 v_service_start		DATE;
110 v_inel_days		NUMBER(9);
111 v_semi_days		NUMBER(9);
112 v_eligible_date		DATE;
113 v_plan_id               NUMBER(9);
114 v_formula_id            NUMBER(9);
115 l_inputs                ff_exec.inputs_t;
116 l_outputs               ff_exec.outputs_t;
117 
118 CURSOR	plan_for_input_value IS
119 SELECT	nvl(ineligible_period_length, 0),
120 	ineligible_period_type,
121 	accrual_start,
122         accrual_plan_id,
123         ineligibility_formula_id
124 FROM	PAY_ACCRUAL_PLANS
125 WHERE	pto_input_value_id	= p_iv_id
126 AND	business_group_id	= p_bg_id;
127 
128 BEGIN
129 
130   --
131   -- Check that this input value is used for accrual pto recording.
132   -- #323214 Redefined as an explicit cursor with an unlooped fetch.
133   -- This prevents a TOO_MANY_ROWS error when > 1 Plan has the same
134   -- absence element.
135   --
136   -- However, if this is the case, note that you cannot guarantee which
137   -- plan for the absence element the details are being retrieved from. There
138   -- may come a subsequent Enhancement Request to prevent users from setting
139   -- up more than one plan with the same absence element. RMF 05-Jan-96.
140   --
141   hr_utility.set_location('get_accrual_ineligibility', 1);
142 
143   open  plan_for_input_value;
144   fetch plan_for_input_value into v_inel_length,
145 				  v_inel_period_type,
146 				  v_start_rule,
147                                   v_plan_id,
148                                   v_formula_id;
149   --
150   -- If there is no associated plan, there is no further work to be
151   -- done in this procedure.
152   --
153   if plan_for_input_value%notfound then
154     close  plan_for_input_value;
155     return;
156   end if;
157   --
158   hr_utility.set_location('get_accrual_ineligibility', 2);
159 
160   close  plan_for_input_value;
161 
162   -- Now check for the assignment's enrollment into the plan
163   -- and the assignment's length of service relative to ineligible period.
164 
165   SELECT	pps.date_start
166   INTO		v_service_start
167   FROM		per_periods_of_service	pps,
168 		per_assignments_f	paf
169   WHERE		paf.assignment_id	= p_asg_id
170   AND		p_sess_date	BETWEEN paf.effective_start_date
171 				AND	paf.effective_end_date
172   AND		pps.person_id		= paf.person_id
173   AND		paf.business_group_id	= p_bg_id
174   AND		p_sess_date	BETWEEN pps.date_start AND pps.final_process_date;
175 
176   if v_formula_id is null then
177 
178      --
179      --  As no eligibility formula, we use the info in the
180      --  accrual plan table to check for ineligibility
181      --
182 
183      -- First check ineligible period, then check accrual start...
184 
185      hr_utility.set_location('get_accrual_ineligibility', 3);
186      hr_utility.trace('Service Start is: ' || v_service_start);
187      hr_utility.trace('Ineligible length is:' || v_inel_length);
188 
189      IF v_inel_length <> 0 THEN
190 
191        hr_utility.set_location('get_accrual_ineligibility', 4);
192 
193        -- Calculate how many days are ineligible...
194        IF v_inel_period_type = 'CM' THEN
195 
196          v_eligible_date := ADD_MONTHS(v_service_start, v_inel_length);
197 
198        ELSIF v_inel_period_type = 'W' THEN
199 
200          v_eligible_date := v_service_start + (v_inel_length * 7);
201 
202        ELSIF v_inel_period_type = 'F' THEN
203 
204          v_eligible_date := v_service_start + (v_inel_length * 14);
205 
206        ELSIF v_inel_period_type = 'SM' THEN
207 
208          v_semi_days := MOD(v_inel_length, 2);
209 
210          IF v_semi_days <> 0 THEN
211 
212            v_semi_days := 15;	-- ie. an odd number of semi-months.
213 
214          END IF;
215 
216          v_eligible_date := ADD_MONTHS(v_service_start, (v_inel_length / 2));
217          v_eligible_date := v_eligible_date + v_semi_days;
218 
219        ELSIF v_inel_period_type = 'Q' THEN
220 
221          v_eligible_date := ADD_MONTHS(v_service_start, (v_inel_length * 3));
222 
223        ELSIF v_inel_period_type = 'Y' THEN
224 
225          v_eligible_date := ADD_MONTHS(v_service_start, (v_inel_length * 12));
226 
227        ELSIF v_inel_period_type = 'SY' THEN
228 
229          v_eligible_date := ADD_MONTHS(v_service_start, (v_inel_length * 6));
230 
231        ELSIF v_inel_period_type = 'LM' THEN
232 
233          v_eligible_date := v_service_start + (v_inel_length * 26);
234 
235        ELSIF v_inel_period_type = 'BM' THEN
236 
237          v_eligible_date := ADD_MONTHS(v_service_start, (v_inel_length * 2));
238 
239        END IF;	-- Inel Period Types
240 
241      ELSIF v_start_rule = 'PLUS_SIX_MONTHS' THEN
242 
243        -- Inel length = 0, check Accrual Start for 6 month inel.
244        -- Ie. you can't take time against an accrual for which you haven't
245        -- started accruing!
246 
247        v_eligible_date := ADD_MONTHS(v_service_start, 6);
248 
249      ELSIF v_start_rule = 'HD' then
250 
251        v_eligible_date := v_service_start;
252 
253      ELSIF v_start_rule = 'BOY' then
254 
255        v_eligible_date := TRUNC(ADD_MONTHS(v_service_start, 12), 'YEAR');
256 
257      END IF;
258 
259      hr_utility.set_location('get_accrual_ineligibility', 5);
260      hr_utility.trace('Eligible Date is: ' || v_eligible_date);
261      hr_utility.trace('Session Date is: ' || p_sess_date);
262 
263      -- Eligible or what?
264 
265      IF p_sess_date >= nvl(v_eligible_date,p_sess_date) THEN -- #4762608
266        hr_utility.set_location('get_accrual_ineligibility', 6);
267 
268        p_eligible := 'Y';
269 
270      ELSE
271        hr_utility.set_location('get_accrual_ineligibility', 7);
272 
273        p_eligible := 'N';
274 
275      END IF;
276 
277   else
278      --
279      -- Use ineligibilty accrual plan formula to calculate
280      -- ineligibility
281      --
282 
283      -- Initialise the Inputs and  Outputs tables
284      ff_exec.init_formula
285         ( v_formula_id
286         , p_sess_date
287         , l_inputs
288         , l_outputs );
289 --
290      -- Set up context values for the formula
291      for i in l_inputs.first..l_inputs.last loop
292 
293        if l_inputs(i).name = 'DATE_EARNED' then
294          l_inputs(i).value := p_sess_date;
295 
296        elsif l_inputs(i).name = 'ASSIGNMENT_ID' then
297          l_inputs(i).value := p_asg_id;
298 
299        elsif l_inputs(i).name = 'ACCRUAL_PLAN_ID' then
300          l_inputs(i).value := v_plan_id;
301 
302        end if;
303      end loop;
304 
305      -- Run the formula
306      ff_exec.run_formula( l_inputs, l_outputs );
307 
308      -- Get the result
309      p_eligible := l_outputs(l_outputs.first).value;
310 
311   end if;
312 
313 EXCEPTION
314       WHEN NO_DATA_FOUND THEN NULL;
315 
316 END get_accrual_ineligibility;
317 
318 --
319 -- **********************************************************************
320 
321 FUNCTION calc_accrual_pay (	p_bg_id		IN   NUMBER,
322 				p_asg_id 	IN   NUMBER,
323 				p_eff_date	IN   DATE,
324 				p_hours_taken 	IN   NUMBER,
325 				p_curr_rate	IN   NUMBER,
326 				p_mode		IN   VARCHAR2) RETURN NUMBER IS
327 
328 l_vac_pay	NUMBER(27,7)	:= 0;
329 l_vac_hours	NUMBER(10,7)	:= 0;
330 l_vac_tot_hrs	NUMBER(10,7)	:= 0;
331 
332 l_sick_pay	NUMBER(27,7)	:= 0;
333 l_sick_hours	NUMBER(10,7)	:= 0;
334 l_sick_tot_hrs	NUMBER(10,7)	:= 0;
335 
336 CURSOR get_vac_hours IS
337 select  fnd_number.canonical_to_number(pev.screen_entry_value)
338 from	pay_accrual_plans 		pap,
339 	pay_element_entries_f 		pee,
340 	pay_element_entry_values_f	pev
341 where	pap.accrual_category 	= 'V'
342 and	pap.business_group_id	= p_bg_id
343 and	pev.input_value_id	= pap.pto_input_value_id
344 and	p_eff_date              between pev.effective_start_date
345 			    	    and pev.effective_end_date
346 and	pee.element_entry_id	= pev.element_entry_id
347 and	pee.assignment_id	= p_asg_id
348 and	p_eff_date              between pee.effective_start_date
349 			    	    and pee.effective_end_date;
350 
351 -- The "vacation_pay" function looks for hours entered against Vacation plans
352 -- in the current period.  The number of hours are summed and multiplied by
353 -- the current rate of Regular Pay..
354 -- Return immediately when no vacation time has been taken.
355 -- Need to loop thru all "Vacation Plans" and check for entries in the current
356 -- period for this assignment.
357 
358 CURSOR get_sick_hours IS
359 select	fnd_number.canonical_to_number(pev.screen_entry_value)
360 from	pay_accrual_plans 		pap,
361 	pay_element_entries_f 		pee,
362 	pay_element_entry_values_f	pev
363 where	pap.accrual_category 	= 'S'
364 and	pap.business_group_id	= p_bg_id
365 and	pev.input_value_id	= pap.pto_input_value_id
366 and	p_eff_date	        between pev.effective_start_date
367 			    	    and pev.effective_end_date
368 and	pee.element_entry_id	= pev.element_entry_id
369 and	pee.assignment_id	= p_asg_id
370 and	p_eff_date              between pee.effective_start_date
371 			    	    and pee.effective_end_date;
372 
373 -- The "sick_pay" function looks for hours entered against Sick plans in the
374 -- current period.  The number of hours are summed and multiplied by the
375 -- current rate of Regular Pay.
376 -- Return immediately when no sick time has been taken.
377 
378 BEGIN
379 
380 hr_utility.set_location('calc_accrual_pay', 11);
381 IF p_mode = 'V' THEN
382 
383   hr_utility.set_location('calc_accrual_pay', 12);
384   OPEN get_vac_hours;
385   LOOP
386 
387     hr_utility.set_location('calc_accrual_pay', 13);
388     FETCH get_vac_hours
389     INTO  l_vac_hours;
390     EXIT  WHEN get_vac_hours%NOTFOUND;
391 
392     hr_utility.set_location('calc_accrual_pay', 14);
393     hr_utility.set_location('l_vac_hours =', l_vac_hours);
394     l_vac_tot_hrs := l_vac_tot_hrs + l_vac_hours;
395     hr_utility.set_location('l_vac_tot_hrs =', l_vac_tot_hrs);
396 
397   END LOOP;
398   CLOSE get_vac_hours;
399   hr_utility.set_location('calc_accrual_pay', 15);
400 
401   IF l_vac_tot_hrs <> 0 THEN
402 
403     hr_utility.set_location('calc_accrual_pay', 16);
404     l_vac_pay := p_hours_taken * p_curr_rate;
405 
406   ELSE
407 
408     l_vac_pay := -777.77;
409 
410   END IF;
411 
412   RETURN l_vac_pay;
413 
414 ELSIF p_mode = 'S' THEN
415 
416   hr_utility.set_location('calc_accrual_pay', 17);
417   OPEN get_sick_hours;
418   LOOP
419 
420     hr_utility.set_location('calc_accrual_pay', 18);
421     FETCH get_sick_hours
422     INTO  l_sick_hours;
423     EXIT  WHEN get_sick_hours%NOTFOUND;
424 
425     hr_utility.set_location('calc_accrual_pay', 19);
426     l_sick_tot_hrs := l_sick_tot_hrs + l_sick_hours;
427 
428   END LOOP;
429   CLOSE get_sick_hours;
430   hr_utility.set_location('calc_accrual_pay', 20);
431 --
432 -- Rmonge 02/26/2002
433 -- Fix for bug 2006907
434 -- Changing sick_tot_hrs > 0 to sick_tot_hrs <> 0
435 --
436   IF l_sick_tot_hrs <> 0 THEN
437 
438     hr_utility.set_location('calc_accrual_pay', 21);
439     l_sick_pay := p_hours_taken * p_curr_rate;
440 
441   ELSE
442 
443     l_sick_pay := -999.99;
444 
445   END IF;
446 
447   RETURN l_sick_pay;
448 
449 ELSE
450 
451   hr_utility.set_location('Accrual Pay mode not set to V or S', 99);
452   l_vac_pay := 0;
453   return l_vac_pay;
454 
455 END IF;
456 
457 END calc_accrual_pay;
458 --
459 FUNCTION accrual_time_taken (	p_bg_id		IN  NUMBER,
460 				p_asg_id 	IN  NUMBER,
461 				p_eff_date	IN  DATE,
462 				p_mode		IN  VARCHAR2) RETURN NUMBER IS
463 
464 l_hours_taken	NUMBER(7,3)	:= 0;
465 
466 BEGIN
467 
468 hr_utility.set_location('accrual_time_taken', 1);
469 select	sum(fnd_number.canonical_to_number(pev.screen_entry_value))
470 into	l_hours_taken
471 from	pay_accrual_plans 		pap,
472 	pay_element_entries_f 		pee,
473 	pay_element_entry_values_f	pev
474 where	pap.accrual_category 	= p_mode
475 and	pap.business_group_id	= p_bg_id
476 and	pev.input_value_id	= pap.pto_input_value_id
477 and	p_eff_date              between pev.effective_start_date
478 			    	    and pev.effective_end_date
479 and	pee.element_entry_id	= pev.element_entry_id
480 and	pee.assignment_id	= p_asg_id
481 and	p_eff_date              between pee.effective_start_date
482 			    	    and pee.effective_end_date;
483 
484 hr_utility.set_location('accrual_time_taken', 3);
485 return l_hours_taken;
486 
487 EXCEPTION
488 
489   WHEN NO_DATA_FOUND THEN
490 
491     hr_utility.set_location('accrual_time_taken', 5);
492     return l_hours_taken;
493 
494 END accrual_time_taken;
495 
496 END hr_us_accrual_plans;