1 package body hr_payrolls as
2 /* $Header: pypyroll.pkb 120.1.12010000.2 2009/09/03 04:34:49 sivanara ship $ */
3 --
4 -- Package constants, denoting the base period types.
5 --
6 WEEKLY CONSTANT varchar2(1) := 'W';
7 MONTHLY CONSTANT varchar2(1) := 'M';
8 SEMIMONTHLY CONSTANT varchar2(1) := 'S';
9 TEN_DAYS CONSTANT varchar2(1) := 'T'; -- Bug 5935976
10 --
11 -- Disable/enable the period name display fetch inline with the view
12 g_enable_period_name_fetch BOOLEAN := TRUE;
13 --
14 --
15 -- Warning variables used by the form
16 g_weeks_reset_warn BOOLEAN := FALSE;
17 g_end_date_changed_warn BOOLEAN := FALSE;
18 g_no_of_weeks_reset NUMBER := 0;
19 g_reset_period_start_date per_time_periods.start_date%type;
20 g_reset_period_end_date per_time_periods.end_date%type;
21 g_reset_period_name per_time_periods.period_name%type;
22 g_new_end_date per_time_periods.end_date%type;
23 g_constant_end_date BOOLEAN := FALSE;
24 --
25 -- This procedure does not currently use PER_TIME_PERIOD_RULES, since that
26 -- table is subject to some change.
27 --
28 procedure get_period_details (p_proc_period_type in varchar2,
29 p_base_period_type out nocopy varchar2,
30 p_multiple out nocopy number) is
31 --
32 proc_name CONSTANT varchar2(50) := 'hr_payrolls.get_period_details';
33 --
34 no_periods per_time_period_types.number_per_fiscal_year%type;
35 --
36 begin
37 hr_utility.set_location(proc_name, 1);
38 select tp.number_per_fiscal_year
39 into no_periods
40 from per_time_period_types tp
41 where tp.period_type = p_proc_period_type;
42 --
43 -- Use the number of periods in a fiscal year to deduce the base
44 -- period and multiple.
45 if no_periods = 1 then -- Yearly
46 p_base_period_type := MONTHLY;
47 p_multiple := 12;
48 elsif no_periods = 2 then -- Semi yearly
49 p_base_period_type := MONTHLY;
50 p_multiple := 6;
51 elsif no_periods = 4 then -- Quarterly
52 p_base_period_type := MONTHLY;
53 p_multiple := 3;
54 elsif no_periods = 6 then -- Bi monthly
55 p_base_period_type := MONTHLY;
56 p_multiple := 2;
57 elsif no_periods = 12 then -- Monthly
58 p_base_period_type := MONTHLY;
59 p_multiple := 1;
60 elsif no_periods = 13 then -- Lunar monthly
61 p_base_period_type := WEEKLY;
62 p_multiple := 4;
63 elsif no_periods = 24 then -- Semi monthly
64 p_base_period_type := SEMIMONTHLY;
65 p_multiple := 1; -- Not used for semi-monthly
66 elsif no_periods = 26 then -- Fortnightly
67 p_base_period_type := WEEKLY;
68 p_multiple := 2;
69 elsif no_periods = 36 then -- 10 Day --Bug 5935976
70 p_base_period_type := TEN_DAYS;
71 p_multiple := 1;
72 elsif no_periods = 52 then -- Weekly
73 p_base_period_type := WEEKLY;
74 p_multiple := 1;
75 else
76 -- Unknown period type.
77 hr_utility.set_message(801, 'PAY_6601_PAYROLL_INV_PERIOD_TP');
78 hr_utility.raise_error;
79 end if;
80 --
81 end get_period_details;
82 --
83 -- Locally defined function that, given the end-date of a semi-month
84 -- period and the first period's end-date (p_fpe_date) returns
85 -- the end date of the following semi-monthly period.
86 --
87 function next_semi_month(p_semi_month_date in date, p_fpe_date in date)
88 return date is
89 day_of_month varchar2(2);
90 last_of_month date;
91 temp_day varchar2(2);
92 func_name CONSTANT varchar2(50) := 'hr_payrolls.next_semi_month';
93 begin
94 hr_utility.set_location(func_name, 1);
95 day_of_month := substr(to_char(p_fpe_date, 'DD-MON-YYYY'), 1, 2);
96 if (day_of_month = '15') OR (last_day(p_fpe_date) = p_fpe_date) then
97 -- The first period's end-date is either the 15th or the end-of-month
98 if last_day(p_semi_month_date) = p_semi_month_date then
99 -- End of month: add 15 days
100 return(p_semi_month_date + 15);
101 else
102 -- 15th of month: return last day
103 return(last_day(p_semi_month_date));
104 end if;
105 else
106 -- The first period's end-date is neither the 15th nor the end-of-month
107 -- temp_day = smaller of the 2 day numbers used to calc period end-dates
108 temp_day := day_of_month ;
109 if temp_day > '15' then
110 temp_day := substr(to_char(p_fpe_date - 15, 'DD-MON-YYYY'), 1, 2);
111 end if ;
112 --
113 day_of_month := substr(to_char(p_semi_month_date, 'DD-MON-YYYY'), 1, 2);
114 if day_of_month between '01' AND '15' then
115 if last_day(p_semi_month_date+15) = last_day(p_semi_month_date) then
116 return(p_semi_month_date + 15);
117 else
118 -- for p_semi_month_date = Feb 14th, for example
119 return(last_day(p_semi_month_date));
120 end if;
121 else -- if on the 16th or later
122 return(to_date( (temp_day ||
123 substr(to_char(add_months(p_semi_month_date,1),'DD-MON-YYYY'),3)
124 ), 'DD-MON-YYYY'));
125 end if ;
126 end if ;
127 end next_semi_month;
128 --
129 -- Locally defined function that, given the end-date of a semi-month
130 -- period and the first period's end-date (p_fpe_date) returns
131 -- the end date of the previous semi-monthly period.
132 --
133 function prev_semi_month(p_semi_month_date in date, p_fpe_date in date)
134 return date is
135 day_of_month varchar2(2);
136 last_of_month date;
137 temp_date date;
138 temp_day varchar2(2);
139 func_name CONSTANT varchar2(50) := 'hr_payrolls.prev_semi_month';
140 begin
141 -- Get the day of the current month.
142 hr_utility.set_location(func_name, 1);
143 day_of_month := substr(to_char(p_fpe_date, 'DD-MON-YYYY'), 1, 2);
144 if (day_of_month = '15') OR (last_day(p_fpe_date) = p_fpe_date) then
145 -- The first period's end-date is either the 15th or the end-of-month
146 if last_day(p_semi_month_date) = p_semi_month_date then
147 -- End of month: return 15th of current month
148 return(add_months(p_semi_month_date,-1) + 15);
149 else
150 -- 15th of month: return last day of previous month
151 return(last_day(add_months(p_semi_month_date,-1)));
152 end if;
153 else
154 -- The first period's end-date is neither the 15th nor the end-of-month
155 -- temp_day = smaller of the 2 day numbers used to calc period end-dates
156 temp_day := day_of_month ;
157 if temp_day > '15' then
158 temp_day := substr(to_char(p_fpe_date - 15, 'DD-MON-YYYY'), 1, 2);
159 end if ;
160 --
161 day_of_month := substr(to_char(p_semi_month_date, 'DD-MON-YYYY'), 1, 2);
162 if day_of_month between '01' AND '15' then
163 temp_date := add_months (p_semi_month_date, -1) ;
164 if last_day(temp_date+15) = last_day(temp_date) then
165 return(temp_date + 15);
166 else
167 -- for p_semi_month_date = Mar 14th, for example
168 return(last_day(temp_date));
169 end if;
170 else -- if after the 16th
171 return(to_date( (temp_day ||
172 substr(to_char(p_semi_month_date,'DD-MON-YYYY'),3)
173 ), 'DD-MON-YYYY'));
174 end if ;
175 end if ;
176 end prev_semi_month;
177 --
178 --
179 -- This function is a customized version of add_months function to
180 -- suit the requirement where an option has to be provided to the user
181 -- to create payroll periods with the same end day as the first period.
182 -- This is controlled by the global variable g_constant_end_date.
183 -- If g_constant_end_date is not true then the result of add_months is
184 -- returned back. If g_constant_end_date is true then a period end date
185 -- which has the day as in the first period end date is determined.
186 -- This value is returned if such a date is valid for the period else
187 -- the last day in the period is returned. Bug #3697834.
188 --
189 FUNCTION customized_add_months ( p_date_in in DATE,
190 p_first_period_end_date in DATE,
191 p_months_shift in NUMBER )
192 RETURN DATE IS
193 l_return_value DATE;
194 l_day_of_month VARCHAR2(2);
195 l_month_year VARCHAR2(6);
196 l_end_of_month DATE;
197 BEGIN
198
199 l_return_value := add_months(p_date_in, p_months_shift);
200
201 if g_constant_end_date then
202
203 -- Pull out the day number of the first period end date
204 l_day_of_month := least ( to_number(to_char(p_first_period_end_date,'DD')), to_number(to_char(last_day ( l_return_value ) , 'DD'))) ;
205
206 -- Grab the month and year of the new date
207 l_month_year := to_char(l_return_value, 'MMYYYY');
208
209 -- Combine these components into an actual date
210
211 l_end_of_month := to_date(l_month_year || l_day_of_month, 'MMYYYYDD');
212
213
214 -- Return the earliest of
215 -- (a) the normal result of ADD_MONTHS
216 -- and (b) the same day in the new period as in the first period end date.
217
218 l_return_value := LEAST (l_return_value, l_end_of_month);
219
220 end if;
221
222 return l_return_value;
223
224 END customized_add_months;
225 --
226 -- The period numbers and period names are derived using regular pay date.
227 -- Since leap years have an extra day in February,
228 -- for some offsets the period numbers derived might not be consistent.
229 -- To avoid this an adjustment is done to the regualar pay date in
230 -- leap years to ignore the extra day in february.
231 -- This function helps in finding out if the adjustment is required or not
232 -- by returning either -1 , 1 or 0. The value returned is added to the
233 -- normal regual pay date before using it for deriving period numbers.
234 -- This is applicable only for payrolls with base period type as MONTHLY.
235 -- Bug # 3663126.
236
237 FUNCTION get_leap_year_offset ( p_period_end_date in date,
238 p_pay_date_offset in number )
239 RETURN NUMBER IS
240 --
241 l_year varchar2(4);
242 l_start_date date;
243 l_end_date date;
244 l_date date;
245 l_return_value number;
246 --
247 BEGIN
248
249 l_year := to_char( p_period_end_date, 'YYYY');
250 l_return_value := 0;
251
252 -- Determine if this is a leap year.
253
254 if ( mod(to_number(l_year), 4) = 0 and mod(to_number(l_year), 100) <> 0 ) or
255 ( mod(to_number(l_year), 4) = 0 and mod(to_number(l_year), 400) = 0 ) then
256
257 l_date := to_date('2902'|| l_year ,'DDMMYYYY');
258
259 if p_pay_date_offset < 0 then
260
261 l_start_date := p_period_end_date + p_pay_date_offset;
262 l_end_date := p_period_end_date;
263
264 if l_date >= l_start_date and l_date <= l_end_date then
265 l_return_value := -1;
266 end if;
267 else
268 l_start_date := p_period_end_date;
269 l_end_date := p_period_end_date + p_pay_date_offset;
270
271 if l_date > l_start_date and l_date <= l_end_date then
272 l_return_value := 1;
273 end if;
274 end if;
275 end if;
276
277 return l_return_value;
278
279 END get_leap_year_offset;
280 --
281 --
282 -- This function performs the date calculation according to the
283 -- base period type for the period type being considered.
284 -- Note that for WEEKLY base period, the calculation can be
285 -- performed by adding days ie. straightforward addition operation.
286 -- For MONTHLY base period, the add_months() function is used.
287 -- The exception to these general categories is semi-monthly,
288 -- which is handled explicitly by the SEMIMONTHLY base period.
289 -- This case only uses the p_multiple parameter to determine whether
290 -- to add or subtract a semi-month, ie. this function can only
291 -- increase semi-months unitarily. Furthermore, it has exclusive use
292 -- of the 'regular_pay_mode' parameter, which for SEMIMONTHLY,
293 -- indicates whether or not we are calculating for a regular payment
294 -- date calculation. The p_fpe_date is the first period's end-date
295 -- and is needed only for semimonthly period calculations.
296 --
297 function add_multiple_of_base (p_target_date in date,
298 p_base_period_type in varchar2,
299 p_multiple in number,
300 p_fpe_date in date,
301 p_regular_pay_mode boolean default false,
302 p_pay_date_offset number default null)
303 return date is
304 --
305 func_name CONSTANT varchar2(50) := 'hr_payrolls.add_multiple_of_base';
306 rest_of_date varchar2(9);
307 temp_date date;
308 -- Bug 5935976 for 10 Payroll
309 l_date2 date;
310 l_day varchar2(10);
311 l_month varchar2(10);
312 l_year varchar2(10);
313 l_start_day varchar2(10);
314 --
315 begin
316 -- Errors can occur when performing date manipulation.
317 if p_base_period_type = WEEKLY then
318 hr_utility.set_location(func_name, 1);
319 return (p_target_date + (7 * p_multiple));
320 elsif p_base_period_type = MONTHLY then
321 hr_utility.set_location(func_name, 2);
322
323 -- Replacing add_months with customized_add_months for Bug #3697834.
324
325 if not p_regular_pay_mode then
326 temp_date := customized_add_months( p_date_in => p_target_date,
327 p_first_period_end_date => p_fpe_date,
328 p_months_shift => p_multiple );
329
330 return temp_date;
331 else
332 temp_date := p_target_date - p_pay_date_offset;
333 temp_date := customized_add_months( p_date_in => temp_date,
334 p_first_period_end_date => p_fpe_date,
335 p_months_shift => p_multiple );
336 return ( temp_date + p_pay_date_offset );
337 end if;
338 -- added following code for 10 day Payroll Bug #5935976
339 elsif p_base_period_type = TEN_DAYS then
340
341 hr_utility.set_location(func_name, 3);
342 l_day := to_char(p_target_date, 'DD');
343 l_month := to_char(p_target_date, 'MM');
344 l_year := to_char(p_target_date, 'YYYY');
345 l_start_day :='01' ;
346
347 if p_multiple > 0 then
348 -- return 10, 20, last_day
349 -- go front and return end date
350 if l_day = 20 then
351 l_date2 := last_day(p_target_date);
352 else
353 l_date2 := p_target_date + 10;
354 end if;
355 else
356 -- return 1, 11,21
357 -- go back and return start date
358 if p_target_date = last_day(p_target_date) then
359 l_start_day := '21';
360 l_date2 := to_date( l_start_day ||'-'|| l_month ||'-' ||l_year, 'DD-MM-YYYY');
361 else
362 l_date2 := p_target_date -9;
363 end if;
364 end if;
365 return (l_date2 );
366 --
367 else
368 -- This is semi-monthly. A pair of semi-months always spand
369 -- a whole calendar month. Their start and end dates are either
370 -- 1st - 15th or 16th - last day of month. This makes the
371 -- addition/subtraction of a period reasonably straightforward,
372 -- if a little involved.
373 -- On the other hand, if the p_regular_pay_mode is TRUE, we
374 -- have to take into account the regular pay date offset.
375 if not p_regular_pay_mode then
376 if p_multiple > 0 then
377 -- Addition of one semi-month.
378 return(next_semi_month(p_target_date, p_fpe_date));
379 else
380 -- Substraction of one semi-month.
381 return(prev_semi_month(p_target_date, p_fpe_date));
382 end if;
383 else
384 -- Special calculation for regular payment date offset.
385 -- In this special case, we calculate the pay date of the previous
386 -- semimonth period: Current pay-date -> Current end-date ->
387 -- Previous period's end-date -> Previous period's pay-date.
388 temp_date := prev_semi_month (p_target_date - p_pay_date_offset,
389 p_fpe_date) + p_pay_date_offset ;
390 hr_utility.trace('pay date ' || to_char(temp_date, 'dd-mon-yyyy'));
391 return(temp_date);
392 -- OLD CODE
393 -- Now period's are not guaranteed to end on the 15th or the end_of_month.
394 --
395 -- rest_of_date := substr(to_char(p_target_date, 'DD-MON-YYYY'), 3);
396 -- if p_target_date between
397 -- to_date(('01' || rest_of_date), 'DD-MON-YYYY') and
398 -- to_date(('15' || rest_of_date), 'DD-MON-YYYY')
399 -- then
400 -- -- First half of month, put to 15th and subtract a period.
401 -- temp_date := to_date(('15' || rest_of_date), 'DD-MON-YYYY');
402 -- temp_date := prev_semi_month(temp_date) + p_pay_date_offset;
403 -- hr_utility.trace('1st half ' || to_char(temp_date, 'dd-mon-yyyy'));
404 -- return(temp_date);
405 -- else
406 -- -- We are in second half of month.
407 -- temp_date := last_day(p_target_date);
408 -- temp_date := prev_semi_month(temp_date) + p_pay_date_offset;
409 -- hr_utility.trace('2nd half ' || to_char(temp_date, 'dd-mon-yyyy'));
410 -- return(temp_date);
411 -- end if;
412 -- OLD CODE
413 end if;
414 end if;
415 end add_multiple_of_base;
416 --
417 --
418 -- This procedure determines the period information that is not
419 -- held directly on the payroll itself, namely:
420 --
421 -- 1. Start date of first period for payroll.
422 -- 2. Start date of first period to be generated.
423 -- 3. End date of first period to be generated.
424 --
425 -- Note that it relies on the base period type, multiple and semi-month
426 -- count on the payroll details record being populated.
427 --
428 procedure derive_payroll_dates(p_pay_det in out nocopy payroll_rec_type) is
429 --
430 proc_name CONSTANT varchar2(50) := 'hr_payrolls.derive_payroll_dates';
431 --
432 earliest_start_date date;
433 latest_end_date date;
434 no_periods number;
435 --
436 begin
437 -- Find the start and end dates of the earliest and latest periods
438 -- generated for the payroll.
439 hr_utility.set_location(proc_name, 1);
440 select min(start_date),
441 max(end_date),
442 count(time_period_id)
443 into earliest_start_date,
444 latest_end_date,
445 no_periods
446 from per_time_periods ptp
447 where ptp.payroll_id = p_pay_det.payroll_id;
448 --
449 if no_periods = 0 then
450 --
451 -- No periods have been generated for the payroll before.
452 --
453 --
454 -- The start date must be derived.
455 hr_utility.set_location(proc_name, 2);
456 -- added for 10 day payroll Bug 5935976
457 if p_pay_det.base_period_type = TEN_DAYS then
458 p_pay_det.first_start_date
459 := add_multiple_of_base(p_pay_det.first_end_date,
460 p_pay_det.base_period_type,
461 -(p_pay_det.multiple),
462 p_pay_det.first_end_date) ;
463 else
464 p_pay_det.first_start_date
465 := add_multiple_of_base(p_pay_det.first_end_date,
466 p_pay_det.base_period_type,
467 -(p_pay_det.multiple),
468 p_pay_det.first_end_date) + 1;
469 end if;
470 --
471 -- The generated start and end dates will be the same as
472 -- those of the earliest payroll period.
473 p_pay_det.first_gen_start_date := p_pay_det.first_start_date;
474 p_pay_det.first_gen_end_date := p_pay_det.first_end_date;
475 else
476 --
477 -- Periods have been generated for the payroll before.
478 --
479 hr_utility.set_location(proc_name, 3);
480 p_pay_det.first_gen_start_date := latest_end_date + 1;
481 p_pay_det.first_start_date := earliest_start_date;
482 --
483 -- The end date of the first period to be generated must be
484 -- derived.
485 hr_utility.set_location(proc_name, 4);
486 p_pay_det.first_gen_end_date
487 := add_multiple_of_base((p_pay_det.first_gen_start_date)-1,
488 p_pay_det.base_period_type,
489 p_pay_det.multiple,
490 p_pay_det.first_end_date) ;
491 end if;
492 --
493 end derive_payroll_dates;
494 --
495 PROCEDURE chk_reset ( p_payroll_details in payroll_rec_type
496 ,p_period_number in per_time_periods.period_num%type
497 ,p_no_of_periods in per_time_period_types.number_per_fiscal_year%type
498 ,p_period_start_date in per_time_periods.start_date%type
499 ,p_next_leg_start_date in date
500 ,p_period_end_date in out nocopy per_time_periods.end_date%type
501 ,p_no_of_weeks_reset in out nocopy number ) IS
502 --
503 proc_name CONSTANT varchar2(50) := 'hr_payrolls.chk_reset';
504 --
505 --
506 l_no_of_weeks number := 0;
507 l_week_number number;
508 l_year_end_date date;
509 l_next_period_start_date date;
510 l_next_period_end_date date;
511 l_last_period boolean := false;
512 --
513 CURSOR csr_week_number (p_date in date) IS
514 select to_char(p_date,'IW') from dual;
515 --
516 BEGIN
517 --
518 hr_utility.set_location(proc_name, 1);
519 --
520 -- Reset the Payroll Periods for Lunar Month
521 --
522
523 -- Check if this is the last period of the financial year
524
525 l_next_period_end_date := add_multiple_of_base(p_period_end_date,
526 p_payroll_details.base_period_type,
527 p_payroll_details.multiple,
528 p_payroll_details.first_end_date);
529
530 -- Determine the period number of the this period.
531
532 if (l_next_period_end_date + p_payroll_details.pay_date_offset - (7 * p_no_of_weeks_reset))
533 >= p_next_leg_start_date then
534 l_last_period := true;
535 else
536 l_last_period := false;
537 end if;
538
539 if (((l_last_period = true and p_payroll_details.period_reset_years = 'L')
540 or (p_period_number = 1 and p_payroll_details.period_reset_years = 'F'))
541 and p_no_of_periods = 13 ) then
542
543 l_year_end_date := to_date('31/12/' ||
544 to_char(p_period_end_date, 'YYYY'), 'DD/MM/YYYY');
545
546 open csr_week_number(l_year_end_date);
547 fetch csr_week_number into l_no_of_weeks;
548 close csr_week_number;
549
550 -- Continue only if the year has 53 ISO Weeks
551
552 if l_no_of_weeks = 53 then
553
554 if p_payroll_details.period_reset_years = 'F' then
555
556 p_period_end_date := add_multiple_of_base(p_period_end_date,
557 p_payroll_details.base_period_type,
558 p_payroll_details.multiple * 12,
559 p_payroll_details.first_end_date);
560
561 end if;
562
563 l_next_period_start_date := p_period_end_date + 1;
564
565 open csr_week_number(l_next_period_start_date);
566 fetch csr_week_number into l_week_number;
567 close csr_week_number;
568
569 -- Calculate the number of weeks to be reset
570 p_no_of_weeks_reset := 0;
571 while l_week_number <> 1 and l_next_period_start_date < p_next_leg_start_date loop
572
573 p_period_end_date := p_period_end_date + 7;
574 l_next_period_start_date := p_period_end_date + 1;
575 p_no_of_weeks_reset := p_no_of_weeks_reset + 1;
576
577 open csr_week_number(l_next_period_start_date);
578 fetch csr_week_number into l_week_number;
579 close csr_week_number;
580
581 end loop;
582
583 if p_payroll_details.period_reset_years = 'F' then
584
585 p_period_end_date := add_multiple_of_base(p_period_end_date - (p_no_of_weeks_reset * 7),
586 p_payroll_details.base_period_type,
587 -(p_payroll_details.multiple * 12),
588 p_payroll_details.first_end_date);
589
590 p_period_end_date := p_period_end_date + (p_no_of_weeks_reset * 7);
591
592 end if;
593
594 if p_no_of_weeks_reset > 1 then
595
596 -- Set the warning variables
597 g_weeks_reset_warn := true;
598 g_reset_period_start_date := p_period_start_date;
599 g_reset_period_end_date := p_period_end_date;
600 g_no_of_weeks_reset := p_no_of_weeks_reset;
601
602 end if;
603
604 end if;
605 end if;
606
607 hr_utility.set_location(proc_name, 5);
608 --
609 END chk_reset;
610 --
611 PROCEDURE clear_warnings IS
612 --
613 proc_name CONSTANT varchar2(50) := 'hr_payrolls.clear_warnings';
614 --
615 BEGIN
616 --
617 hr_utility.set_location(proc_name, 1);
618
619 g_weeks_reset_warn := false;
620 g_end_date_changed_warn := false;
621 g_no_of_weeks_reset := 0;
622 g_reset_period_name := null;
623 g_new_end_date := null;
624
625 hr_utility.set_location(proc_name, 5);
626 --
627 END clear_warnings;
628 --
629 --
630 PROCEDURE get_warnings ( p_weeks_reset_warn IN OUT nocopy boolean
631 ,p_end_date_changed_warn IN OUT nocopy boolean
632 ,p_no_of_weeks_reset IN OUT nocopy number
633 ,p_reset_period_name IN OUT nocopy per_time_periods.period_name%type
634 ,p_new_end_date IN OUT nocopy per_time_periods.end_date%type ) IS
635 --
636 proc_name CONSTANT varchar2(50) := 'hr_payrolls.get_warnings';
637 --
638 BEGIN
639 --
640 hr_utility.set_location(proc_name, 1);
641
642 p_weeks_reset_warn := g_weeks_reset_warn;
643 p_end_date_changed_warn := g_end_date_changed_warn;
644 p_no_of_weeks_reset := g_no_of_weeks_reset;
645 p_reset_period_name := g_reset_period_name;
646 p_new_end_date := g_new_end_date;
647
648 hr_utility.set_location(proc_name, 5);
649 --
650 END get_warnings;
651 --
652 -- This procedure is called either to create payroll processing
653 -- periods for a payroll for the first time, or to create further
654 -- periods to the ones which already exist.
655 -- If no periods already exist, then we only have the end date of
656 -- the first period, from which we can calculate that period's
657 -- start date. However, if periods do already exist, then the
658 -- start date of the first period we must generate is passed in.
659 -- Note that the end date of the very first period generated/to
660 -- be generated is ALWAYS passed in. It is from this that we can
661 -- determine how far into the future we generate payroll periods.
662 -- Note further that throughout the procedure, reference is made
663 -- to the period number. For calculation purposes, this is a
664 -- monotomically increasing number for periods within a legislative
665 -- year, being reset to 1 for each year. It is NOT the period number
666 -- which is stored against the period. The requirement is that
667 -- the displayed period number is a multiple of the base period
668 -- types comprising the period type of the generated periods
669 -- eg. the first lunar month period is numbered 4, the second 8 etc.
670 --
671 --
672 procedure insert_proc_periods(p_pay_det in out nocopy payroll_rec_type,
673 p_last_update_date in date default sysdate,
674 p_last_updated_by in number default -1,
675 p_last_update_login in number default -1,
676 p_created_by in number default -1,
677 p_creation_date in date default sysdate,
678 p_first_gen_date out nocopy date) is
679 --
680 proc_name CONSTANT varchar2(50) := 'hr_payrolls.insert_proc_periods';
681 --
682 per_num number; -- Monotonic period number, not displayed.
683 payroll_start_date pay_all_payrolls_f.effective_start_date%type;
684 payroll_end_date pay_all_payrolls_f.effective_end_date%type;
685 within_period_flag boolean := FALSE;
686 leg_start_date date;
687 end_years_marker date;
688 next_leg_start_date date;
689 period_start_date date;
690 period_end_date date;
691 current_regular_pay_date date;
692 l_period_number number;
693 l_period_name per_time_periods.period_name%type ;
694 l_display_period_type per_time_period_types.display_period_type%type ;
695 l_first_period_end_date date;
696 l_period_generate_count number := 1;
697 l_tax_year number(4);
698 --
699 l_no_of_periods per_time_period_types.number_per_fiscal_year%type;
700 l_no_of_weeks_reset number := 0;
701 l_period_end_date date;
702 l_leap_year_offset number;
703 --
704 CURSOR c_get_no_of_periods IS
705 select tp.number_per_fiscal_year
706 from per_time_period_types tp
707 where tp.period_type = p_pay_det.period_type;
708 --
709 begin
710 --
711 -- Derive the complete date range for this payroll.
712 hr_utility.set_location(proc_name, 1);
713 select min(ppy.effective_start_date),
714 max(ppy.effective_end_date)
715 into payroll_start_date,
716 payroll_end_date
717 from pay_all_payrolls_f ppy
718 where ppy.payroll_id = p_pay_det.payroll_id;
719 --
720 --
721 -- The periods generated must exist within the lifetime of the
722 -- payroll. Throughout the system, data is viewed within the
723 -- context of a period; hence, creating periods outside of the
724 -- payroll could introduce problems.
725 -- A consequence of this is that no periods will be generated
726 -- for the payroll if we cannot fit one into the date-effective
727 -- lifetime of the payroll. In this case, we raise an exception.
728 -- Note that if the code is invoked to add further periods to existing
729 -- ones, and none are created because of the end date on the payroll,
730 -- then no exception is raised (this situation could quite possibly
731 -- arise).
732 --
733 if p_pay_det.first_start_date < payroll_start_date or
734 p_pay_det.first_end_date > payroll_end_date then
735 hr_utility.set_message(801, 'PAY_6603_PAYROLL_NOGEN_PERIODS');
736 hr_utility.raise_error;
737 end if;
738 --
739 --
740 -- Derive the period number of the first period. It is not necessarily
741 -- 1, since this period is defined to be the first period whose regular
742 -- payment date lies within the legislative year.
743 --
744 declare
745 regular_pay_date date;
746 no_periods number;
747 begin
748 -- Loop back to find the first time period with its regular pay date
749 -- in the current legislative year. This is period 1, so from this
750 -- the period number of the first period to be generated can be
751 -- derived.
752 hr_utility.set_location(proc_name, 2);
753
754 -- Adjust regular pay date for the first generated period if required.
755
756 l_leap_year_offset := 0;
757
758 if p_pay_det.base_period_type = MONTHLY then
759
760 l_leap_year_offset := get_leap_year_offset ( p_period_end_date => p_pay_det.first_gen_end_date
761 ,p_pay_date_offset => p_pay_det.pay_date_offset );
762
763 end if;
764
765 regular_pay_date := p_pay_det.first_gen_end_date + l_leap_year_offset +
766 p_pay_det.pay_date_offset ;
767 --
768 -- Append the year component of the first regular pay date
769 -- to the legislative year start. This is necessary so that
770 -- we can determine the legislative start date to consider
771 -- eg. if the pay date is 04-apr-1992, then the legislative start
772 -- date in the UK is 06-apr-1991; if the pay date is 07-apr-1992,
773 -- then the legislative start date is 06-apr-1992.
774 -- Changed for MLS compliance to query the rule mode of the
775 -- format DD/MM, then make up the actual date using the regular
776 -- pay for the year element as before.
777 --
778 hr_utility.set_location(proc_name, 3);
779 begin
780 select to_date(plr.rule_mode || '/' ||
781 to_char(regular_pay_date, 'YYYY'), 'DD/MM/YYYY')
782 into leg_start_date
783 from pay_legislation_rules plr
784 where plr.rule_type = 'L'
785 and plr.legislation_code = p_pay_det.legislation_code ;
786 --
787 -- Also change defaulting.
788 EXCEPTION
789 when NO_DATA_FOUND then
790 leg_start_date := to_date('01/01/' ||
791 to_char(regular_pay_date, 'YYYY'), 'DD/MM/YYYY');
792 end;
793 --
794 -- Now establish whether the payment date must always lie within
795 -- the period. Default already set to FALSE.
796 hr_utility.set_location(proc_name, 11);
797 --
798 declare
799 rulemode pay_legislation_rules.rule_mode%type;
800 begin
801 --
802 select plr.rule_mode
803 into rulemode
804 from pay_legislation_rules plr
805 where plr.rule_type = 'PDO'
806 and plr.legislation_code = p_pay_det.legislation_code ;
807 --
808 if rulemode = 'N' then
809 within_period_flag := TRUE;
810 end if;
811 --
812 EXCEPTION
813 when NO_DATA_FOUND then null;
814 end;
815 --
816 if leg_start_date > regular_pay_date then
817 -- Must reduce the legislative start date by a year.
818 hr_utility.set_location(proc_name, 4);
819 leg_start_date := add_months(leg_start_date, -12);
820 end if;
821 --
822 -- Remove the l_leap_year_offset added to the regular pay date
823 -- as it is again added in the while loop.
824
825 regular_pay_date := regular_pay_date - l_leap_year_offset ;
826
827 no_periods := 0;
828 while regular_pay_date + l_leap_year_offset >= leg_start_date loop
829 regular_pay_date := add_multiple_of_base(regular_pay_date,
830 p_pay_det.base_period_type,
831 -(p_pay_det.multiple),
832 p_pay_det.first_end_date,
833 true, -- regular pay mode.
834 p_pay_det.pay_date_offset);
835 no_periods := no_periods + 1;
836 -- added to calculate previous period end date
837 if p_pay_det.base_period_type = TEN_DAYS then
838 regular_pay_date := regular_pay_date -1 ;
839 end if;
840
841 l_leap_year_offset := 0;
842
843 if p_pay_det.base_period_type = MONTHLY then
844
845 l_leap_year_offset := get_leap_year_offset ( p_period_end_date => regular_pay_date - p_pay_det.pay_date_offset
846 ,p_pay_date_offset => p_pay_det.pay_date_offset );
847
848 end if;
849
850 end loop;
851 --
852 per_num := no_periods;
853 hr_utility.set_location('per_num '||per_num,10);
854 end; -- Deriving period number.
855 --
856
857 -- Clear the Global Warning Variables
858 --
859 clear_warnings;
860
861 --
862 -- Insert time periods for the number of years required.
863 --
864 --
865 hr_utility.set_location(proc_name, 5);
866 end_years_marker := add_months(p_pay_det.first_start_date,
867 (12 * p_pay_det.no_years));
868 --
869 -- Hold the start date of the next legislative year in order to
870 -- determine when we are crossing the year boundary.
871 hr_utility.set_location(proc_name, 6);
872 next_leg_start_date := add_months(leg_start_date, 12);
873 period_start_date := p_pay_det.first_gen_start_date;
874 period_end_date := p_pay_det.first_gen_end_date;
875 --
876
877 -- Code for the resetting of periods for lunar months
878 --
879 open c_get_no_of_periods;
880 fetch c_get_no_of_periods into l_no_of_periods;
881 close c_get_no_of_periods;
882
883 -- Check if first generated period has to be reset.
884 -- Also check if the first period end date has to be changed (possible only while inserting)
885
886 l_period_end_date := period_end_date;
887
888 chk_reset( p_payroll_details => p_pay_det
889 ,p_period_number => per_num
890 ,p_no_of_periods => l_no_of_periods
891 ,p_period_start_date => period_start_date
892 ,p_next_leg_start_date => next_leg_start_date
893 ,p_period_end_date => period_end_date
894 ,p_no_of_weeks_reset => l_no_of_weeks_reset );
895
896 if l_period_end_date <> period_end_date then
897
898 -- If first generated period is same as first period of the entire payroll then
899 -- first period end date of the payroll has to be updated
900
901 if p_pay_det.first_start_date = p_pay_det.first_gen_start_date and
902 p_pay_det.first_end_date = p_pay_det.first_gen_end_date then
903
904 p_pay_det.first_end_date := period_end_date;
905 p_pay_det.first_gen_end_date := period_end_date;
906
907 update pay_all_payrolls_f
908 set first_period_end_date = period_end_date
909 where payroll_id = p_pay_det.payroll_id;
910
911 -- Set the warning variable
912 g_end_date_changed_warn := true;
913 g_new_end_date := period_end_date;
914
915 if p_pay_det.first_end_date > payroll_end_date then
916 hr_utility.set_message(801, 'PAY_6603_PAYROLL_NOGEN_PERIODS');
917 hr_utility.raise_error;
918 end if;
919 else
920 p_pay_det.first_gen_end_date := period_end_date;
921 end if;
922
923 end if;
924 --
925
926 -- get leap year offset for the first generated period as it might have been
927 -- lost.
928
929 l_leap_year_offset := 0;
930
931 if p_pay_det.base_period_type = MONTHLY then
932
933 l_leap_year_offset := get_leap_year_offset ( p_period_end_date => p_pay_det.first_gen_end_date
934 ,p_pay_date_offset => p_pay_det.pay_date_offset );
935
936 end if;
937
938
939 -- Generate periods for the more restrictive of the two date
940 -- ranges:
941 --
942 -- 1. Number of years to be generated on the payroll.
943 -- 2. Date effective lifetime of the payroll.
944 --
945 while (period_start_date < end_years_marker) and
946 (period_end_date <= payroll_end_date) loop
947 --
948 current_regular_pay_date := period_end_date + p_pay_det.pay_date_offset;
949 --
950 -- If payment dates must lie within their periods for the legislation,
951 -- then check this is the case. It's too difficult to catch all cases
952 -- at offset definition time.
953 --
954 if within_period_flag = TRUE then
955 if ( current_regular_pay_date < period_start_date ) or
956 ( current_regular_pay_date > period_end_date ) then
957 hr_utility.set_message(801, 'PAY_6999_PAYROLL_INV_PAY_DATE');
958 hr_utility.raise_error;
959 end if;
960 end if;
961 --
962 -- Bug 493007
963 -- Find the Display Period Type (translated version) for the given
964 -- Period Type.
965 --
966 select NVL(tpt.display_period_type, p_pay_det.period_type)
967 into l_display_period_type
968 from per_time_period_types_vl tpt
969 where tpt.period_type = p_pay_det.period_type;
970 --
971 -- For GB legislation we store the period number as the multiple of
972 -- constituent base period types.
973 --
974 l_tax_year := (to_char(next_leg_start_date, 'YYYY') - 1);
975
976 if ( p_pay_det.legislation_code = 'GB' ) then
977 l_period_number := per_num * p_pay_det.multiple ;
978 --
979 -- Check to see if a profile value is set to create period names
980 -- based on current tax year instead of current calendar year.
981 --
982 --Bug 1818469
983 if (fnd_profile.value('PAY_GENERATE_PAYROLL_PERIODS_TAX_YEAR') = 'Y' and
984 period_start_date < next_leg_start_date) then
985 l_period_name := to_char(per_num * p_pay_det.multiple) || ' '
986 || to_char(l_tax_year) || ' '
987 || l_display_period_type ;
988 else
989 l_period_name := to_char(per_num * p_pay_det.multiple) || ' '
990 || to_char(current_regular_pay_date + l_leap_year_offset - (7 * l_no_of_weeks_reset), 'YYYY') || ' '
991 || l_display_period_type ;
992 end if;
993 --
994 else
995 l_period_number := per_num ;
996 --
997 -- Check to see if a profile value is set to create period names
998 -- based on current tax year instead of current calendar year.
999 --
1000 if (fnd_profile.value('PAY_GENERATE_PAYROLL_PERIODS_TAX_YEAR') = 'Y' and
1001 period_start_date < next_leg_start_date) then
1002 l_period_name := to_char(per_num) || ' '
1003 || to_char(l_tax_year) || ' '
1004 || l_display_period_type ;
1005
1006 else
1007 l_period_name := to_char(per_num) || ' '
1008 || to_char(current_regular_pay_date + l_leap_year_offset - (7 * l_no_of_weeks_reset), 'YYYY') || ' '
1009 || l_display_period_type ;
1010 end if;
1011 --
1012 end if;
1013
1014 -- Store the reset period name for displaying in the warning message
1015
1016 if period_start_date = g_reset_period_start_date and period_end_date = g_reset_period_end_date then
1017 g_reset_period_name := l_period_name;
1018 end if;
1019
1020 --
1021 hr_utility.set_location('l_period_name '||l_period_name,10);
1022 -- Insert the processing time period.
1023 hr_utility.set_location(proc_name, 7);
1024 insert into per_time_periods
1025 (time_period_id,
1026 payroll_id,
1027 start_date,
1028 end_date,
1029 regular_payment_date,
1030 cut_off_date,
1031 pay_advice_date,
1032 default_dd_date,
1033 period_type,
1034 period_num,
1035 period_name,
1036 status,
1037 run_display_number,
1038 quickpay_display_number,
1039 last_update_date,
1040 last_updated_by,
1041 last_update_login,
1042 created_by,
1043 creation_date,
1044 payslip_view_date)
1045 select
1046 per_time_periods_s.nextval,
1047 p_pay_det.payroll_id,
1048 period_start_date,
1049 period_end_date,
1050 current_regular_pay_date,
1051 period_end_date + p_pay_det.cut_off_date_offset,
1052 period_end_date + p_pay_det.pay_advice_date_offset,
1053 period_end_date + p_pay_det.direct_deposit_date_offset,
1054 p_pay_det.period_type,
1055 l_period_number,
1056 l_period_name,
1057 'O',
1058 1,
1059 1,
1060 p_last_update_date,
1061 p_last_updated_by,
1062 p_last_update_login,
1063 p_created_by,
1064 p_creation_date,
1065 Current_regular_pay_date + p_pay_det.payslip_view_date_offset
1066 from sys.dual;
1067 --
1068 -- Increment loop variables.
1069 hr_utility.set_location(proc_name, 8);
1070 -- Store the first period end date, on the first loop.
1071 if l_period_generate_count = 1 then
1072 l_first_period_end_date := period_end_date;
1073 end if;
1074 --
1075 l_period_generate_count := l_period_generate_count + 1;
1076 period_start_date := period_end_date + 1;
1077 --
1078 period_end_date := add_multiple_of_base(period_end_date,
1079 p_pay_det.base_period_type,
1080 p_pay_det.multiple,
1081 p_pay_det.first_end_date);
1082
1083 -- Determine the period number.
1084 hr_utility.set_location(proc_name, 9);
1085
1086 -- Adjust regular pay date if required.
1087
1088 l_leap_year_offset := 0;
1089
1090 if p_pay_det.base_period_type = MONTHLY then
1091
1092 l_leap_year_offset := get_leap_year_offset ( p_period_end_date => period_end_date
1093 ,p_pay_date_offset => p_pay_det.pay_date_offset );
1094
1095 end if;
1096
1097 if (period_end_date + l_leap_year_offset + p_pay_det.pay_date_offset - (7 * l_no_of_weeks_reset))
1098 >= next_leg_start_date then
1099
1100 -- Reset the period number since we have just crossed the year
1101 -- boundary. Also, advance next_leg_start_date to next year.
1102 per_num := 1;
1103 hr_utility.set_location(proc_name, 10);
1104 next_leg_start_date := add_months(next_leg_start_date, 12);
1105 else
1106 per_num := per_num + 1;
1107 end if;
1108
1109 -- Check if reset is required.
1110
1111 chk_reset( p_payroll_details => p_pay_det
1112 ,p_period_number => per_num
1113 ,p_no_of_periods => l_no_of_periods
1114 ,p_period_start_date => period_start_date
1115 ,p_next_leg_start_date => next_leg_start_date
1116 ,p_period_end_date => period_end_date
1117 ,p_no_of_weeks_reset => l_no_of_weeks_reset );
1118 --
1119 end loop;
1120 --
1121 p_first_gen_date := l_first_period_end_date;
1122 --
1123 end insert_proc_periods;
1124 -------------------------------------------------------------------------
1125 --
1126 -- PROCEDURE create_dynamic_local_cal
1127 -- This procedure is used to derive a call to a localization's
1128 -- calendar procedure, by use of dynamic SQL. All the necessary
1129 -- parameters are here to enable localizations to effectively
1130 -- seed extra calendar data.
1131 -------------------------------------------------------------------------
1132 --
1133 procedure create_dynamic_local_cal (p_payroll_id in number,
1134 p_first_period_end in date,
1135 p_first_gen_date in date,
1136 p_period_type in varchar2,
1137 p_base_period_type in varchar2,
1138 p_multiple in number,
1139 p_legislation_code in varchar2) is
1140 --
1141 l_tp_last_end_date date;
1142 NO_PACKAGE_BODY exception;
1143 pragma exception_init(NO_PACKAGE_BODY,-6508);
1144 NO_PACKAGE_PROCEDURE exception;
1145 pragma exception_init(NO_PACKAGE_PROCEDURE,-6550);
1146 --
1147 -- dynamic SQL variables
1148 --
1149 sql_curs number;
1150 rows_processed integer;
1151 statem varchar2(512);
1152 --
1153 cursor get_period_last_end_date(c_payroll_id in number) is
1154 select max(end_date)
1155 from per_time_periods
1156 where payroll_id = c_payroll_id;
1157 --
1158 begin
1159 --
1160 open get_period_last_end_date(p_payroll_id);
1161 fetch get_period_last_end_date into
1162 l_tp_last_end_date;
1163 close get_period_last_end_date;
1164 --
1165 --
1166 -- Create dynamic SQL call to localization calendars package
1167 --
1168 statem := 'BEGIN
1169 pay_'||lower(p_legislation_code)||'_calendars_pkg.create_calendar
1170 (:p_payroll_id,
1171 :p_first_end_date,
1172 :p_last_end_date,
1173 :p_period_type,
1174 :p_base_period_type,
1175 :p_multiple,
1176 :p_first_period_end); END;';
1177 --
1178 sql_curs := dbms_sql.open_cursor;
1179 --
1180 dbms_sql.parse(sql_curs,
1181 statem,
1182 dbms_sql.v7);
1183 --
1184 -- Bind all the variables for the dynamic call
1185 --
1186 dbms_sql.bind_variable(sql_curs,'p_payroll_id',p_payroll_id);
1187 dbms_sql.bind_variable(sql_curs,'p_first_end_date',p_first_gen_date);
1188 dbms_sql.bind_variable(sql_curs,'p_last_end_date',l_tp_last_end_date);
1189 dbms_sql.bind_variable(sql_curs,'p_period_type',p_period_type);
1190 dbms_sql.bind_variable(sql_curs,'p_base_period_type',p_base_period_type);
1191 dbms_sql.bind_variable(sql_curs,'p_multiple',p_multiple);
1192 dbms_sql.bind_variable(sql_curs,'p_first_period_end',p_first_period_end);
1193 --
1194 -- Execute the dyn cursor for the procedure call, then close.
1195 --
1196 BEGIN
1197 --
1198 rows_processed := dbms_sql.execute(sql_curs);
1199 --
1200 -- If one of the user-defined exceptions are raised,
1201 -- do nothing as it means that the legislation does not
1202 -- have a package procedure defined for the localization, in which
1203 -- case we can ignore the call and no further processing outside
1204 -- the normal payroll periods is necessary.
1205 -- Other exceptions (that might be raised by the actual
1206 -- localization's code) can be raised as normal.
1207 --
1208 EXCEPTION
1209 WHEN NO_PACKAGE_BODY OR NO_PACKAGE_PROCEDURE THEN
1210 NULL;
1211 --
1212 END;
1213 dbms_sql.close_cursor(sql_curs);
1214 --
1215 --
1216 end create_dynamic_local_cal;
1217 --
1218 -----------------------------------------------------------------------------
1219 --
1220 -- This procedure is called to insert payroll processing periods.
1221 --
1222 --
1223 procedure create_payroll_proc_periods (p_payroll_id in number,
1224 p_last_update_date in date,
1225 p_last_updated_by in number,
1226 p_last_update_login in number,
1227 p_created_by in number,
1228 p_creation_date in date) is
1229 --
1230 proc_name CONSTANT varchar2(50) := 'hr_payrolls.create_payroll_proc_periods';
1231 --
1232 payroll_details payroll_rec_type;
1233 l_first_gen_end_date date;
1234 --
1235 begin
1236 payroll_details.payroll_id := p_payroll_id;
1237 --
1238 -- Get the payroll details from the date-effective view, so that
1239 -- the correct number of years is retrieved. All other payroll
1240 -- attributes that we are interested in cannot be date-effectively
1241 -- updated.
1242 --
1243 hr_utility.set_location(proc_name, 1);
1244 select ppy.number_of_years,
1245 ppy.period_type,
1246 ppy.pay_date_offset,
1247 ppy.cut_off_date_offset,
1248 ppy.pay_advice_date_offset,
1249 ppy.direct_deposit_date_offset,
1250 ppy.first_period_end_date,
1251 ppy.period_reset_years,
1252 hr_api.return_legislation_code(ppy.business_group_id),
1253 ppy.payslip_view_date_offset
1254 into payroll_details.no_years,
1255 payroll_details.period_type,
1256 payroll_details.pay_date_offset,
1257 payroll_details.cut_off_date_offset,
1258 payroll_details.pay_advice_date_offset,
1259 payroll_details.direct_deposit_date_offset,
1260 payroll_details.first_end_date,
1261 payroll_details.period_reset_years,
1262 payroll_details.legislation_code,
1263 payroll_details.payslip_view_date_offset
1264 from pay_all_payrolls ppy
1265 where ppy.payroll_id = p_payroll_id;
1266 --
1267 --
1268 -- Validate the number of years and midpoint offset, where
1269 -- appropriate.
1270 --
1271 -- Number of years must be > 0.
1272 if payroll_details.no_years <= 0 then
1273 hr_utility.set_message(801, 'PAY_6604_PAYROLL_INV_NO_YEARS');
1274 hr_utility.raise_error;
1275 end if;
1276 --
1277 -- All of the supported time period types map to either a weekly or
1278 -- monthly base period and multiple eg. fortnight = 2 * week,
1279 -- bi-monthly = 2 * month.
1280 --
1281 -- Determine the base period and multiple for the period type specified.
1282 get_period_details(payroll_details.period_type,
1283 payroll_details.base_period_type,
1284 payroll_details.multiple);
1285 --
1286 -- Now derive the remaining payroll period dates.
1287 derive_payroll_dates(payroll_details);
1288 --
1289 -- Insert the further periods required.
1290 insert_proc_periods(payroll_details,
1291 p_last_update_date,
1292 p_last_updated_by,
1293 p_last_update_login,
1294 p_created_by,
1295 p_creation_date,
1296 l_first_gen_end_date);
1297 --
1298 -- Create legislative further calendars information.
1299 --
1300 create_dynamic_local_cal (p_payroll_id => p_payroll_id,
1301 p_first_period_end => payroll_details.first_end_date,
1302 p_first_gen_date => l_first_gen_end_date,
1303 p_period_type => payroll_details.period_type,
1304 p_base_period_type => payroll_details.base_period_type,
1305 p_multiple => payroll_details.multiple,
1306 p_legislation_code => payroll_details.legislation_code);
1307 --
1308 end create_payroll_proc_periods;
1309 ------------------------------------------------------------------------------------
1310 --This is a overloaded version of create_payroll_proc_periods with
1311 --additional parameter p_effective_date and using PAY_ALL_PAYROLLS_F
1312 --table instead of PAY_ALL_PAYROLLS view.
1313 --
1314 procedure create_payroll_proc_periods (p_payroll_id in number,
1315 p_last_update_date in date,
1316 p_last_updated_by in number,
1317 p_last_update_login in number,
1318 p_created_by in number,
1319 p_creation_date in date,
1320 p_effective_date in date ) is
1321 --
1322 proc_name CONSTANT varchar2(50) := 'hr_payrolls.create_payroll_proc_periods';
1323 --
1324 payroll_details payroll_rec_type;
1325 l_first_gen_end_date date;
1326 --
1327 begin
1328 payroll_details.payroll_id := p_payroll_id;
1329 --
1330 -- Get the payroll details from the date-effective view, so that
1331 -- the correct number of years is retrieved. All other payroll
1332 -- attributes that we are interested in cannot be date-effectively
1333 -- updated.
1334 --
1335 hr_utility.set_location(proc_name, 1);
1336 select ppy.number_of_years,
1337 ppy.period_type,
1338 ppy.pay_date_offset,
1339 ppy.cut_off_date_offset,
1340 ppy.pay_advice_date_offset,
1341 ppy.direct_deposit_date_offset,
1342 ppy.first_period_end_date,
1343 pbg.legislation_code,
1344 ppy.payslip_view_date_offset,
1345 ppy.period_reset_years -- Added for bug 8616134
1346 into payroll_details.no_years,
1347 payroll_details.period_type,
1348 payroll_details.pay_date_offset,
1349 payroll_details.cut_off_date_offset,
1350 payroll_details.pay_advice_date_offset,
1351 payroll_details.direct_deposit_date_offset,
1352 payroll_details.first_end_date,
1353 payroll_details.legislation_code,
1354 payroll_details.payslip_view_date_offset,
1355 payroll_details.period_reset_years -- Added for bug 8616134
1356 from pay_all_payrolls_f ppy,
1357 per_business_groups pbg
1358 where ppy.payroll_id = p_payroll_id
1359 and ppy.business_group_id + 0 = pbg.business_group_id + 0
1360 and ppy.effective_start_date <= p_effective_date
1361 and ppy.effective_end_date >= p_effective_date ;
1362 --
1363 --
1364 -- Validate the number of years and midpoint offset, where
1365 -- appropriate.
1366 --
1367 -- Number of years must be > 0.
1368 if payroll_details.no_years <= 0 then
1369 hr_utility.set_message(801, 'PAY_6604_PAYROLL_INV_NO_YEARS');
1370 hr_utility.raise_error;
1371 end if;
1372 --
1373 -- All of the supported time period types map to either a weekly or
1374 -- monthly base period and multiple eg. fortnight = 2 * week,
1375 -- bi-monthly = 2 * month.
1376 --
1377 -- Determine the base period and multiple for the period type specified.
1378 get_period_details(payroll_details.period_type,
1379 payroll_details.base_period_type,
1380 payroll_details.multiple);
1381 --
1382 -- Now derive the remaining payroll period dates.
1383 derive_payroll_dates(payroll_details);
1384 --
1385 -- Insert the further periods required.
1386 insert_proc_periods(payroll_details,
1387 p_last_update_date,
1388 p_last_updated_by,
1389 p_last_update_login,
1390 p_created_by,
1391 p_creation_date,
1392 l_first_gen_end_date);
1393 --
1394 -- Create legislative further calendars information.
1395 --
1396 create_dynamic_local_cal (p_payroll_id => p_payroll_id,
1397 p_first_period_end => payroll_details.first_end_date,
1398 p_first_gen_date => l_first_gen_end_date,
1399 p_period_type => payroll_details.period_type,
1400 p_base_period_type => payroll_details.base_period_type,
1401 p_multiple => payroll_details.multiple,
1402 p_legislation_code => payroll_details.legislation_code);
1403 --
1404 end create_payroll_proc_periods;
1405 --
1406 ------------------------------------------------------------------------------------
1407 --
1408 -- This procedure displays the correct format of period_name
1409 -- depending on ACTION_TYPE.
1410 --
1411 --
1412 function local_display_period_name(p_payroll_action_id IN NUMBER)
1413 --
1414 RETURN VARCHAR2 is
1415 --
1416 l_period_name VARCHAR2(70);
1417 l_payroll_id NUMBER;
1418 l_time_period_id NUMBER;
1419 l_effective_date DATE;
1420 l_start_date DATE;
1421 l_date_earned DATE;
1422 l_action_type VARCHAR2(4);
1423 l_date_from_and_to BOOLEAN := FALSE;
1424 --
1425 cursor action_info(c_payroll_action_id IN NUMBER) is
1426 SELECT payroll_id,
1427 time_period_id,
1428 effective_date,
1429 start_date,
1430 date_earned,
1431 action_type
1432 FROM pay_payroll_actions
1433 WHERE payroll_action_id = c_payroll_action_id;
1434 --
1435 cursor get_name (c_payroll_id IN NUMBER,
1436 c_date_earned IN DATE) is
1437 SELECT period_name
1438 FROM per_time_periods
1439 WHERE payroll_id = c_payroll_id
1440 AND c_date_earned between start_date and end_date;
1441 --
1442 BEGIN
1443 --
1444 open action_info(p_payroll_action_id);
1445 FETCH action_info INTO l_payroll_id,
1446 l_time_period_id,
1447 l_effective_date,
1448 l_start_date,
1449 l_date_earned,
1450 l_action_type;
1451 close action_info;
1452 --
1453 -- Display period name as 'date from and to' if in following action types:
1454 -- Transfer To GL, Retropay, Costing.
1455 --
1456 if l_action_type in ('C','O','P','T') then
1457 l_date_from_and_to := TRUE;
1458 end if;
1459 --
1460 -- where no date_earned is set and action type is not 'date from and to' type
1461 -- just report the period as the start and end of the action.
1462 --
1463 if l_date_earned IS NULL or l_date_from_and_to THEN
1464 l_period_name := to_char(l_start_date, 'dd-MON-yyyy')||' - '
1465 ||to_char (l_effective_date,'dd-MON-yyyy');
1466 else
1467 open get_name (l_payroll_id, l_date_earned);
1468 FETCH get_name into l_period_name;
1469 close get_name;
1470 end if;
1471 --
1472 RETURN l_period_name;
1473 --
1474 end local_display_period_name;
1475 --
1476 function display_period_name(p_payroll_action_id IN NUMBER)
1477 return VARCHAR2 IS
1478 BEGIN
1479 IF g_enable_period_name_fetch THEN
1480 RETURN local_display_period_name(p_payroll_action_id);
1481 END IF;
1482 RETURN NULL;
1483 END display_period_name;
1484 --
1485 function display_period_name_forced(p_payroll_action_id IN NUMBER)
1486 return VARCHAR2 IS
1487 BEGIN
1488 RETURN local_display_period_name(p_payroll_action_id);
1489 END display_period_name_forced;
1490 --
1491 PROCEDURE enable_display_fetch(p_mode IN BOOLEAN) IS
1492 BEGIN
1493 g_enable_period_name_fetch := p_mode;
1494 END enable_display_fetch;
1495 --
1496 PROCEDURE set_globals ( p_constant_end_date in boolean ) IS
1497 BEGIN
1498 g_constant_end_date := p_constant_end_date ;
1499 END set_globals;
1500 --
1501 end hr_payrolls;