DBA Data[Home] [Help]

PACKAGE BODY: APPS.PQP_NL_PGGM_FUNCTIONS

Source


1 PACKAGE BODY PQP_NL_PGGM_FUNCTIONS AS
2 /* $Header: pqpnlpgg.pkb 120.20 2012/01/19 07:41:17 rpahune ship $ */
3 
4 --
5 --Cursor to fetch the max. salary value beyond which
6 --the threshold is constant,from global values
7 --
8 CURSOR c_get_global_value(c_global_name IN VARCHAR2,c_date_earned IN DATE) IS
9 SELECT nvl(fnd_number.canonical_to_number(global_value),0)
10   FROM ff_globals_f
11 WHERE  global_name = c_global_name
12   AND  legislation_code = 'NL'
13   AND  (c_date_earned between effective_start_date and effective_end_date);
14 
15 
16 CURSOR c_get_num_periods_per_year(c_payroll_action_id IN NUMBER)  IS
17 SELECT TPTYPE.number_per_fiscal_year
18  FROM  pay_payroll_actions     PACTION
19       ,per_time_periods        TPERIOD
20       ,per_time_period_types   TPTYPE
21 WHERE PACTION.payroll_action_id   = c_payroll_action_id
22   AND TPERIOD.payroll_id          = PACTION.payroll_id
23   AND (PACTION.date_earned   between TPERIOD.start_date
24                                 and TPERIOD.end_date)
25   AND TPTYPE.period_type          = TPERIOD.period_type;
26 
27 --9975522
28 CURSOR c_get_global_value_custom(c_global_name IN VARCHAR2, c_date_earned IN DATE, c_business_group_id IN NUMBER) IS
29 SELECT nvl(fnd_number.canonical_to_number(global_value),0)
30   FROM ff_globals_f
31 WHERE  global_name = c_global_name
32   AND  legislation_code IS NULL
33   AND  business_group_id = c_business_group_id
34   AND  (c_date_earned between effective_start_date and effective_end_date);
35 --9975522
36 
37 
38 
39 --
40 -- ----------------------------------------------------------------------------
41 -- |------------------------< CHECK_ELIGIBILITY >-----------------------------|
42 -- ----------------------------------------------------------------------------
43 --
44 -- This function is used to check if an employee is eligible to contribute
45 -- towards a particular pension type by verifying that the employee age
46 -- falls between the minimum and maximum ages for the pension type
47 
48 FUNCTION CHECK_ELIGIBILITY
49    (p_date_earned       IN  DATE
50    ,p_business_group_id IN  NUMBER
51    ,p_person_age        IN  NUMBER
52    ,p_pension_type_id   IN  NUMBER
53    ,p_eligible          OUT NOCOPY NUMBER
54    ,p_err_message       OUT NOCOPY VARCHAR2)
55 
56 RETURN NUMBER IS
57 
58 --
59 --Cursor to fetch the min. and max. age specified at the pension type
60 --
61 CURSOR c_get_min_max_ages IS
62 SELECT nvl(minimum_age,0),nvl(maximum_age,100)
63  FROM  pqp_pension_types_f
64 WHERE  pension_type_id = p_pension_type_id
65   AND  p_date_earned BETWEEN effective_start_date
66   AND  effective_end_date;
67 
68 l_min_age   NUMBER := 0;
69 l_max_age   NUMBER := 100;
70 l_ret_value NUMBER := 0;
71 l_proc_name VARCHAR2(30) := 'CHECK_ELIGIBILITY';
72 
73 BEGIN
74 
75 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
76 --Query up the min. and max. age specified at the pension type
77 
78 OPEN c_get_min_max_ages;
79 FETCH c_get_min_max_ages INTO l_min_age,l_max_age;
80 
81 IF c_get_min_max_ages%FOUND THEN
82    --the min and max ages have been found,now check for eligibility
83 
84    CLOSE c_get_min_max_ages;
85    hr_utility.set_location('Min. and Max. ages are : '||l_min_age||
86                            ' and '||l_max_age,20);
87 
88    IF p_person_age BETWEEN l_min_age and l_max_age THEN
89       --the person is eligible for the pension type
90 
91       hr_utility.set_location('Person is eligible, age is : '||p_person_age,30);
92       p_eligible := 1;
93 
94    ELSE
95       --the person is not eligible for this pension type
96       hr_utility.set_location('Person is not eligible, age is : '||p_person_age,30);
97       p_err_message := 'This person is not eligible for the pension type';
98       p_eligible := 0;
99       l_ret_value := 2;
100 
101    END IF;
102 
103 ELSE
104    --no row could be found for this pension type
105    CLOSE c_get_min_max_ages;
106    hr_utility.set_location('No row could be found for this pension type',40);
107    p_err_message := 'No row could be found for this pension type on this date';
108    p_eligible := 0;
109    l_ret_value := 2;
110 
111 END IF;
112 
113 hr_utility.set_location('Returning from : '||g_pkg_name||l_proc_name,50);
114 
115 RETURN 0;
116 
117 EXCEPTION
118 WHEN OTHERS THEN
119    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,60);
120    p_eligible := 0;
121    p_err_message := 'Error occured when determining eligibility : '||SQLERRM;
122    RETURN 1;
123 
124 END CHECK_ELIGIBILITY;
125 
126 --
127 -- ----------------------------------------------------------------------------
128 -- |-------------------------< GET_CONTRIBUTION >-----------------------------|
129 -- ----------------------------------------------------------------------------
130 --
131 -- This function is used to get the contribution percentage / flat amount from
132 -- the org hierarchy or from the pension types table if there is no override
133 -- at the org hierarchy level
134 
135 FUNCTION GET_CONTRIBUTION
136    (p_assignment_id     IN  NUMBER
137    ,p_date_earned       IN  DATE
138    ,p_business_group_id IN  NUMBER
139    ,p_ee_or_total       IN  NUMBER
140    ,p_pension_type_id   IN  NUMBER
141    ,p_contrib_value     OUT NOCOPY NUMBER
142    ,p_err_message       OUT NOCOPY VARCHAR2)
143 
144 RETURN NUMBER IS
145 
146 --
147 -- Cursor to fetch the org id for a given assignment id
148 --
149 CURSOR c_get_org_id IS
150 SELECT organization_id
151   FROM per_all_assignments_f
152 WHERE  assignment_id = p_assignment_id
153   AND  p_date_earned BETWEEN effective_start_date
154   AND  effective_end_date;
155 
156 --
157 -- Cursor to get the parent org id for a given organization
158 -- given the version id of the org hierarchy defined
159 --
160 CURSOR c_get_parent_id(c_org_id     IN NUMBER
161                       ,c_version_id IN NUMBER) IS
162 SELECT organization_id_parent
163   FROM per_org_structure_elements
164 WHERE  organization_id_child = c_org_id
165   AND  org_structure_version_id = c_version_id
166   AND  business_group_id = p_business_group_id;
167 
168 --
169 -- Cursor to get the percentage value from the ORG EIT
170 --
171 CURSOR c_get_contrib_frm_org(c_org_id IN NUMBER) IS
172 SELECT decode(p_ee_or_total,0,nvl(fnd_number.canonical_to_number(org_information4),0)
173              ,nvl(fnd_number.canonical_to_number(org_information5),0))
174   FROM hr_organization_information
175 WHERE  org_information_context = 'PQP_NL_PGGM_PT'
176   AND  organization_id = c_org_id
177   AND  p_date_earned BETWEEN fnd_date.canonical_to_date(org_information1)
178   AND  nvl(fnd_date.canonical_to_date(org_information2),hr_api.g_eot)
179   AND  fnd_number.canonical_to_number(org_information3) = p_pension_type_id;
180 
181 --
182 -- Cursor to get the percentage value from the pension types table
183 --
184 CURSOR c_get_contrib_frm_pt IS
185 SELECT decode(p_ee_or_total,0,nvl(ee_contribution_percent,0)
186              ,nvl(er_contribution_percent,0))
187   FROM pqp_pension_types_f
188 WHERE  pension_type_id = p_pension_type_id
189   AND  p_date_earned BETWEEN effective_start_date
190   AND  effective_end_date;
191 
192 l_proc_name         VARCHAR2(30) := 'GET_CONTRIBUTION';
193 l_loop_again        NUMBER := 1;
194 l_emp_or_total      VARCHAR2(30) := 'Employee';
195 l_org_contrib_found NUMBER := 0;
196 l_ret_value         NUMBER := 0;
197 l_version_id        NUMBER;
198 l_org_id            NUMBER;
199 l_contrib_value     NUMBER := 0;
200 
201 
202 BEGIN
203 
204 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
205 --First fetch the HR Org Id for the current assignment
206 OPEN c_get_org_id;
207 FETCH c_get_org_id INTO l_org_id;
208 CLOSE c_get_org_id;
209 hr_utility.set_location('Org Id for this assignment is : '||l_org_id,20);
210 
211 -- Now fetch the contribution percentages from the ORG EIT
212 -- This will proceed in a loop from the HR Organization
213 -- of this assignment and then up the org the hierarchy until
214 -- we find a EIT row or the topmost parent is reached
215 
216 IF p_ee_or_total = 0 THEN
217    l_emp_or_total := 'Employee';
218 ELSE
219    l_emp_or_total := 'Total';
220 END IF;
221 hr_utility.set_location('Now deriving contribution percentage for : '||l_emp_or_total,25);
222 
223 --check to see if the version id is already present for this business group
224 IF NOT g_version_info.EXISTS(p_business_group_id) THEN
225    --no cached value of the version id exists for this BG
226    g_version_info(p_business_group_id).version_id
227    := pqp_pension_functions.GET_VERSION_ID(p_business_group_id
228                                           ,p_date_earned);
229 
230 END IF;
231 
232 l_version_id := g_version_info(p_business_group_id).version_id;
233 hr_utility.set_location('Org Hierarchy version id : '||l_version_id,27);
234 
235 WHILE (l_loop_again = 1)
236 LOOP
237    OPEN c_get_contrib_frm_org(l_org_id);
238    FETCH c_get_contrib_frm_org INTO l_contrib_value;
239 
240    IF c_get_contrib_frm_org%FOUND THEN
241       --Contribution percentages have been found at this org
242       hr_utility.set_location('Contribution values found at org : '||l_org_id,30);
243       CLOSE c_get_contrib_frm_org;
244 
245       p_contrib_value := fnd_number.canonical_to_number(l_contrib_value);
246 
247       --set the flag indicating that contribution percentage has been found at the
248       --ORG level, so we dont need to continue any further
249       l_org_contrib_found := 1;
250 
251       hr_utility.set_location('Contribution percentage is : '||p_contrib_value,40);
252       --we no longer need to continue up the hierarchy
253       l_loop_again := 0;
254 
255    ELSE
256       --contribution percentages not found at this org, now move up the hierarchy
257       --find the parent org for this current org
258       CLOSE c_get_contrib_frm_org;
259       OPEN c_get_parent_id(c_org_id     => l_org_id
260                           ,c_version_id => l_version_id);
261       FETCH c_get_parent_id INTO l_org_Id;
262 
263       IF c_get_parent_id%FOUND THEN
264          --a parent org has been found,so we can loop again
265          CLOSE c_get_parent_id;
266 
267       ELSE
268          --no further parents exist,so exit the loop
269          CLOSE c_get_parent_id;
270          l_loop_again := 0;
271 
272          --set the flag indicating that org contributions
273          --have not been found, so derive it from the Pension Type
274          l_org_contrib_found := 0;
275 
276       END IF;
277 
278    END IF;
279 
280 END LOOP;
281 
282 --now check to see if the contribution percentage
283 --has been found at the ORG level or do we need to
284 --derive it from the pension type
285 IF l_org_contrib_found = 0 THEN
286   hr_utility.set_location('No contribution values found at the org'||
287                           ' ,now deriving it from the pension type',50);
288   --contribution values have not been found at the ORG level
289   --query up the contribution percentages from the pension type
290   OPEN c_get_contrib_frm_pt;
291   FETCH c_get_contrib_frm_pt INTO p_contrib_value;
292 
293   IF c_get_contrib_frm_pt%FOUND THEN
294      --contribution percentages have been found from the pension type
295      hr_utility.set_location('Contribution derived from pension type : '
296                              ||p_contrib_value,60);
297      CLOSE c_get_contrib_frm_pt;
298 
299   ELSE
300      --no data has been found for this pension type, this is an error condition
301      CLOSE c_get_contrib_frm_pt;
302      hr_utility.set_location('No data could be found for the pension type on date earned',70);
303      p_contrib_value := 0;
304      p_err_message := 'No data could be found for the pension type attached to '
305                      ||'this scheme on the date earned.';
306      l_ret_value := 2;
307 
308   END IF;
309 
310 END IF;
311 
312 hr_utility.set_location('Returning from : '||g_pkg_name||l_proc_name,80);
313 RETURN l_ret_value;
314 
315 EXCEPTION
316 WHEN OTHERS THEN
317    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,90);
318    p_contrib_value := 0;
319    p_err_message := 'Error occured when determining contribution : '||SQLERRM;
320    RETURN 1;
321 
322 END GET_CONTRIBUTION;
323 
324 --
325 -- ----------------------------------------------------------------------------
326 -- |-----------------------< GET_AGE_DEPENDANT_THLD>--------------------------|
327 -- ----------------------------------------------------------------------------
328 --
329 -- This function is used to derive the age dependant threshold for an employee
330 -- based on his/her age from a user defined table
331 
332 FUNCTION GET_AGE_DEPENDANT_THLD
333    (p_person_age        IN  NUMBER
334    ,p_business_group_id IN  NUMBER
335    ,p_date_earned       IN  DATE)
336 
337 RETURN NUMBER IS
338 
339 --
340 --Cursor to fetch the maximum age for which thresholds are defined
341 --all ages above this value have the same threshold
342 --
343 CURSOR c_get_max_age IS
344 SELECT max(fnd_number.canonical_to_number(row_low_range_or_name))
345   FROM pay_user_rows_f
346 WHERE  p_date_earned BETWEEN effective_start_date
347   AND  effective_end_date
348   AND  user_table_id = (SELECT user_table_id
349                           FROM pay_user_tables
350                         WHERE  user_table_name = 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD'
351                           AND  legislation_code = 'NL'
352                        );
353 
354 --9975522
355 CURSOR c_get_max_age_custom IS
356 SELECT max(fnd_number.canonical_to_number(row_low_range_or_name))
357   FROM pay_user_rows_f
358 WHERE  p_date_earned BETWEEN effective_start_date
359   AND  effective_end_date
360   AND  user_table_id = (SELECT user_table_id
361                           FROM pay_user_tables
362                         WHERE  user_table_name = 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD_CUSTOM'
363                           AND  legislation_code = 'NL'
364                        );
365 --9975522
366 
367 
368 l_proc_name            VARCHAR2(30) := 'GET_AGE_DEPENDANT_THLD';
369 l_return_value         pay_user_column_instances.value%TYPE;
370 l_value_found          NUMBER := 0;
371 l_threshold_percentage NUMBER := 0;
372 l_max_age              NUMBER;
373 
374 BEGIN
375 
376 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
377 
378 --9975522
379 --FIRST CHECK INTO THE CUSTOME USER TABLE IF NOT THEN SEEDED
380 --first check to see if the user defined table for age dependant
381 --thresholds has a row for the person's age, then return this value
382 BEGIN
383 hr_utility.set_location('Checking for threshold percentage for age : '||p_person_age,200);
384 l_return_value :=
385 		   hruserdt.get_table_value
386 		   (
387 		    p_bus_group_id    => p_business_group_id
388 		   ,p_table_name      => 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD_CUSTOM'
389 		   ,p_col_name        => 'Percentage Of Maximum Threshold'
390 		   ,p_row_value       => p_person_age
391 		   ,p_effective_date  => p_date_earned
392 		   );
393 
394 l_value_found := 1;
395 l_threshold_percentage := nvl(fnd_number.canonical_to_number(l_return_value),0);
396 hr_utility.set_location('Threshold percentage derived as : '||l_threshold_percentage,300);
397 
398 EXCEPTION
399 WHEN NO_DATA_FOUND THEN
400    l_value_found := 0;
401 
402 END;
403 
404 --if no value has been found for the person's age, find the maximum age
405 --for which values have been defined, if the person's age exceeds this age
406 --then the value applicable for the person is the same as the value defined
407 --for the maximum age
408 IF l_value_found = 0 THEN
409 
410    hr_utility.set_location('No row found for the person''s age,now finding max age',400);
411    --query up the maximum age defined in the rows for this user defined tbl
412    OPEN c_get_max_age_custom;
413    FETCH c_get_max_age_custom INTO l_max_age;
414    IF c_get_max_age_custom%FOUND THEN
415 
416       --Found the maximum age upto which thresholds have been defined
417       hr_utility.set_location('Max age in threshold udt : '||l_max_age,500);
418       CLOSE c_get_max_age_custom;
419 
420       --if the person's age is > the max age, then the threshold is the same
421       --as the value defined for this max age
422       IF p_person_age > l_max_age THEN
423 
424          BEGIN
425          l_return_value :=
426                         hruserdt.get_table_value
427                         (
428                          p_bus_group_id    => p_business_group_id
429                         ,p_table_name      => 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD_CUSTOM'
430                         ,p_col_name        => 'Percentage Of Maximum Threshold'
431                         ,p_row_value       => l_max_age
432                         ,p_effective_date  => p_date_earned
433                         );
434 	   l_value_found := 1;
435          l_threshold_percentage := nvl(fnd_number.canonical_to_number(l_return_value),0);
436          hr_utility.set_location('value of max age used : '||l_threshold_percentage,600);
437 
438          EXCEPTION
439          WHEN NO_DATA_FOUND THEN
440 	      l_value_found := 0;
441             l_threshold_percentage := 0;
442          END;
443 
444       --else the person's age is lesser than the max age and no row has been defined
445       ELSE
446          l_value_found := 0;
447          l_threshold_percentage := 0;
448 
449       END IF;
450 
451    --else no rows have been defined for the user defined table
452    --so return the percentage as 0
453    ELSE
454 
455       hr_utility.set_location('No rows were defined for the udt',700);
456       CLOSE c_get_max_age_custom;
457 	l_value_found := 0;
458       l_threshold_percentage := 0;
459 
460    END IF;
461 
462 END IF;
463 --9975522
464 
465 IF l_value_found = 0 THEN --IF NO VALUE FOUND IN CUSTOM TABLE --9975522
466 	--first check to see if the user defined table for age dependant
467 	--thresholds has a row for the person's age, then return this value
468 	BEGIN
469 	hr_utility.set_location('Checking for threshold percentage for age : '||p_person_age,20);
470 	l_return_value :=
471 			   hruserdt.get_table_value
472 			   (
473 			    p_bus_group_id    => p_business_group_id
474 			   ,p_table_name      => 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD'
475 			   ,p_col_name        => 'Percentage Of Maximum Threshold'
476 			   ,p_row_value       => p_person_age
477 			   ,p_effective_date  => p_date_earned
478 			   );
479 
480 	l_value_found := 1;
481 	l_threshold_percentage := nvl(fnd_number.canonical_to_number(l_return_value),0);
482 	hr_utility.set_location('Threshold percentage derived as : '||l_threshold_percentage,30);
483 
484 	EXCEPTION
485 	WHEN NO_DATA_FOUND THEN
486 	   l_value_found := 0;
487 
488 	END;
489 
490 	--if no value has been found for the person's age, find the maximum age
491 	--for which values have been defined, if the person's age exceeds this age
492 	--then the value applicable for the person is the same as the value defined
493 	--for the maximum age
494 	IF l_value_found = 0 THEN
495 
496 	   hr_utility.set_location('No row found for the person''s age,now finding max age',40);
497 	   --query up the maximum age defined in the rows for this user defined tbl
498 	   OPEN c_get_max_age;
499 	   FETCH c_get_max_age INTO l_max_age;
500 	   IF c_get_max_age%FOUND THEN
501 
502 		--Found the maximum age upto which thresholds have been defined
503 		hr_utility.set_location('Max age in threshold udt : '||l_max_age,50);
504 		CLOSE c_get_max_age;
505 
506 		--if the person's age is > the max age, then the threshold is the same
507 		--as the value defined for this max age
508 		IF p_person_age > l_max_age THEN
509 
510 		   BEGIN
511 		   l_return_value :=
512 					hruserdt.get_table_value
513 					(
514 					 p_bus_group_id    => p_business_group_id
515 					,p_table_name      => 'PQP_NL_PGGM_AGE_DEPENDANT_THRESHOLD'
516 					,p_col_name        => 'Percentage Of Maximum Threshold'
517 					,p_row_value       => l_max_age
518 					,p_effective_date  => p_date_earned
519 					);
520 		   l_threshold_percentage := nvl(fnd_number.canonical_to_number(l_return_value),0);
521 		   hr_utility.set_location('value of max age used : '||l_threshold_percentage,60);
522 
523 		   EXCEPTION
524 		   WHEN NO_DATA_FOUND THEN
525 			l_threshold_percentage := 0;
526 		   END;
527 
528 		--else the person's age is lesser than the max age and no row has been defined
529 		ELSE
530 
531 		   l_threshold_percentage := 0;
532 
533 		END IF;
534 
535 	   --else no rows have been defined for the user defined table
536 	   --so return the percentage as 0
537 	   ELSE
538 
539 		hr_utility.set_location('No rows were defined for the udt',70);
540 		CLOSE c_get_max_age;
541 		l_threshold_percentage := 0;
542 
543 	   END IF;
544 
545 	END IF;
546 END IF; -- IF NO VALUE FOUND IN CUSTOM TABLE --9975522
547 
548 hr_utility.set_location('Value of threshold percentage is : '||l_threshold_percentage,75);
549 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,80);
550 
551 RETURN l_threshold_percentage;
552 
553 EXCEPTION
554 WHEN OTHERS THEN
555    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,90);
556    RETURN 0;
557 
558 END GET_AGE_DEPENDANT_THLD;
559 
560 --=============================================================================
561 -- Function to get the age of a person given the effective date
562 --=============================================================================
563 FUNCTION Get_Age
564          (p_assignment_id   IN  per_all_assignments_f.assignment_id%TYPE
565          ,p_effective_date  IN  DATE
566 	 ,p_begin_of_year_date IN DATE)
567 RETURN NUMBER IS
568 
569 CURSOR get_dob IS
570 SELECT trunc(date_of_birth)
571   FROM per_all_people_f per
572       ,per_all_assignments_f paf
573  WHERE per.person_id      = paf.person_id
574    AND paf.assignment_id  = p_assignment_id
575    AND p_effective_date BETWEEN per.effective_start_date
576                             AND per.effective_end_date
577    AND p_effective_date BETWEEN paf.effective_start_date
578                             AND paf.effective_end_date;
579 
580 l_age NUMBER;
581 l_dob DATE;
582 
583 BEGIN
584 
585 --
586 --Fetch the date of birth
587 --
588 OPEN get_dob;
589 FETCH get_dob INTO l_dob;
590 CLOSE get_dob;
591 
592 l_dob := NVL(l_dob,p_effective_date);
593 
594 RETURN (TRUNC(MONTHS_BETWEEN(p_begin_of_year_date,l_dob)/12,2));
595 
596 END Get_Age;
597 
598 
599 --
600 -- ----------------------------------------------------------------------------
601 -- |-------------------------< GET_PENSION_BASIS >-----------------------------|
602 -- ----------------------------------------------------------------------------
603 --
604 -- This function is used to derive the pension basis value for a given pension
605 -- type based on the basis method defined
606 
607 FUNCTION GET_PENSION_BASIS
608    (
609     p_payroll_action_id    IN  NUMBER
610    ,p_date_earned          IN  DATE
611    ,p_business_group_id    IN  NUMBER
612    ,p_person_age           IN  NUMBER
613    ,p_pension_type_id      IN  NUMBER
614    ,p_pension_salary       IN  NUMBER
615    ,p_part_time_percentage IN  NUMBER
616    ,p_pension_basis        OUT NOCOPY NUMBER
617    ,p_err_message          OUT NOCOPY VARCHAR2
618    ,p_avlb_thld            IN  OUT NOCOPY NUMBER
619    ,p_used_thld            IN  OUT NOCOPY NUMBER)
620 
621 RETURN NUMBER IS
622 
623 --
624 --Cursor to fetch the basis method from the pension type
625 --
626 CURSOR c_get_basis_method IS
627 SELECT pension_basis_calc_method
628   FROM pqp_pension_types_f
629 WHERE  pension_type_id = p_pension_type_id
630   AND  p_date_earned BETWEEN effective_start_date
631   AND  effective_end_date;
632 
633 l_proc_name            VARCHAR2(30) := 'GET_PENSION_BASIS';
634 l_ret_value            NUMBER := 0;
635 l_threshold_salary     NUMBER;
636 l_max_salary_threshold NUMBER;
637 l_max_age_threshold    NUMBER;
638 l_threshold            NUMBER;
639 l_threshold_percentage NUMBER;
640 l_avlb_thld            NUMBER := 0;
641 l_used_thld            NUMBER := 0;
642 l_basis_method         pqp_pension_types_f.pension_basis_calc_method%TYPE;
643 l_num_periods          NUMBER :=12;
644 
645 BEGIN
646 --hr_utility.trace_on(null,'SS');
647 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
648 
649 --first fetch the basis method for this pension type
650 OPEN c_get_basis_method;
651 FETCH c_get_basis_method INTO l_basis_method;
652 CLOSE c_get_basis_method;
653 
654 --Get number of payroll periods in a year
655 OPEN c_get_num_periods_per_year(p_payroll_action_id);
656 FETCH c_get_num_periods_per_year INTO l_num_periods;
657 CLOSE c_get_num_periods_per_year;
658 
659 --now calculate the basis value depending on the basis method
660 --derived above
661 IF l_basis_method = '6' THEN
662 
663    --basis method is (Pension Salary - Salary dependant threshold)
664    -- * Part Time Percentage
665 
666    hr_utility.set_location('Basis method : '||'(Pension Salary - Salary threshold)'
667                            ||' * Part Time %',20);
668    --9975522
669    OPEN c_get_global_value_custom('PQP_NL_PGGM_THRESHOLD_SALARY_CUSTOM', p_date_earned, p_business_group_id);
670    FETCH c_get_global_value_custom INTO l_threshold_salary;
671    --9975522
672    IF c_get_global_value_custom%FOUND THEN
673       CLOSE c_get_global_value_custom;
674       --the value for the threshold salary has been found
675       hr_utility.set_location('PQP_NL_PGGM_THRESHOLD_SALARY_CUSTOM : '||l_threshold_salary,25);
676    ELSE
677       CLOSE c_get_global_value_custom;
678    --9975522
679 
680 	--first derive the salary dependant threshold
681 	--query up the maximum salary
682 	OPEN c_get_global_value('PQP_NL_PGGM_THRESHOLD_SALARY',p_date_earned);
683 	FETCH c_get_global_value INTO l_threshold_salary;
684 
685 	IF c_get_global_value%FOUND THEN
686 	CLOSE c_get_global_value;
687 	--the value for the threshold salary has been found
688 	hr_utility.set_location('PQP_NL_PGGM_THRESHOLD_SALARY : '||l_threshold_salary,25);
689 
690 	ELSE
691 	CLOSE c_get_global_value;
692 	--the global value was not found,raise a warning
693 	hr_utility.set_location('PQP_NL_PGGM_THRESHOLD_SALARY not found',25);
694 	p_err_message := 'No value was found for the global PQP_NL_PGGM_THRESHOLD_SALARY';
695 	l_ret_value := 2;
696 
697 	END IF;
698    END IF; --9975522
699 
700    --9975522
701    OPEN c_get_global_value_custom('PQP_NL_PGGM_MAX_SALARY_THRESHOLD_CUSTOM', p_date_earned, p_business_group_id);
702    FETCH c_get_global_value_custom INTO l_max_salary_threshold;
703 
704    IF c_get_global_value_custom%FOUND THEN
705       CLOSE c_get_global_value_custom;
706       --the value for the salary threshold has been found
707       hr_utility.set_location('PQP_NL_PGGM_MAX_SALARY_THRESHOLD_CUSTOM : '||l_max_salary_threshold,26);
708    ELSE
709       CLOSE c_get_global_value_custom;
710    --9975522
711 	--query up the maximum salary dependant threshold
712 	OPEN c_get_global_value('PQP_NL_PGGM_MAX_SALARY_THRESHOLD',p_date_earned);
713 	FETCH c_get_global_value INTO l_max_salary_threshold;
714 
715 	IF c_get_global_value%FOUND THEN
716 	CLOSE c_get_global_value;
717 	--the value for the salary threshold has been found
718 	hr_utility.set_location('PQP_NL_PGGM_MAX_SALARY_THRESHOLD : '||l_max_salary_threshold,26);
719 
720 	ELSE
721 	CLOSE c_get_global_value;
722 	--the global value was not found,raise a warning
723 	hr_utility.set_location('PQP_NL_PGGM_MAX_SALARY_THRESHOLD not found',26);
724 	p_err_message := p_err_message || 'No value was found for the global'||
725 			    'PQP_NL_PGGM_MAX_SALARY_THRESHOLD';
726 	l_ret_value := 2;
727 
728 	END IF;
729 
730    END IF; --9975522
731 
732    IF (p_date_earned < to_date('01-01-2006','DD-MM-YYYY'))THEN
733       IF p_pension_salary >= l_threshold_salary THEN
734          l_threshold := l_max_salary_threshold;
735       ELSE
736          l_threshold := (p_pension_salary * l_max_salary_threshold)/
737                      (l_threshold_salary + 1);
738       END IF;
739    ELSE --Legislative year 2006 Change
740         l_threshold := l_max_salary_threshold; -- 9566 fixed value
741    END IF;
742 
743    hr_utility.set_location('Salary Dependant Threshold : '||l_threshold,30);
744 
745    p_pension_basis := (p_pension_salary - l_threshold)
746                       * p_part_time_percentage/100;
747 
748    p_pension_basis := p_pension_basis / l_num_periods;
749 
750 ELSIF l_basis_method = '7' THEN
751 
752    --basis method is Pension Salary * Part Time Percentage
753    hr_utility.set_location('Basis method : '||'(Pension Salary * Part Time %)',20);
754    p_pension_basis := p_pension_salary * p_part_time_percentage/100;
755 
756    p_pension_basis := p_pension_basis / l_num_periods;
757 
758 ELSIF l_basis_method = '8' THEN
759 
760    --basis method is (Pension Salary * Part Time Percentage) -
761    -- Age Dependant Threshold
762    hr_utility.set_location('Basis method : '||'(Pension Salary * Part Time %)'
763                            ||' - Age Threshold',20);
764 
765    --9975522
766    OPEN c_get_global_value_custom('PQP_NL_PGGM_MAX_AGE_THRESHOLD_CUSTOM', p_date_earned, p_business_group_id);
767    FETCH c_get_global_value_custom INTO l_max_age_threshold;
768 
769    IF c_get_global_value_custom%FOUND THEN
770       CLOSE c_get_global_value_custom;
771       --the value for the age threshold has been found
772       hr_utility.set_location('PQP_NL_PGGM_MAX_AGE_THRESHOLD_CUSTOM : '||l_max_age_threshold,22);
773    ELSE
774       CLOSE c_get_global_value_custom;
775    --9975522
776 
777 	--query up the maximum age dependant threshold
778 	OPEN c_get_global_value('PQP_NL_PGGM_MAX_AGE_THRESHOLD',p_date_earned);
779 	FETCH c_get_global_value INTO l_max_age_threshold;
780 
781 	IF c_get_global_value%FOUND THEN
782 	CLOSE c_get_global_value;
783 	--the value for the age threshold has been found
784 	hr_utility.set_location('PQP_NL_PGGM_MAX_AGE_THRESHOLD : '||l_max_age_threshold,22);
785 
786 	ELSE
787 	CLOSE c_get_global_value;
788 	--the global value was not found,raise a warning
789 	hr_utility.set_location('PQP_NL_PGGM_MAX_AGE_THRESHOLD not found',22);
790 	p_err_message := p_err_message || 'No value was found for the global'||
791 			    'PQP_NL_PGGM_MAX_AGE_THRESHOLD';
792 	l_ret_value := 2;
793 
794 	END IF;
795 
796    END IF; --9975522
797 
798    l_threshold_percentage := GET_AGE_DEPENDANT_THLD(p_person_age        => p_person_age
799                                                    ,p_business_group_id => p_business_group_id
800                                                    ,p_date_earned       => p_date_earned);
801 
802    IF l_threshold_percentage = 0 THEN
803       p_err_message := p_err_message ||' The age dependant threshold could not be '
804                       ||'derived for this person and 0 will be used';
805       l_ret_value := 2;
806    END IF;
807 
808    --Calculate Age dependent Threshold value and drop the decimals
809    l_threshold := trunc(l_max_age_threshold * l_threshold_percentage/100);
810 
811    hr_utility.set_location('Age Dependant Threshold : '||l_threshold,30);
812    hr_utility.set_location('Available threshold : '||l_avlb_thld,30);
813    hr_utility.set_location('Used Threshold : '||l_used_thld,30);
814 
815    l_avlb_thld := l_threshold/l_num_periods;
816 
817    l_threshold := GREATEST((p_avlb_thld + l_threshold/l_num_periods - p_used_thld),0);
818 
819    p_pension_basis := (p_pension_salary * p_part_time_percentage/100)/l_num_periods -
820                       l_threshold;
821 
822    IF p_pension_basis < 0 THEN
823       l_used_thld := (p_pension_salary * p_part_time_percentage/100)/l_num_periods;
824    ELSE
825       l_used_thld := l_threshold;
826    END IF;
827 
828 END IF;
829 
830 /*
831 Bug 5215600
832 SR : 5461519.993
833 --if the calculated pension basis is < 0 then restrict it to 0
834 IF p_pension_basis < 0 THEN
835    p_pension_basis := 0;
836 END IF;
837 */
838 p_avlb_thld := l_avlb_thld;
839 p_used_thld := l_used_thld;
840 
841 hr_utility.set_location('Calculated pension basis value : '||p_pension_basis,40);
842 hr_utility.set_location('Available threshold : '||l_avlb_thld,40);
843 hr_utility.set_location('Used Threshold : '||l_used_thld,40);
844 
845 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,50);
846 --hr_utility.trace_off;
847 
848 RETURN l_ret_value;
849 
850 EXCEPTION
851 WHEN OTHERS THEN
852    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,60);
853    p_pension_basis := 0;
854    p_err_message := 'Error occured while deriving the pension basis : '||SQLERRM;
855    RETURN 1;
856 
857 END GET_PENSION_BASIS;
858 
859 --
860 -- ----------------------------------------------------------------------------
861 -- |---------------------------< DO_PRORATION >-------------------------------|
862 -- ----------------------------------------------------------------------------
863 --
864 -- This function is used to perform a calendar day proration of the deduction
865 -- amount for starter/leavers
866 
867 FUNCTION DO_PRORATION
868    (p_assignment_id        IN  NUMBER
869    ,p_payroll_action_id    IN  NUMBER
870    ,p_period_start_date    IN  DATE
871    ,p_period_end_date      IN  DATE
872    ,p_dedn_amount          IN  OUT NOCOPY NUMBER
873    ,p_err_message          OUT NOCOPY VARCHAR2)
874 
875 RETURN NUMBER IS
876 
877 --
878 --Cursor to fetch the range of dates for which the assignment
879 --is active in the pay period
880 --
881 CURSOR c_get_asg_dates IS
882 SELECT asg.effective_start_date start_date
883       ,nvl(asg.effective_end_date,p_period_end_date) end_date
884  FROM  per_all_assignments_f asg,per_assignment_status_types past
885 WHERE  asg.assignment_id = p_assignment_id
886   AND  asg.assignment_status_type_id = past.assignment_status_type_id
887   AND  past.per_system_status = 'ACTIVE_ASSIGN'
888   AND  asg.effective_start_date <= p_period_end_date
889   AND  nvl(asg.effective_end_date,p_period_end_date)
890        >= p_period_start_date;
891 
892 --
893 --Cursor to fetch period type of payroll attached to assignment
894 --
895 CURSOR c_get_period_type(c_payroll_action_id IN NUMBER)
896 IS
897 SELECT TPERIOD.period_type
898  FROM  pay_payroll_actions     PACTION
899       ,per_time_periods        TPERIOD
900  WHERE PACTION.payroll_action_id   = c_payroll_action_id
901   AND TPERIOD.payroll_id          = PACTION.payroll_id
902   AND (PACTION.date_earned   between TPERIOD.start_date
903                                 and TPERIOD.end_date);
904 
905 
906 c_asg_row c_get_asg_dates%ROWTYPE;
907 
908 l_proc_name         VARCHAR2(30) := 'DO_PRORATION';
909 l_ret_value         NUMBER := 0;
910 l_start_date        DATE;
911 l_end_date          DATE;
912 l_days              NUMBER := 0;
913 l_payroll_days      NUMBER := 0;
914 l_non_insured_days  NUMBER := 0;
915 l_proration_factor  NUMBER := 1;
916 l_period_type       VARCHAR2(150);
917 l_num_of_days_in_period NUMBER:=30;
918 
919 BEGIN
920 
921 --first fetch the range of dates when the assignment is
922 --active in the pay period
923 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
924 
925 OPEN c_get_period_type(p_payroll_action_id);
926 FETCH c_get_period_type INTO l_period_type;
927 CLOSE c_get_period_type;
928  IF l_period_type='Calendar Month' THEN
929     l_num_of_days_in_period:= 30;
930  ELSE  IF l_period_type = 'Lunar Month' THEN
931          l_num_of_days_in_period:=28;
932        ELSE  IF l_period_type = 'Week' THEN
933                 l_num_of_days_in_period:=7;
934              ELSE IF l_period_type = 'Quarter' THEN
935                     l_num_of_days_in_period:=90;
936                   END IF;
937              END IF;
938        END IF;
939  END IF;
940 
941 FOR c_asg_row IN c_get_asg_dates
942 LOOP
943    --loop through all assignment rows effective in this pay period
944    --and find the number of days the person is insured for
945    IF c_asg_row.start_date < p_period_start_date THEN
946       l_start_date := p_period_start_date;
947    ELSE
948       l_start_date := c_asg_row.start_date;
949    END IF;
950 
951    IF c_asg_row.end_date > p_period_end_date THEN
952       l_end_date := p_period_end_date;
953    ELSE
954       l_end_date := c_asg_row.end_date;
955    END IF;
956 
957    l_days := l_days + (l_end_date - l_start_date) + 1;
958 
959 END LOOP;
960 
961 hr_utility.set_location('Assignment was active for : '||l_days||' days',20);
962 
963 --now find the days the person was not insured for in this period
964 --first find the total number of days in this pay period
965 
966 l_payroll_days := p_period_end_date - p_period_start_date + 1;
967 hr_utility.set_location('Days in pay period : '||l_payroll_days,30);
968 
969 --the non insured days in the difference of the pay period days and
970 --the number of days the assignment has been active
971 --if the assignment has not been active any day in the pay period
972 --then the non insured days is taken as 30 to make the proration
973 --factor 0
974 
975 IF l_days > 0 THEN
976    l_non_insured_days := l_payroll_days - l_days;
977 ELSE
978    l_non_insured_days := l_num_of_days_in_period;
979    p_err_message := 'Assignment was not active in this pay period, so '||
980                     'deduction amount is prorated as 0';
981    l_ret_value := 2;
982 END IF;
983 
984 hr_utility.set_location('Non insured days : '||l_non_insured_days,40);
985 
986 --now derive the proration factor, the days in a pay period are
987 --taken as 30 for this purpose, so we need to first find the days the
988 --person has been insured for in the period, ie (30 - days not insured)
989 --the proration factor is then this number divided by 30
990 
991 l_proration_factor := (l_num_of_days_in_period - l_non_insured_days) / l_num_of_days_in_period;
992 hr_utility.set_location('Proration factor is : '||l_proration_factor,50);
993 
994 --now multiply the deduction amount with the proration factor to
995 --find the prorated amount
996 hr_utility.set_location('Original deduction amount : '||p_dedn_amount,60);
997 
998 p_dedn_amount := p_dedn_amount * l_proration_factor;
999 
1000 hr_utility.set_location('Prorated deduction amount : '||p_dedn_amount,70);
1001 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,80);
1002 
1003 RETURN l_ret_value;
1004 
1005 EXCEPTION
1006 WHEN OTHERS THEN
1007    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,90);
1008    p_dedn_amount := 0;
1009    p_err_message := 'Error occured while prorating : '||SQLERRM;
1010    RETURN 1;
1011 
1012 END DO_PRORATION;
1013 
1014 --
1015 -- ----------------------------------------------------------------------------
1016 -- |--------------------------< GET_GENERAL_INFO >-----------------------------|
1017 -- ----------------------------------------------------------------------------
1018 --
1019 -- This function is used to derive the general information such as holiday allowance
1020 -- and end of year bonus percentage from the org extra information by traversing
1021 -- the org hierarchy
1022 
1023 FUNCTION GET_GENERAL_INFO
1024    (p_assignment_id     IN  NUMBER
1025    ,p_business_group_id IN  NUMBER
1026    ,p_date_earned       IN  DATE
1027    ,p_code              IN  NUMBER
1028    ,p_value             OUT NOCOPY NUMBER)
1029 
1030 RETURN NUMBER IS
1031 
1032 --
1033 -- Cursor to fetch the org id for the current assignment
1034 --
1035 CURSOR c_get_org_id IS
1036 SELECT organization_id
1037   FROM per_all_assignments_f
1038 WHERE  assignment_id = p_assignment_id
1039   AND  p_date_earned BETWEEN effective_start_date
1040   AND  effective_end_date;
1041 
1042 --
1043 -- Cursor to fetch the parent id for a given organization id
1044 -- for a particular hierarchy version id
1045 --
1046 CURSOR c_get_parent_id(c_org_id     IN NUMBER
1047                       ,c_version_id IN NUMBER) IS
1048 SELECT organization_id_parent
1049   FROM per_org_structure_elements
1050 WHERE  organization_id_child = c_org_id
1051   AND  org_structure_version_id = c_version_id
1052   AND  business_group_id = p_business_group_id;
1053 
1054 --
1055 -- Cursor to fetch the holiday allowance or eoy bonus
1056 -- percentage from the relevant segment based on the
1057 -- code passed in
1058 -- Code 0 => Holiday Allowance Percentage
1059 -- Code 1 => End Of Year Bonus Percentage
1060 --
1061 CURSOR c_get_general_info(c_org_id IN NUMBER) IS
1062 SELECT decode(p_code,0,org_information3,1,org_information4)
1063   FROM hr_organization_information
1064 WHERE  organization_id = c_org_id
1065   AND  org_information_context = 'PQP_NL_PGGM_INFO'
1066   AND  p_date_earned BETWEEN fnd_date.canonical_to_date(org_information1)
1067   AND  fnd_date.canonical_to_date(nvl(org_information2,fnd_date.date_to_canonical(hr_api.g_eot)))
1068   AND  decode(p_code,0,org_information3,1,org_information4) IS NOT NULL;
1069 
1070 l_proc_name  VARCHAR2(30) := 'GET_GENERAL_INFO';
1071 l_org_id     NUMBER;
1072 l_value      hr_organization_information.org_information1%TYPE;
1073 l_loop_again NUMBER := 1;
1074 l_version_id NUMBER;
1075 
1076 BEGIN
1077 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
1078 
1079 --initialise the percentage return value to 0
1080 p_value := 0;
1081 
1082 -- fetch the org id for the organization this assignment is attached to
1083 OPEN c_get_org_id;
1084 FETCH c_get_org_id INTO l_org_id;
1085 IF c_get_org_id%NOTFOUND THEN
1086    --org id for the assignment could not be found
1087    --return 1 and a value of 0
1088    CLOSE c_get_org_id;
1089    p_value := 0;
1090    RETURN 1;
1091 ELSE
1092    --org id was found
1093    CLOSE c_get_org_id;
1094    hr_utility.set_location('Org id for the ASG : '||l_org_id,20);
1095 
1096    -- now find the holiday allowance/eoy bonus percentage from the
1097    -- org extra information and by traversing the org hierarchy
1098    --check to see if the version id is already present for this business group
1099 
1100    IF NOT g_version_info.EXISTS(p_business_group_id) THEN
1101       --no cached value of the version id exists for this BG
1102       g_version_info(p_business_group_id).version_id
1103       := pqp_pension_functions.GET_VERSION_ID(p_business_group_id
1104                                              ,p_date_earned);
1105 
1106    END IF;
1107 
1108    l_version_id := g_version_info(p_business_group_id).version_id;
1109    hr_utility.set_location('Org Hierarchy version id : '||l_version_id,30);
1110 
1111    WHILE (l_loop_again = 1)
1112    LOOP
1113       OPEN c_get_general_info(l_org_id);
1114       FETCH c_get_general_info INTO l_value;
1115 
1116       IF c_get_general_info%FOUND THEN
1117          --holiday allowance /eoy bonus percentages have been found at this org
1118          hr_utility.set_location('Percentages found at org : '||l_org_id,40);
1119          CLOSE c_get_general_info;
1120 
1121          p_value := fnd_number.canonical_to_number(l_value);
1122 
1123          hr_utility.set_location('Percentage is : '||p_value,50);
1124          --we no longer need to continue up the hierarchy
1125          l_loop_again := 0;
1126 
1127       ELSE
1128          -- percentages not found at this org, now move up the hierarchy
1129          --find the parent org for this current org
1130          CLOSE c_get_general_info;
1131          OPEN c_get_parent_id(c_org_id     => l_org_id
1132                              ,c_version_id => l_version_id);
1133          FETCH c_get_parent_id INTO l_org_Id;
1134 
1135          IF c_get_parent_id%FOUND THEN
1136             --a parent org has been found,so we can loop again
1137             CLOSE c_get_parent_id;
1138 
1139          ELSE
1140             --no further parents exist,so exit the loop
1141             CLOSE c_get_parent_id;
1142             l_loop_again := 0;
1143 
1144             -- no value has been found , so set it to 0
1145             p_value := 0;
1146 
1147          END IF;
1148 
1149       END IF;
1150 
1151    END LOOP;
1152 
1153 END IF;
1154 
1155 hr_utility.set_location('Percentage value : '||p_value,55);
1156 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,60);
1157 
1158 RETURN 0;
1159 
1160 EXCEPTION
1161 WHEN OTHERS THEN
1162    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,70);
1163    p_value := 0;
1164    RETURN 1;
1165 
1166 END GET_GENERAL_INFO;
1167 
1168 
1169 -- ----------------------------------------------------------------------------
1170 -- |------------------------<GET_PENSION_SALARY >------------------------------|
1171 -- ----------------------------------------------------------------------------
1172 --
1173 FUNCTION GET_PENSION_SALARY
1174          (p_assignment_id        IN  NUMBER
1175          ,p_date_earned          IN  DATE
1176          ,p_business_group_id    IN  NUMBER
1177          ,p_payroll_id           IN  NUMBER
1178          ,p_period_start_date    IN  DATE
1179          ,p_period_end_date      IN  DATE
1180          ,p_scale_salary         IN  NUMBER
1181          ,p_scale_salary_h       IN  NUMBER
1182          ,p_scale_salary_e       IN  NUMBER
1183          ,p_ft_rec_payments      IN  NUMBER
1184          ,p_ft_rec_payments_h    IN  NUMBER
1185          ,p_ft_rec_payments_e    IN  NUMBER
1186          ,p_pt_rec_payments      IN  NUMBER
1187          ,p_pt_rec_payments_h    IN  NUMBER
1188          ,p_pt_rec_payments_e    IN  NUMBER
1189          ,p_salary_balance_value OUT NOCOPY NUMBER
1190          ,p_err_message          OUT NOCOPY VARCHAR2
1191          ,p_err_message1         OUT NOCOPY VARCHAR2
1192          ,p_err_message2         OUT NOCOPY VARCHAR2
1193          )
1194 RETURN NUMBER IS
1195 
1196 --
1197 -- Cursor to get the hire date of the person
1198 --
1199 CURSOR c_hire_dt_cur(c_asg_id IN NUMBER) IS
1200 SELECT max(date_start)
1201  FROM  per_all_assignments_f asg
1202       ,per_periods_of_service pps
1203 WHERE  pps.person_id     = asg.person_id
1204   AND  asg.assignment_id = c_asg_id
1205   AND  pps.business_group_id = p_business_group_id
1206   AND  date_start <= p_date_earned;
1207 
1208 --
1209 --Cursor to fetch the part time percentage from the
1210 --assignment standard conditions for a given effective date
1211 --
1212 CURSOR c_pt_cur (c_effective_date IN DATE) IS
1213 SELECT fnd_number.canonical_to_number(NVL(target.SEGMENT29,'100')) pt_perc
1214  FROM  per_assignments_f asg
1215       ,hr_soft_coding_keyflex target
1216 WHERE  asg.assignment_id = p_assignment_id
1217   AND  target.soft_coding_keyflex_id = asg.soft_coding_keyflex_id
1218   AND  trunc(c_effective_date) between asg.effective_start_date
1219   AND  asg.effective_end_date
1220   AND  target.enabled_flag = 'Y';
1221 
1222 --
1223 --Cursor to fetch the assignment start date
1224 --
1225 CURSOR c_get_asg_start IS
1226 SELECT min(effective_start_date)
1227   FROM per_all_assignments_f
1228 WHERE  assignment_id = p_assignment_id;
1229 
1230 --
1231 -- Cursor to get the defined balance id for a given balance and dimension
1232 --
1233 CURSOR csr_defined_bal (c_balance_name      IN VARCHAR2
1234                        ,c_dimension_name    IN VARCHAR2
1235                        ,c_business_group_id IN NUMBER) IS
1236 SELECT db.defined_balance_id
1237   FROM pay_balance_types pbt
1238       ,pay_defined_balances db
1239       ,pay_balance_dimensions bd
1240 WHERE  pbt.balance_name        = c_balance_name
1241   AND  pbt.balance_type_id     = db.balance_type_id
1242   AND  bd.balance_dimension_id = db.balance_dimension_id
1243   AND  bd.dimension_name       = c_dimension_name
1244   AND  (pbt.business_group_id  = c_business_group_id OR
1245         pbt.legislation_code   = 'NL')
1246   AND  (db.business_group_id   = pbt.business_group_id OR
1247         db.legislation_code    = 'NL');
1248 
1249 --
1250 -- Cursor to get the holiday allowance global
1251 --
1252 CURSOR c_global_cur(c_global_name IN VARCHAR2) IS
1253 SELECT fnd_number.canonical_to_number(global_value)
1254   FROM ff_globals_f
1255 WHERE  global_name = c_global_name
1256   AND  trunc (p_date_earned) BETWEEN effective_start_date
1257   AND  effective_end_date;
1258 
1259 --
1260 -- Cursor to get the collective agreement name as of 1 Jan/Hire Date
1261 --
1262 CURSOR c_cag_name (c_asg_id    IN NUMBER
1263                   ,c_eff_date  IN DATE) IS
1264 SELECT cola.name
1265   FROM per_collective_agreements cola
1266       ,per_all_assignments_f asg
1267 WHERE asg.assignment_id = c_asg_id
1268   AND asg.collective_agreement_id = cola.collective_agreement_id
1269   AND cola.status = 'A'
1270   AND c_eff_date BETWEEN asg.effective_start_date
1271   AND asg.effective_end_date
1272   AND c_eff_date BETWEEN cola.start_date
1273   AND NVL(cola.end_date,to_date('31/12/4712','DD/MM/YYYY'));
1274 
1275 --
1276 -- Cursor to get the number of pay periods per year.
1277 --
1278 CURSOR c_pp_cur IS
1279 SELECT pety.number_per_fiscal_year
1280   FROM pay_payrolls_f ppaf
1281       ,per_time_period_types pety
1282 WHERE  ppaf.payroll_id   = p_payroll_id
1283   AND  ppaf.period_type  = pety.period_type;
1284 
1285 --
1286 --Cursor to fetch the org id for the organization
1287 --attached to this assignment
1288 --
1289 CURSOR c_get_org_id(c_eff_date IN DATE) IS
1290 SELECT organization_id
1291   FROM per_all_assignments_f
1292 WHERE  assignment_id = p_assignment_id
1293   AND  c_eff_date BETWEEN effective_start_date
1294   AND  effective_end_date;
1295 
1296 --
1297 -- Cursor to get the value for EOY Bonus override percent
1298 --
1299 CURSOR c_eoy_per_or (c_asg_id         IN NUMBER
1300                     ,c_effective_date IN DATE) IS
1301 select min (fffunc.cn(decode(
1302     decode(INPUTV.uom,'M','N','N','N','I','N',null),'N',decode(INPUTV.hot_default_flag,'Y',nvl(EEV.screen_entry_value,
1303 nvl(LIV.default_value,INPUTV.default_value)),'N',EEV.screen_entry_value),null))) eoy_or
1304 FROM    pay_element_entry_values_f               EEV,
1305         pay_element_entries_f                    EE,
1306         pay_link_input_values_f                  LIV,
1307         pay_input_values_f                       INPUTV,
1308         pay_element_types_f                      pet
1309 WHERE   INPUTV.element_type_id                  = pet.element_type_id
1310 AND     INPUTV.name                             = 'End of Year Bonus Percentage'
1311 AND     c_effective_date BETWEEN INPUTV.effective_start_date
1312                              AND INPUTV.effective_end_date
1313 AND     INPUTV.element_type_id = pet.element_type_id
1314 AND     c_effective_date BETWEEN pet.effective_start_date
1315                              AND pet.effective_end_date
1316 AND     pet.element_name = 'PGGM Pensions General Information'
1317 AND     pet.legislation_code = 'NL'
1318 AND     LIV.input_value_id                     = INPUTV.input_value_id
1319 AND     c_effective_date BETWEEN LIV.effective_start_date
1320                  AND LIV.effective_end_date
1321 AND     EEV.input_value_id + 0                 = INPUTV.input_value_id
1322 AND     EEV.element_entry_id                   = EE.element_entry_id
1323 AND     EEV.effective_start_date               = EE.effective_start_date
1324 AND     EEV.effective_end_date                 = EE.effective_end_date
1325 AND     EE.element_link_id                     = LIV.element_link_id
1326 AND     EE.assignment_id                       = c_asg_id
1327 AND     c_effective_date BETWEEN EE.effective_start_date
1328                              AND EE.effective_end_date ;
1329 
1330 --
1331 -- Cursor to get the value for Holiday Allowance override percent
1332 --
1333 CURSOR c_ha_per_or (c_asg_id         IN NUMBER
1334                    ,c_effective_date IN DATE) IS
1335 select min (fffunc.cn(decode(
1336     decode(INPUTV.uom,'M','N','N','N','I','N',null),'N',decode(INPUTV.hot_default_flag,'Y',nvl(EEV.screen_entry_value,
1337 nvl(LIV.default_value,INPUTV.default_value)),'N',EEV.screen_entry_value),null))) ha_or
1338 FROM    pay_element_entry_values_f               EEV,
1339         pay_element_entries_f                    EE,
1340         pay_link_input_values_f                  LIV,
1341         pay_input_values_f                       INPUTV,
1342         pay_element_types_f                      pet
1343 WHERE   INPUTV.element_type_id                  = pet.element_type_id
1344 AND     INPUTV.name                             = 'Holiday Allowance Percentage'
1345 AND     c_effective_date BETWEEN INPUTV.effective_start_date
1346                              AND INPUTV.effective_end_date
1347 AND     INPUTV.element_type_id = pet.element_type_id
1348 AND     c_effective_date BETWEEN pet.effective_start_date
1349                              AND pet.effective_end_date
1350 AND     pet.element_name = 'PGGM Pensions General Information'
1351 AND     pet.legislation_code = 'NL'
1352 AND     LIV.input_value_id                     = INPUTV.input_value_id
1353 AND     c_effective_date BETWEEN LIV.effective_start_date
1354                  AND LIV.effective_end_date
1355 AND     EEV.input_value_id + 0                 = INPUTV.input_value_id
1356 AND     EEV.element_entry_id                   = EE.element_entry_id
1357 AND     EEV.effective_start_date               = EE.effective_start_date
1358 AND     EEV.effective_end_date                 = EE.effective_end_date
1359 AND     EE.element_link_id                     = LIV.element_link_id
1360 AND     EE.assignment_id                       = c_asg_id
1361 AND     c_effective_date BETWEEN EE.effective_start_date
1362                              AND EE.effective_end_date ;
1363 
1364 -- =============================================================================
1365 --Cursor to fetch Start date of a year
1366 -- =============================================================================
1367 CURSOR c_get_period_start_date ( c_year           IN VARCHAR2
1368                                 )
1369 IS
1370 SELECT NVL(min(PTP.start_date),to_date('0101'||c_year,'DDMMYYYY'))
1371  FROM per_time_periods PTP
1372  WHERE
1373       PTP.payroll_id = p_payroll_id
1374  AND (substr(PTP.period_name,4,4)=c_year
1375       OR substr(PTP.period_name,3,4)=c_year);
1376 
1377 l_loop_again          NUMBER;
1378 l_valid_pt            NUMBER;
1379 l_org_id              NUMBER;
1380 l_run_year            NUMBER;
1381 l_begin_of_year_date  DATE;
1382 l_end_of_last_year    DATE;
1383 l_effective_date      DATE;
1384 l_hire_date           DATE;
1385 l_asg_st_date         DATE;
1386 l_jan_hire_ptp        NUMBER;
1387 l_error_message       VARCHAR2(1000);
1388 l_defined_balance_id  NUMBER;
1389 l_scale_salary        NUMBER := nvl(p_scale_salary,0);
1390 l_scale_salary_h      NUMBER := nvl(p_scale_salary_h,0);
1391 l_scale_salary_e      NUMBER := nvl(p_scale_salary_e,0);
1392 l_ft_rec_paymnt       NUMBER := nvl(p_ft_rec_payments,0);
1393 l_ft_rec_paymnt_h     NUMBER := nvl(p_ft_rec_payments_h,0);
1394 l_ft_rec_paymnt_e     NUMBER := nvl(p_ft_rec_payments_e,0);
1395 l_pt_rec_paymnt       NUMBER := nvl(p_pt_rec_payments,0);
1396 l_pt_rec_paymnt_h     NUMBER := nvl(p_pt_rec_payments_h,0);
1397 l_pt_rec_paymnt_e     NUMBER := nvl(p_pt_rec_payments_e,0);
1398 l_holiday_allowance   NUMBER := 0;
1399 l_holiday_allow_per   NUMBER := 0;
1400 l_min_holiday_allow   NUMBER := 0;
1401 l_min_holiday_char    VARCHAR2(80);
1402 l_eoy_bonus           NUMBER := 0;
1403 l_eoy_bonus_per       NUMBER := 0;
1404 l_min_eoy_bonus       NUMBER := 0;
1405 l_min_eoy_bonus_char  VARCHAR2(80);
1406 l_cag_name            per_collective_agreements.name%TYPE;
1407 l_max_periods         NUMBER;
1408 l_max_ptp             NUMBER := 0;
1409 l_prev_max_ptp        NUMBER := 0;
1410 l_ret_val             NUMBER := 0;
1411 l_error_status        CHAR;
1412 l_message_flag        CHAR;
1413 UDT_CONTAINS_NO_DATA  EXCEPTION;
1414 l_proc_name           VARCHAR2(30) := 'GET_PENSION_SALARY';
1415 l_asg_eoy_bonus_per   NUMBER;
1416 l_asg_ha_per          NUMBER;
1417 l_ignore_eoy_cag      NUMBER;
1418 l_ignore_ha_cag       NUMBER;
1419 l_min_age_holiday_allow VARCHAR2(50);
1420 l_person_age          NUMBER;
1421 l_first_date_of_year  DATE;
1422 
1423 BEGIN
1424 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
1425 --hr_utility.trace_on(null,'SS');
1426 
1427 --initialise the error message params
1428 p_err_message         := ' ';
1429 p_err_message1        := ' ';
1430 p_err_message2        := ' ';
1431 
1432 --derive the year in which payroll is being run
1433 l_run_year := to_number(to_char(p_date_earned,'YYYY'));
1434 hr_utility.set_location('Payroll run year : '||l_run_year,20);
1435 
1436 OPEN c_get_period_start_date(l_run_year);
1437 FETCH c_get_period_start_date INTO l_first_date_of_year;
1438 CLOSE c_get_period_start_date;
1439 
1440 -- Get the first date of the run year
1441 l_begin_of_year_date := l_first_date_of_year;
1442 
1443 -- Get the latest start date of the assignment
1444 OPEN c_get_asg_start;
1445 FETCH c_get_asg_start INTO l_asg_st_date;
1446 
1447 IF c_get_asg_start%FOUND THEN
1448    CLOSE c_get_asg_start;
1449 ELSE
1450    CLOSE c_get_asg_start;
1451    p_err_message := 'Error: Unable to find the start date of the assignment';
1452    p_salary_balance_value := 0;
1453    RETURN 1;
1454 
1455 END IF;
1456 
1457 hr_utility.set_location('Asg start date : '||l_asg_st_date,30);
1458 
1459 -- Get the hire date
1460 OPEN c_hire_dt_cur (p_assignment_id);
1461 FETCH c_hire_dt_cur INTO l_hire_date;
1462 
1463 IF c_hire_dt_cur%FOUND THEN
1464    CLOSE c_hire_dt_cur;
1465    hr_utility.set_location('Hire date is : '||l_hire_date,40);
1466    -- The effective date is now the valid assignemnt
1467    --start date for the assignment
1468    l_effective_date := pqp_nl_abp_functions.get_valid_start_date
1469                        (p_assignment_id,
1470                         p_date_earned,
1471                         l_error_status,
1472                         l_error_message);
1473 
1474    --if an error occured while fetching the valid start date
1475    IF(l_error_status = trim(to_char(1,'9'))) THEN
1476       hr_utility.set_location('Error occured while fetching valid start date',50);
1477       fnd_message.set_name('PQP',l_error_message);
1478       p_err_message :='Error : '|| fnd_message.get();
1479       p_salary_balance_value :=0;
1480       RETURN 1;
1481    ELSE
1482       hr_utility.set_location('Valid start date fetched : '||l_effective_date,50);
1483    END IF;
1484 
1485 ELSE
1486    CLOSE c_hire_dt_cur;
1487    hr_utility.set_location('Hire date could not be found',60);
1488    p_err_message := 'Error: Unable to find the hire date for the person ';
1489    p_salary_balance_value :=0;
1490    RETURN 1;
1491 END IF;
1492 
1493 -- Get the maximum number of periods in a year.
1494 OPEN c_pp_cur;
1495 FETCH c_pp_cur INTO l_max_periods;
1496 
1497 IF c_pp_cur%NOTFOUND THEN
1498    p_err_message := 'Error: Unable to find the pay periods per year';
1499    p_salary_balance_value :=0;
1500    CLOSE c_pp_cur;
1501    RETURN 1;
1502 ELSE
1503    CLOSE c_pp_cur;
1504 END IF;
1505 
1506 hr_utility.set_location('Number of periods in a year : '||l_max_periods,70);
1507 hr_utility.set_location('Deriving the part time percentage',80);
1508 
1509 -- Calculate the ptp as of 1 jan or Hire Date
1510 OPEN c_pt_cur (l_effective_date);
1511 FETCH c_pt_cur INTO l_jan_hire_ptp;
1512 
1513 IF c_pt_cur%NOTFOUND THEN
1514    CLOSE c_pt_cur;
1515    hr_utility.set_location('No value found for part time percentage',90);
1516    p_err_message := 'Error: Unable to find the part time percentage.';
1517    p_err_message := p_err_message || 'Please enter a value as of 1 January or Hire Date';
1518    p_salary_balance_value :=0;
1519    RETURN 1;
1520 ELSE
1521     CLOSE c_pt_cur;
1522 END IF;
1523 
1524 IF l_jan_hire_ptp = 0 THEN
1525    l_jan_hire_ptp := 100;
1526 END IF;
1527 
1528 l_jan_hire_ptp := LEAST(l_jan_hire_ptp,125);
1529 
1530 hr_utility.set_location('Part Time Percentage used for salary : '||l_jan_hire_ptp,100);
1531 l_jan_hire_ptp := l_jan_hire_ptp/100;
1532 
1533 -- Divide all the part time balances by this value
1534 
1535 l_pt_rec_paymnt          := l_pt_rec_paymnt/l_jan_hire_ptp;
1536 l_pt_rec_paymnt_h        := l_pt_rec_paymnt_h/l_jan_hire_ptp;
1537 l_pt_rec_paymnt_e        := l_pt_rec_paymnt_e/l_jan_hire_ptp;
1538 
1539 --
1540 -- EOY Bonus Calculation
1541 -- This section will calculate the end of year bonus
1542 -- based on the EOY Bonus percentage specified at the
1543 -- org level. These will be derived from the following
1544 -- three balances.
1545 --
1546 -- PGGM Scale Salary For End Of Year Bonus
1547 -- PGGM Full Time Recurring Payments For End Of Year Bonus
1548 -- PGGM Part Time Recurring Payments For End Of Year Bonus
1549 --
1550 
1551 --
1552 -- Check to see if the EOY Bonus has been overridden
1553 -- at the assignment input value level. If it has been overridden
1554 -- and is not null. Use this value and do not derive from the org.
1555 -- Otherwise derive it from the org.
1556 -- It is imp to note that if the value is 0, then do not consider
1557 -- the min at the CAG level.
1558 --
1559 OPEN c_eoy_per_or(p_assignment_id
1560                  ,l_effective_date);
1561    FETCH c_eoy_per_or INTO l_asg_eoy_bonus_per;
1562    IF c_eoy_per_or%FOUND THEN
1563 
1564       l_eoy_bonus_per := l_asg_eoy_bonus_per;
1565       hr_utility.set_location('EOY Bonus Override at the I/V Level',105);
1566 
1567    END IF;
1568 
1569 CLOSE c_eoy_per_or;
1570 
1571 --
1572 -- Call the function to derive EOY Bonus
1573 -- percentage from the org level only if it is null at the asg i/v level.
1574 --
1575 IF NVL(l_eoy_bonus_per,-99) = -99 THEN
1576 
1577    l_ret_val := pqp_nl_pggm_functions.get_general_info
1578              (p_assignment_id         => p_assignment_id
1579              ,p_business_group_id     => p_business_group_id
1580              ,p_date_earned           => p_date_earned
1581              ,p_code                  => 1
1582              ,p_value                 => l_eoy_bonus_per
1583              );
1584 
1585    IF l_ret_val <> 0 THEN
1586       l_eoy_bonus_per := 0;
1587    END IF;
1588    hr_utility.set_location('EOY Bonus Calculated from the org',106);
1589 
1590 END IF;
1591 
1592 --
1593 -- Check if the final calculated value for EOY Bonus % is 0
1594 -- If it is zero then ignore the min EOY Bonus specified
1595 -- at the CAG ( Collective Agreement) level.
1596 --
1597    IF l_eoy_bonus_per = 0 THEN
1598       l_ignore_eoy_cag := 1;
1599    ELSE
1600       l_ignore_eoy_cag := 0;
1601    END IF;
1602 
1603 hr_utility.set_location('EOY Bonus % used for calculation is : '||l_eoy_bonus_per,110);
1604 
1605 --
1606 -- Calculate the EOY Bonus that needs to be included for
1607 -- PGGM Pension Salary calculations
1608 --
1609 l_eoy_bonus := (l_scale_salary_e
1610                +l_ft_rec_paymnt_e
1611                +l_pt_rec_paymnt_e
1612                )
1613                * l_eoy_bonus_per/100
1614                * l_max_periods;
1615 
1616 hr_utility.set_location('EOY Bonus amount calculated : '||l_eoy_bonus,120);
1617 
1618 --
1619 -- Holiday Allowance Calculation
1620 -- This section will calculate the holiday allowance
1621 -- based on the holiday allowance percentage specified
1622 -- at the org level. These will be derived from the
1623 -- following three balances.
1624 --
1625 -- PGGM Scale Salary For Holiday Allowance
1626 -- PGGM Full Time Recurring Payments For Holiday Allowance
1627 -- PGGM Part Time Recurring Payments For Holiday Allowance
1628 --
1629 
1630 --
1631 -- Check to see if the Holiday Allowance % has been overridden
1632 -- at the assignment input value level. If it has been overridden
1633 -- and is not null, Use this value and do not derive from the org.
1634 -- Otherwise derive it from the org.
1635 -- It is imp to note that if the value is 0, the do not consider
1636 -- the min at the cag level.
1637 --
1638 OPEN c_ha_per_or(p_assignment_id
1639                  ,l_effective_date);
1640    FETCH c_ha_per_or INTO l_asg_ha_per;
1641 
1642    IF c_ha_per_or%FOUND THEN
1643 
1644       l_holiday_allow_per := l_asg_ha_per;
1645       hr_utility.set_location('Holiday Allowance overridden at the iv level ',125);
1646 
1647    END IF;
1648 
1649 CLOSE c_ha_per_or;
1650 --
1651 -- Call the function to derive Holiday allowance
1652 -- percentage from the org level only if it is null at the asg i/v level.
1653 --
1654 IF NVL(l_holiday_allow_per,-99) = -99 THEN
1655 
1656    l_ret_val := pqp_nl_pggm_functions.get_general_info
1657              (p_assignment_id         => p_assignment_id
1658              ,p_business_group_id     => p_business_group_id
1659              ,p_date_earned           => p_date_earned
1660              ,p_code                  => 0
1661              ,p_value                 => l_holiday_allow_per
1662              );
1663 
1664    IF l_ret_val <> 0 THEN
1665       l_holiday_allow_per := 0;
1666    END IF;
1667    hr_utility.set_location('Holiday Allowance Calculated from the org',125);
1668 
1669 END IF;
1670 
1671 hr_utility.set_location('Holiday allow % used for calculation is : '
1672                         ||l_holiday_allow_per,130);
1673 
1674 --
1675 -- Check if the final calculated value for HA % is 0
1676 -- If it is zero then ignore the min HA specified
1677 -- at the CAG (Collective Agreement) level.
1678 --
1679 IF l_holiday_allow_per = 0 THEN
1680    l_ignore_ha_cag := 1;
1681 ELSE
1682    l_ignore_ha_cag := 0;
1683 END IF;
1684 
1685 l_holiday_allowance   := (l_scale_salary_h
1686                          +l_ft_rec_paymnt_h
1687                          +l_pt_rec_paymnt_h
1688                          )
1689                          * l_holiday_allow_per/100
1690                          * l_max_periods;
1691 
1692 hr_utility.set_location('Calculated holiday allowance : '||l_holiday_allowance,140);
1693 
1694 -- Find the minimum values for EOY Bonus and Holiday
1695 -- allowance that may have been defined for this
1696 -- assignment. The value of holiday allowance and EOY
1697 -- bonus used in pension salary calculation should
1698 -- not be lesser than this defined minimum
1699 
1700 -- First get the CAG Name
1701 OPEN  c_cag_name (c_asg_id    => p_assignment_id
1702                  ,c_eff_date  => l_effective_date) ;
1703 
1704 FETCH c_cag_name INTO l_cag_name;
1705 
1706 IF c_cag_name%FOUND THEN
1707 
1708   -- We found a CAG at the asg level . Now get the Min End Of
1709   -- Year Bonus for this CAG from the UDT.
1710   hr_utility.set_location('CAG attached to the asg : '||l_cag_name,150);
1711   BEGIN
1712      l_min_eoy_bonus_char := hruserdt.get_table_value
1713                              (
1714                               p_bus_group_id    => p_business_group_id
1715                              ,p_table_name      => 'PQP_NL_MIN_END_OF_YEAR_BONUS'
1716                              ,p_col_name        => 'PGGM Minimum End Of Year Bonus'
1717                              ,p_row_value       => l_cag_name
1718                              ,p_effective_date  => l_effective_date
1719                              );
1720 
1721      --
1722      -- Calculate the min EOY bonus only if the override percentage is not 0
1723      --
1724      IF NVL(l_ignore_eoy_cag,0) = 0 THEN
1725         l_min_eoy_bonus   := fnd_number.canonical_to_number(NVL(l_min_eoy_bonus_char,'0'));
1726      ELSIF NVL(l_ignore_eoy_cag,0) = 1 THEN
1727         l_min_eoy_bonus := 0;
1728      END IF;
1729 
1730   EXCEPTION
1731   WHEN NO_DATA_FOUND THEN
1732      hr_utility.set_location('Exception occured :NO_DATA_FOUND ',160);
1733      l_min_eoy_bonus := 0;
1734   END;
1735 
1736   -- We found a CAG at the asg level . Now get the Min holiday
1737   -- allowance for this CAG from the UDT.
1738   BEGIN
1739      l_min_age_holiday_allow:= hruserdt.get_table_value
1740                          (
1741                           p_bus_group_id    => p_business_group_id
1742                          ,p_table_name      => 'PQP_NL_MIN_HOLIDAY_ALLOWANCE'
1743                          ,p_col_name        => 'PGGM Min Age for Holiday Allowance'
1744                          ,p_row_value       => l_cag_name
1745                          ,p_effective_date  => l_effective_date
1746                          );
1747      --Get the age of the person
1748      hr_utility.set_location('l_begin_of_year_date'||l_begin_of_year_date,161);
1749      l_person_age := Get_age(p_assignment_id,l_effective_date,l_begin_of_year_date);
1750      hr_utility.set_location('l_person_age'||l_person_age,162);
1751      hr_utility.set_location('l_min_age_holiday_allow'||l_min_age_holiday_allow,163);
1752 
1753      --Comapre it with min age defined at CAG level
1754      IF (l_person_age < to_number(l_min_age_holiday_allow) ) THEN
1755       --Person is not eligible for Min holiday allowance
1756         l_min_holiday_allow :=0;
1757        p_err_message2 :=p_err_message2|| 'Min. holiday allowance is set to 0 as'
1758                       ||'person age is less than min age defined at collective agreement ';
1759       l_ret_val := 2;
1760      ELSE
1761        l_min_holiday_char := hruserdt.get_table_value
1762                          (
1763                           p_bus_group_id    => p_business_group_id
1764                          ,p_table_name      => 'PQP_NL_MIN_HOLIDAY_ALLOWANCE'
1765                          ,p_col_name        => 'PGGM Minimum Holiday Allowance'
1766                          ,p_row_value       => l_cag_name
1767                          ,p_effective_date  => l_effective_date
1768                          );
1769        hr_utility.set_location('l_min_holiday_char'||l_min_holiday_char,165);
1770            --
1771            -- Calculate the min HA only if the override percentage is not 0
1772            --
1773         IF NVL(l_ignore_ha_cag,0) = 0 THEN
1774            l_min_holiday_allow := fnd_number.canonical_to_number(NVL(l_min_holiday_char,'0'));
1775         ELSIF NVL(l_ignore_ha_cag,0) = 1 THEN
1776            l_min_holiday_allow := 0;
1777         END IF;
1778      END IF; -- End of person age check
1779 
1780   EXCEPTION
1781   WHEN NO_DATA_FOUND THEN
1782      hr_utility.set_location('Exception occured :NO_DATA_FOUND ',170);
1783      l_min_holiday_allow := 0;
1784   END;
1785 
1786 --no collective agreement defined for this assignment
1787 ELSE
1788   -- set Min EOY bonus and Min Holiday allowance to 0 .
1789   hr_utility.set_location('No CAG attached',160);
1790   l_min_eoy_bonus     := 0;
1791   l_min_holiday_allow := 0;
1792 END IF;
1793 
1794 CLOSE c_cag_name;
1795 
1796 hr_utility.set_location('Min. EOY bonus : '||l_min_eoy_bonus,170);
1797 hr_utility.set_location('Min. Holiday allowance : '||l_min_holiday_allow,180);
1798 
1799 --now compare the calculated eoy bonus and the min. eoy bonus
1800 IF l_eoy_bonus < l_min_eoy_bonus THEN
1801    p_err_message1 :=p_err_message1|| 'Min. end of year bonus for the collective agreement'
1802                       ||' was used for Pension Salary calculation ';
1803    l_ret_val := 2;
1804 END IF;
1805 
1806 l_eoy_bonus    := GREATEST(l_eoy_bonus,nvl(l_min_eoy_bonus,0));
1807 
1808 hr_utility.set_location('Final EOY Bonus value : '||l_eoy_bonus,190);
1809 
1810 --now compare the calculated holiday allowance and the min. holiday allowance
1811 IF l_holiday_allowance < l_min_holiday_allow THEN
1812    p_err_message2 :=p_err_message2|| 'Min. holiday allowance for the collective agreement'
1813                       ||' was used for Pension Salary calculation ';
1814    l_ret_val := 2;
1815 END IF;
1816 
1817 l_holiday_allowance    := GREATEST(l_holiday_allowance,nvl(l_min_holiday_allow,0));
1818 
1819 hr_utility.set_location('Final Holiday Allowance value : '||l_holiday_allowance,200);
1820 
1821 p_salary_balance_value := (l_scale_salary
1822                           +l_ft_rec_paymnt
1823                           +l_pt_rec_paymnt
1824                           ) * l_max_periods
1825                           +l_holiday_allowance
1826                           +l_eoy_bonus;
1827 
1828 p_salary_balance_value := CEIL(p_salary_balance_value);
1829 
1830 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,210);
1831 --hr_utility.trace_off;
1832 RETURN l_ret_val;
1833 
1834 EXCEPTION
1835 WHEN OTHERS THEN
1836    p_salary_balance_value := 0;
1837    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,220);
1838    p_err_message := 'Error occured while deriving the PGGM Pension Salary'
1839                       ||' value : '||SQLERRM;
1840 RETURN 1;
1841 
1842 END GET_PENSION_SALARY;
1843 
1844 -- ----------------------------------------------------------------------------
1845 -- |----------------------<GET_PART_TIME_PERCENTAGE >--------------------------|
1846 -- ----------------------------------------------------------------------------
1847 --
1848 FUNCTION GET_PART_TIME_PERCENTAGE
1849          (p_assignment_id        IN  NUMBER
1850 	 ,p_payroll_action_id    IN  NUMBER
1851 	 ,p_date_earned          IN  DATE
1852          ,p_business_group_id    IN  NUMBER
1853          ,p_period_start_date    IN  DATE
1854          ,p_period_end_date      IN  DATE
1855          ,p_override_value       IN  NUMBER
1856          ,p_parental_leave       IN  VARCHAR2
1857          ,p_extra_hours          IN  NUMBER
1858          ,p_hours_worked         OUT NOCOPY NUMBER
1859          ,p_total_hours          OUT NOCOPY NUMBER
1860          ,p_part_time_percentage OUT NOCOPY NUMBER
1861          ,p_err_message          OUT NOCOPY VARCHAR2
1862          )
1863 RETURN NUMBER IS
1864 
1865 --
1866 -- Cursor to fetch the earliest start date of the assignment
1867 -- for this period
1868 --
1869 CURSOR c_get_st_date IS
1870 SELECT min(effective_start_date)
1871   FROM per_all_assignments_f
1872 WHERE  assignment_id = p_assignment_id
1873    AND effective_end_date >= p_period_start_date;
1874 --
1875 --Cursor to fetch the part time percentage from the
1876 --assignment standard conditions for a given effective date
1877 --
1878 CURSOR c_get_ptp(c_effective_date IN DATE) IS
1879 SELECT fnd_number.canonical_to_number(NVL(target.SEGMENT29,'0')) pt_perc
1880  FROM  per_assignments_f asg
1881       ,hr_soft_coding_keyflex target
1882 WHERE  asg.assignment_id = p_assignment_id
1883   AND  target.soft_coding_keyflex_id = asg.soft_coding_keyflex_id
1884   AND  c_effective_date between asg.effective_start_date
1885   AND  asg.effective_end_date
1886   AND  target.enabled_flag = 'Y';
1887 
1888 --
1889 -- cursor to fetch the date tracked assignment rows
1890 -- for all changes in the pay period
1891 -- the calendar day average value of all these changes
1892 -- is taken as the average part time percentage of this period
1893 --
1894 CURSOR c_get_asg_rows IS
1895 SELECT fnd_number.canonical_to_number(NVL(target.segment28,'0')) hours_worked
1896       ,nvl(asg.normal_hours,0) total_hours
1897       ,nvl(asg.frequency,'W') freq
1898       ,asg.effective_start_date start_date
1899       ,asg.effective_end_date end_date
1900   FROM per_assignments_f asg
1901       ,per_assignment_status_types ast
1902       ,hr_soft_coding_keyflex target
1903 WHERE  asg.assignment_id = p_assignment_id
1904    AND asg.assignment_status_type_id = ast.assignment_status_type_id
1905    AND ast.per_system_status = 'ACTIVE_ASSIGN'
1906    AND target.soft_coding_keyflex_id = asg.soft_coding_keyflex_id
1907    AND asg.effective_start_date <= p_period_end_date
1908    AND asg.effective_end_date >= p_period_start_date;
1909 
1910 
1911 --
1912 --Cursor to fetch period type of payroll attached to assignment
1913 --
1914 CURSOR c_get_period_type(c_payroll_action_id IN NUMBER)
1915 IS
1916 SELECT TPERIOD.period_type
1917  FROM  pay_payroll_actions     PACTION
1918       ,per_time_periods        TPERIOD
1919  WHERE PACTION.payroll_action_id   = c_payroll_action_id
1920   AND TPERIOD.payroll_id          = PACTION.payroll_id
1921   AND (PACTION.date_earned   between TPERIOD.start_date
1922                                 and TPERIOD.end_date);
1923 
1924 c_asg_row c_get_asg_rows%ROWTYPE;
1925 
1926 l_proc_name    VARCHAR2(30) := 'GET_PART_TIME_PERCENTAGE';
1927 l_eff_date     DATE;
1928 l_ptp          NUMBER := 100;
1929 l_emp_kind     NUMBER := 1;
1930 l_start_date   DATE;
1931 l_end_date     DATE;
1932 l_days         NUMBER;
1933 l_pay_days     NUMBER;
1934 l_tot_days     NUMBER := 0;
1935 hours_worked   NUMBER := 0;
1936 total_hours    NUMBER := 0;
1937 l_hours_worked NUMBER;
1938 l_total_hours  NUMBER;
1939 l_ret_value    NUMBER := 0;
1940 l_num_periods  NUMBER :=12;
1941 l_period_type  VARCHAR2(150):='Calendar Month';
1942 l_num_of_days_in_period NUMBER:=30;
1943 
1944 BEGIN
1945 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
1946 
1947 OPEN c_get_period_type(p_payroll_action_id);
1948 FETCH c_get_period_type INTO l_period_type;
1949 CLOSE c_get_period_type;
1950  IF l_period_type='Calendar Month' THEN
1951     l_num_of_days_in_period:= 30;
1952  ELSE  IF l_period_type = 'Lunar Month' THEN
1953          l_num_of_days_in_period:=28;
1954        ELSE  IF l_period_type = 'Week' THEN
1955                 l_num_of_days_in_period:=7;
1956              ELSE IF l_period_type = 'Quarter' THEN
1957                     l_num_of_days_in_period:=90;
1958                   END IF;
1959              END IF;
1960        END IF;
1961  END IF;
1962 
1963 p_err_message := '';
1964 --
1965 -- check if the person is a full timer or part timer
1966 -- if the person is a part timer, then the final part time
1967 -- percentage cannot exceed 100% and it cannot exceed 125%
1968 -- for a full timer
1969 -- If the part time percentage derived from the standard
1970 -- conditions is < 100 then the person is a part time employee
1971 -- if the value is equal to or exceeds 100 then this is a full
1972 -- timer
1973 --
1974 
1975 -- fetch the part time percentage on the period start date
1976 -- first fetch the date on which this part time percentage needs
1977 -- to be derived on
1978 
1979 OPEN c_get_st_date;
1980 FETCH c_get_st_date INTO l_eff_date;
1981 CLOSE c_get_st_date;
1982 
1983 hr_utility.set_location('Start date of asg for this period : '||l_eff_date,20);
1984 
1985 -- the date on which ptp needs to be derived is the greater of the asg start date
1986 -- and the period start date
1987 
1988 l_eff_date := GREATEST(l_eff_date,p_period_start_date);
1989 
1990 hr_utility.set_location('date on which check is performed : '||l_eff_date,30);
1991 
1992 --Get number of payroll periods in a year
1993 OPEN c_get_num_periods_per_year(p_payroll_action_id);
1994 FETCH c_get_num_periods_per_year INTO l_num_periods;
1995 CLOSE c_get_num_periods_per_year;
1996 
1997 
1998 --now derive the ptp from standard conditions on this eff date to check
1999 -- for part/full timers
2000 
2001 OPEN c_get_ptp(l_eff_date);
2002 FETCH c_get_ptp INTO l_ptp;
2003 CLOSE c_get_ptp;
2004 
2005 hr_utility.set_location('PTP on the start date : '||l_ptp,40);
2006 
2007 IF l_ptp < 100 THEN
2008    -- the employee is a part time employee
2009    l_emp_kind := 0;
2010 ELSE
2011    -- the employee is full time
2012    l_emp_kind := 1;
2013 END IF;
2014 
2015 hr_utility.set_location('Employee Kind : '||l_emp_kind,50);
2016 
2017 --calculate the number of days in this pay period
2018 l_pay_days := TRUNC(p_period_end_date) - TRUNC(p_period_start_date) + 1;
2019 
2020 --now loop through the asg changes to find the total average hours worked
2021 FOR c_asg_row IN c_get_asg_rows
2022 LOOP
2023    --if the start date is before period start,use period start
2024    IF c_asg_row.start_date < p_period_start_date THEN
2025       l_start_date := p_period_start_date;
2026    ELSE
2027       l_start_date := c_asg_row.start_date;
2028    END IF;
2029 
2030    -- if end date is after period end,use period end
2031    IF c_asg_row.end_date > p_period_end_date THEN
2032       l_end_date := p_period_end_date;
2033    ELSE
2034       l_end_date := c_asg_row.end_date;
2035    END IF;
2036 
2037    hr_utility.set_location('Start Date : '||l_start_date,60);
2038    hr_utility.set_location('End Date : '||l_end_date,70);
2039    hr_utility.set_location('Hours worked : '||c_asg_row.hours_worked,80);
2040    hr_utility.set_location('Total Hours : '||c_asg_row.total_hours,90);
2041    hr_utility.set_location('Frequency : '||c_asg_row.freq,100);
2042 
2043    --calculate the hours per week based on the frequency
2044    IF c_asg_row.freq = 'D' THEN
2045       l_hours_worked := c_asg_row.hours_worked * 5;
2046       l_total_hours  := c_asg_row.total_hours * 5;
2047    ELSIF c_asg_row.freq = 'M' THEN
2048       l_hours_worked := c_asg_row.hours_worked * l_num_periods/52;
2049       l_total_hours  := c_asg_row.total_hours * l_num_periods/52;
2050    ELSIF c_asg_row.freq = 'Y' THEN
2051       l_hours_worked := c_asg_row.hours_worked/52;
2052       l_total_hours  := c_asg_row.total_hours/52;
2053    ELSE
2054       l_hours_worked := c_asg_row.hours_worked;
2055       l_total_hours  := c_asg_row.total_hours;
2056    END IF;
2057 
2058    --calculate the days for this asg row
2059    l_days := TRUNC(l_end_date) - TRUNC(l_start_date) + 1;
2060    l_tot_days := l_tot_days + l_days;
2061 
2062     --the total days should always be l_num_of_days_in_period,
2063     --adjust the last l_days so that it adds up to l_num_of_days_in_period
2064    IF l_tot_days = l_pay_days THEN
2065       --the number of days is equal to the number of days in the
2066       --pay period,but this has to always be l_num_of_days_in_period
2067       l_days := l_days + (l_num_of_days_in_period - l_tot_days);
2068    END IF;
2069 
2070    hr_utility.set_location('l_days : '||l_days,110);
2071 
2072    hours_worked := hours_worked +
2073                    l_hours_worked * l_days/l_num_of_days_in_period;
2074 
2075    total_hours  := total_hours +
2076                    l_total_hours * l_days/l_num_of_days_in_period;
2077 END LOOP;
2078 
2079 --hours worked and total hours for the month is the average calculated
2080 -- above * 52/12
2081 hours_worked := hours_worked * 52/l_num_periods;
2082 total_hours := total_hours * 52/l_num_periods;
2083 
2084 hr_utility.set_location('Avg. Hours worked : '||hours_worked,120);
2085 hr_utility.set_location('Avg. Total Hours : '||total_hours,130);
2086 
2087 --
2088 -- check if an override has been entered, if so then the part time
2089 -- percentage is the same as the value entered in the override
2090 -- however for the case where the person is on parental leave,
2091 -- the override part time percentage needs to be added with
2092 -- the extra hours entered
2093 --
2094 
2095 IF p_override_value <> -99 THEN
2096    --override has been entered
2097    l_ptp := p_override_value;
2098    hr_utility.set_location('Override exists : '||l_ptp,140);
2099    --check if the employee is also on parental leave
2100    IF p_parental_leave = 'Y' THEN
2101       --we also need to add any increase in ptp due to extra hours
2102       hr_utility.set_location('parental leave exists',150);
2103       IF total_hours > 0 THEN
2104          --only if the employee is part time,extra hours can be considered
2105          IF l_emp_kind = 0 THEN
2106             l_ptp := l_ptp + (nvl(p_extra_hours,0)/total_hours) * 100;
2107          END IF;
2108       END IF;
2109    END IF;
2110 
2111 ELSE
2112    --no override exists
2113    hr_utility.set_location('No override exists',160);
2114    --final ptp value is calculated value + increase due to extra hours
2115    IF total_hours > 0 THEN
2116       --only if emp is part time, then consider extra hours
2117       IF l_emp_kind = 0 THEN
2118          l_ptp := ((hours_worked + nvl(p_extra_hours,0))/total_hours) * 100;
2119       ELSE
2120          l_ptp := (hours_worked/total_hours) * 100;
2121       END IF;
2122    ELSE
2123       l_ptp := 0;
2124    END IF;
2125 END IF;
2126 
2127 l_ptp := nvl(l_ptp,0);
2128 
2129 hr_utility.set_location('Calculated PTP : '||l_ptp,170);
2130 /*
2131 PGGM 2006 Legislative change
2132 No max limit for Part time percentage
2133 --
2134 -- Restrict the final value of PTP to 125
2135 --
2136 IF l_ptp > 125 THEN
2137    p_err_message := 'Part time percentage has been restricted to 125%';
2138    l_ret_value := 2;
2139 END IF;
2140 
2141 l_ptp := LEAST(l_ptp,125);
2142 */
2143 
2144 hr_utility.set_location('Final ptp value : '||l_ptp,180);
2145 
2146 p_part_time_percentage := round(nvl(l_ptp,0),2);
2147 p_hours_worked := round(nvl(hours_worked,0),2);
2148 p_total_hours := round(nvl(total_hours,0),2);
2149 
2150 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,190);
2151 
2152 RETURN l_ret_value;
2153 
2154 EXCEPTION
2155 WHEN OTHERS THEN
2156    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,200);
2157    p_part_time_percentage := 0;
2158    p_hours_worked := 0;
2159    p_total_hours := 0;
2160    p_err_message := 'Error occured while deriving part time percentage : '||SQLERRM;
2161    RETURN 1;
2162 
2163 END GET_PART_TIME_PERCENTAGE;
2164 
2165 -- ----------------------------------------------------------------------------
2166 -- |----------------------<GET_INCI_WKR_CODE >--------------------------------|
2167 -- ----------------------------------------------------------------------------
2168 --
2169 FUNCTION GET_INCI_WKR_CODE
2170          (p_assignment_id        IN  NUMBER
2171           ,p_business_group_id    IN  NUMBER
2172 	  ,p_date_earned          IN  DATE
2173 	  ,p_result_value         OUT NOCOPY VARCHAR2
2174           ,p_err_message          OUT NOCOPY VARCHAR2
2175          )
2176 RETURN NUMBER IS
2177 CURSOR csr_get_inci_wkr_code(c_assignment_id NUMBER,c_date_earned DATE) IS
2178 SELECT scl.SEGMENT1
2179   FROM per_all_assignments_f asg
2180       ,hr_soft_coding_keyflex scl
2181 WHERE asg.assignment_id = c_assignment_id
2182   AND c_date_earned BETWEEN asg.effective_start_date
2183   AND asg.effective_end_date
2184   AND asg.soft_coding_keyflex_id = scl.soft_coding_keyflex_id;
2185 
2186 l_proc_name    VARCHAR2(30) := 'GET_INCI_WKR_CODE';
2187 l_inci_code VARCHAR2(1):='N';
2188 l_ret_value NUMBER:=0;
2189 BEGIN
2190 hr_utility.set_location('Entering : '||g_pkg_name||l_proc_name,10);
2191 
2192 OPEN csr_get_inci_wkr_code(p_assignment_id,p_date_earned);
2193 FETCH csr_get_inci_wkr_code INTO l_inci_code;
2194 
2195 IF csr_get_inci_wkr_code%FOUND THEN
2196 p_result_value:=l_inci_code;
2197 ELSE
2198 p_result_value:='N';
2199 END IF;
2200 CLOSE csr_get_inci_wkr_code;
2201 
2202 hr_utility.set_location('Leaving : '||g_pkg_name||l_proc_name,190);
2203 RETURN l_ret_value;
2204 EXCEPTION
2205 WHEN OTHERS THEN
2206    hr_utility.set_location('Exception occured in : '||g_pkg_name||l_proc_name,200);
2207    p_err_message := 'Error occured while deriving incidental worker code : '||SQLERRM;
2208    RETURN 1;
2209 END GET_INCI_WKR_CODE;
2210 
2211 END PQP_NL_PGGM_FUNCTIONS;