1 PACKAGE BODY PER_POS_BGT_PKG AS
2 /* $Header: pebgt03t.pkb 115.2 99/07/17 18:47:18 porting ship $ */
3 --
4 -- PROCEDURE GET_HOLDERS: Calculates the number of people holding
5 -- a position and returns the holders name and emp no if only one
6 -- else returns an appropriate message if number of holders is zero
7 -- or greater than one to X_HOLDER_NAME.
8 --
9 procedure get_holders(X_POSITION_ID NUMBER,
10 X_ORGANIZATION_ID NUMBER,
11 X_BUSINESS_GROUP_ID NUMBER,
12 X_NO_OF_HOLDERS IN OUT VARCHAR2,
13 X_HOLDER_NAME IN OUT VARCHAR2,
14 X_HOLDER_EMP_NO IN OUT VARCHAR2) is
15 --
16 l_real_holder_name varchar2 (240);
17 --
18 begin
19 --
20 hr_utility.set_message('801','HR_ALL_COUNT_HOLDERS');
21 --
22 -- Assume > 1 holder, so set string to "Holders"
23 --
24 X_HOLDER_NAME := hr_utility.get_message;
25 --
26 -- calculate the number of people holding a position and concatenate number
27 -- with "Holders". Get the holder name and holder employee number at the
28 -- same time - we have to use group functions for these, so we get the MAX
29 -- name and number. If the count = 1, the name and number we get must be
30 -- the correct ones; if count <> 1 we're not interested in which name and
31 -- number we'll get, as we discard them anyway. This approach removes
32 -- the need for a second cursor to get the name and number separately.
33 -- RMF 15.11.94.
34 --
35 SELECT COUNT(E.PERSON_ID),
36 '** ' || COUNT(E.PERSON_ID) ||' '|| X_HOLDER_NAME,
37 MAX(E.FULL_NAME),
38 MAX(E.EMPLOYEE_NUMBER)
39 INTO X_NO_OF_HOLDERS,
40 X_HOLDER_NAME,
41 l_real_holder_name,
42 X_HOLDER_EMP_NO
43 FROM PER_ALL_PEOPLE E
44 , PER_ALL_ASSIGNMENTS A
45 WHERE A.POSITION_ID = X_POSITION_ID
46 AND A.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
47 AND A.ORGANIZATION_ID = X_ORGANIZATION_ID
48 AND A.ASSIGNMENT_TYPE = 'E'
49 AND A.PERSON_ID = E.PERSON_ID;
50 --
51 if X_NO_OF_HOLDERS = 0 then
52 -- return the message no holders
53 --
54 hr_utility.set_message('801','HR_ALL_NO_HOLDERS');
55 X_HOLDER_NAME := hr_utility.get_message;
56 X_HOLDER_EMP_NO := NULL;
57 --
58 elsif X_NO_OF_HOLDERS = 1 then
59 -- set X_HOLDER_NAME to the real holder name.
60 --
61 X_HOLDER_NAME := l_real_holder_name;
62 else
63 -- more than one holder, so clear the holder emp no. We've already set
64 -- the holder name to "** n Holders **".
65 --
66 X_HOLDER_EMP_NO := NULL;
67 end if;
68 --
69 end get_holders;
70 --
71 -- PROCEDURE GET_BUDGET_VALUE: Returns the budgeted value for the position.
72 --
73 PROCEDURE GET_BUDGET_VALUE(X_BUDGET_VALUE IN OUT NUMBER,
74 X_BUDGET_VALUE_ID IN OUT NUMBER,
75 X_POSITION_ID NUMBER,
76 X_BUDGET_VERSION_ID NUMBER,
77 X_TIME_PERIOD_ID NUMBER) IS
78 CURSOR C IS
79 SELECT BV.VALUE, BV.BUDGET_VALUE_ID
80 FROM PER_BUDGET_VALUES BV, PER_BUDGET_ELEMENTS BE
81 WHERE BE.POSITION_ID = X_POSITION_ID
82 AND BE.BUDGET_VERSION_ID = X_BUDGET_VERSION_ID
83 AND BV.BUDGET_ELEMENT_ID = BE.BUDGET_ELEMENT_ID
84 AND BV.TIME_PERIOD_ID = X_TIME_PERIOD_ID;
85 --
86 BEGIN
87 OPEN C;
88 FETCH C INTO X_BUDGET_VALUE, X_BUDGET_VALUE_ID;
89 IF C%NOTFOUND THEN
90 X_BUDGET_VALUE := NULL;
91 END IF;
92 CLOSE C;
93 END GET_BUDGET_VALUE;
94
95 --
96 -- PROCEDURE GET_PERIOD_START: Obtain the count as of the start date for the
97 -- selected period.
98 --
99 -- Added join to per_assignment_status_types to filter out terminated
100 -- assignments. RMF 14.11.94.
101 --
102 --
103 --
104 -- Changed datatype from VARCHAR2 to DATE for X_START_DATE and removed call to TO_DATE()
105 -- function from Cursor. PASHUN. 31-10-1997. BUG : 572545.
106 --
107 --
108 -- Added reference to effective dates on per_assignment_budget_values_f and changed name to
109 -- per_assignment_budget_values_f.
110 -- SASmith 31-MAR-1998.
111 --
112 PROCEDURE GET_PERIOD_START(X_PERIOD_START IN OUT NUMBER,
113 X_POSITION_ID NUMBER,
114 X_BUSINESS_GROUP_ID NUMBER,
115 X_START_DATE DATE,
116 X_UNIT VARCHAR2) IS
117 CURSOR C IS
118 SELECT NVL(SUM(ABV.VALUE),0)
119 FROM PER_ASSIGNMENT_BUDGET_VALUES_F ABV,
120 PER_ASSIGNMENT_STATUS_TYPES AST,
121 PER_ASSIGNMENTS_F A
122 WHERE A.POSITION_ID = X_POSITION_ID
123 AND A.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
124 AND X_START_DATE BETWEEN A.EFFECTIVE_START_DATE AND
125 A.EFFECTIVE_END_DATE
126 AND A.ASSIGNMENT_ID = ABV.ASSIGNMENT_ID
127 AND ABV.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
128 AND X_START_DATE BETWEEN ABV.EFFECTIVE_START_DATE AND
129 ABV.EFFECTIVE_END_DATE
130 AND X_UNIT = ABV.UNIT
131 AND A.ASSIGNMENT_STATUS_TYPE_ID = AST.ASSIGNMENT_STATUS_TYPE_ID
132 AND AST.PER_SYSTEM_STATUS <> 'TERM_ASSIGN'
133 AND A.ASSIGNMENT_TYPE = 'E';
134 --
135 BEGIN
136 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_PERIOD_START' ,5 ) ;
137 OPEN C;
138 FETCH C INTO X_PERIOD_START;
139 IF (C%NOTFOUND) THEN
140 X_PERIOD_START := 0;
141 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_PERIOD_START' ,10 ) ;
142 END IF;
143 CLOSE C;
144
145 END GET_PERIOD_START;
146 --
147 -- PROCEDURE GET_PERIOD_END: Obtain the count as of the end date for the
148 -- selected period.
149 --
150 -- Added join to per_assignment_status_types to filter out terminated
151 -- assignments. RMF 14.11.94.
152 --
153 --
154 --
155 -- Changed datatype from VARCHAR2 to DATE for X_END_DATE and removed call to TO_DATE()
156 -- function from Cursor. PASHUN. 31-10-1997. BUG : 572545.
157 --
158 --
159 -- Added reference to effective dates on per_assignment_budget_values and changed name to
160 -- per_assignment_budget_values_f.
161 -- SASMITH 31-MAR-1998.
162 --
163
164 PROCEDURE GET_PERIOD_END(X_PERIOD_END IN OUT NUMBER,
165 X_POSITION_ID NUMBER,
166 X_BUSINESS_GROUP_ID NUMBER,
167 X_END_DATE DATE,
168 X_UNIT VARCHAR2) IS
169 CURSOR C IS
170 SELECT NVL(SUM(ABV.VALUE),0)
171 FROM PER_ASSIGNMENT_BUDGET_VALUES_F ABV,
172 PER_ASSIGNMENT_STATUS_TYPES AST,
173 PER_ASSIGNMENTS_F A
174 WHERE A.POSITION_ID = X_POSITION_ID
175 AND A.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
176 AND X_END_DATE BETWEEN A.EFFECTIVE_START_DATE AND
177 A.EFFECTIVE_END_DATE
178 AND ABV.UNIT = X_UNIT
179 AND A.ASSIGNMENT_ID = ABV.ASSIGNMENT_ID
180 AND X_END_DATE BETWEEN ABV.EFFECTIVE_START_DATE AND
181 ABV.EFFECTIVE_END_DATE
182 AND A.ASSIGNMENT_STATUS_TYPE_ID = AST.ASSIGNMENT_STATUS_TYPE_ID
183 AND AST.PER_SYSTEM_STATUS <> 'TERM_ASSIGN'
184 AND A.ASSIGNMENT_TYPE = 'E';
185 --
186 BEGIN
187 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_PERIOD_END' ,5 ) ;
188
189 OPEN C;
190 FETCH C INTO X_PERIOD_END;
191 IF (C%NOTFOUND) THEN
192 X_PERIOD_END := 0;
193 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_PERIOD_END' ,10) ;
194 END IF;
195 CLOSE C;
196 END GET_PERIOD_END;
197 --
198 --
199 -- PROCEDURE GET_STARTERS: Obtain the number of assignments attaining a
200 -- position within a period.
201 --
202 -- G1448: the cursor has an error in that it joins directly to the
203 -- per_assignments_f table, with the result that a value is counted
204 -- once for *each occurrence* of an assignment record. So, if an assgt
205 -- has 2 date effective updates, that results in three records for the
206 -- assgt. Hence the starters count is often too high. Recoded using the
207 -- following rules:
208 --
209 -- Starters
210 -- --------
211 -- Any assgt record where:
212 -- its pos id matches the pos id in question AND
213 -- its start date is within the time period we're interested in AND
214 -- it's a new assgt, or the previous assgt was to a different pos
215 --
216 -- The date clauses below in the cursor ensure it picks up the date effective
217 -- assgt record ending immediately prior to the first one starting in the
218 -- period, even if the end date is the day before the start date of the period,
219 -- as well as all the date effective assgt records starting within the period.
220 -- This is because we need it to see if the position has changed.
221 --
222 --
223 --
224 -- Changed datatype from VARCHAR2 to DATE for X_END_DATE and X_START_DATE and removed
225 -- call to TO_DATE() function from Cursor. PASHUN. 31-10-1997. BUG : 572545.
226 --
227 --
228 --
229 -- Added reference to effective dates on per_assignment_budget_values and changed name to
230 -- per_assignment_budget_values_f. Required due to the date tracking of per_assignment_budget_values.
231 -- Ensure that the correct assignment budget value is being picked up for the assignment as this may
232 -- be used further down to determine the number of starters (values).
233 -- NOTE : As this table is now date tracked there can be many ABV rows to one assignment row.
234 -- SASMITH 31-MAR-1998.
235 --
236 --
237
238 PROCEDURE GET_STARTERS(X_STARTERS IN OUT NUMBER,
239 X_POSITION_ID NUMBER,
240 X_BUSINESS_GROUP_ID NUMBER,
241 X_START_DATE DATE,
242 X_END_DATE DATE,
243 X_UNIT VARCHAR2) IS
244 CURSOR C IS
245 SELECT A.ASSIGNMENT_ID, A.POSITION_ID,
246 A.EFFECTIVE_START_DATE, A.EFFECTIVE_END_DATE, ABV.VALUE
247 FROM PER_ASSIGNMENT_BUDGET_VALUES_F ABV,
248 PER_ASSIGNMENTS_F A
249 WHERE A.POSITION_ID = X_POSITION_ID
250 AND A.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
251 AND A.EFFECTIVE_START_DATE <= X_END_DATE
252 AND A.EFFECTIVE_END_DATE >= X_START_DATE - 1
253 AND X_UNIT = ABV.UNIT
254 AND A.ASSIGNMENT_ID = ABV.ASSIGNMENT_ID
255
256 AND (A.EFFECTIVE_START_DATE BETWEEN ABV.EFFECTIVE_START_DATE AND ABV.EFFECTIVE_END_DATE)
257
258 AND A.ASSIGNMENT_TYPE = 'E'
259 ORDER BY A.ASSIGNMENT_ID, A.EFFECTIVE_START_DATE;
260 --
261 l_prev_assgt_id number := 0;
262 l_prev_assgt_end date;
263 --
264 BEGIN
265 --
266 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,5 ) ;
267 x_starters := 0;
268 --
269 FOR c_starters IN C LOOP
270 --
271 if c_starters.assignment_id <> l_prev_assgt_id then
272 --
273 -- First rec of an assignment. If its start date is within the period,
274 -- increment the starter count. Otherwise, this record starts before the
275 -- start of the period, so we only need it for comparisons - don't
276 -- increment the counter.
277 --
278 --
279 --
280 -- Removed call to TO_DATE() function forh X_START_DATE.
281 -- PASHUN. 31-OCT-1997. BUG : 572545.
282 --
283 --
284 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,10) ;
285 if c_starters.effective_start_date >= x_start_date then
286 x_starters := x_starters + c_starters.value;
287 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,15) ;
288 end if;
289 --
290 -- Note assignment_id for comparison with the next rec.
291 --
292 l_prev_assgt_id := c_starters.assignment_id;
293 else
294 --
295 -- It's another record for the same assignment, so it must start within
296 -- the budget period. Increment the counter if the assgt record does not
297 -- follow on immediately from the previous one. As the cursor only picks
298 -- up rows with one position_id, a gap in the dates means the position_id
299 -- must have just changed.
300 --
301 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,20) ;
302 if c_starters.effective_start_date - 1 <> l_prev_assgt_end then
303 x_starters := x_starters + c_starters.value;
304 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,25) ;
305 end if;
306 end if;
307 --
308 -- Note end date for comparison with the next rec.
309 --
310 l_prev_assgt_end := c_starters.effective_end_date;
311 --
312 END LOOP;
313 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_STARTERS' ,30) ;
314 END GET_STARTERS;
315 --
316 -- PROCEDURE GET_LEAVERS: Obtain the number of assignments leaving
317 -- a position within a period.
318 --
319 -- G1448: the cursor has an error in that it joins directly to the
320 -- per_assignments_f table, with the result that a value is counted
321 -- once for *each occurrence* of an assignment record. So, if an assgt
322 -- has 2 date effective updates, that results in three records for the
323 -- assgt. Hence the starters count is often too high. Recoded using the
324 -- following rules:
325 --
326 -- Leavers
327 -- -------
328 -- Any assgt record where:
329 -- its pos id matches the pos id in question AND
330 -- its end date is within the time period we're interested in AND
331 -- ( its status is not term_assign but the next assgt's status is
332 -- term_assign
333 -- OR
334 -- the next assgt's pos id has changed
335 -- )
336 --
337 -- The date clauses in the cursor ensure that it picks up the date effective
338 -- assgt record which ends after the end of the period, even if the end date
339 -- of the previous record coincides wit hthe end of the period, as well as all
340 -- the date effective assgt records ending within the period.
341 -- This is because we may need it to see if the position has changed.
342 --
343 --
344 --
345 -- Changed datatype from VARCHAR2 to DATE for X_START_DATE and X_END_DATE
346 -- and removed calls to TO_DATE(). PASHUN. 31-OCT-1997. BUG : 572545.
347 --
348 --
349 --
350 --
351 -- Added reference to effective dates on per_assignment_budget_values and changed name to
352 -- per_assignment_budget_values_f. Required due to the date tracking of per_assignment_budget_values.
353 -- Ensure that the correct assignment budget value is being picked up for the assignment as this may
354 -- be used further down to determine the number of leavers (values).
355 -- NOTE : As this table is now date tracked there can be many ABV rows to one assignment row.
356 -- SASMITH 31-MAR-1998.
357 --
358 --
359 --
360 --
361
362 PROCEDURE GET_LEAVERS(X_LEAVERS IN OUT NUMBER,
363 X_POSITION_ID NUMBER,
364 X_BUSINESS_GROUP_ID NUMBER,
365 X_START_DATE DATE,
366 X_END_DATE DATE,
367 X_UNIT VARCHAR2) IS
368
369 CURSOR C IS
370 SELECT A.ASSIGNMENT_ID, A.POSITION_ID, AST.PER_SYSTEM_STATUS,
371 A.EFFECTIVE_START_DATE, A.EFFECTIVE_END_DATE, ABV.VALUE
372 FROM PER_ASSIGNMENT_BUDGET_VALUES_F ABV,
373 PER_ASSIGNMENT_STATUS_TYPES AST,
374 PER_ASSIGNMENTS_F A
375 WHERE A.POSITION_ID = X_POSITION_ID
376 AND A.BUSINESS_GROUP_ID = X_BUSINESS_GROUP_ID
377 AND A.ASSIGNMENT_STATUS_TYPE_ID = AST.ASSIGNMENT_STATUS_TYPE_ID
378 AND A.EFFECTIVE_START_DATE <= X_END_DATE + 1
379 AND A.EFFECTIVE_END_DATE >= X_START_DATE
380 AND X_UNIT = ABV.UNIT
381 AND A.ASSIGNMENT_ID = ABV.ASSIGNMENT_ID
382
383 AND (A.EFFECTIVE_START_DATE BETWEEN ABV.EFFECTIVE_START_DATE AND ABV.EFFECTIVE_END_DATE)
384
385 AND A.ASSIGNMENT_TYPE = 'E'
386 ORDER BY A.ASSIGNMENT_ID, A.EFFECTIVE_START_DATE;
387 --
388 --
389 l_prev_assgt_id number := 0;
390 l_prev_assgt_value number := 0;
391 l_prev_assgt_status varchar2(30);
392 l_prev_assgt_end date;
396 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',5) ;
393 --
394 BEGIN
395 --
397 x_leavers := 0;
398 --
399 FOR c_leavers IN C LOOP
400 --
401 if c_leavers.assignment_id <> l_prev_assgt_id then
402 --
403 -- First rec of an assignment. Was the previously retrieved record a
404 -- leaver (assuming there was a previous record)? It was a leaver if:
405 -- its end date is not later than the end date of the period AND
406 -- its status is NOT TERM_ASSIGN (because if it is TERM_ASSIGN, we've
407 -- already counted it.
408 --
409 --
410 -- BUG. 572545. Removed call to TO_DATE() function for X_END_DATE.
411 -- PASHUN. 31-OCT-1997.
412 --
413 --
414 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',10) ;
415 if (l_prev_assgt_id <> 0 and
416 l_prev_assgt_end <= x_end_date and
417 l_prev_assgt_status <> 'TERM_ASSIGN'
418 ) then
419 x_leavers := x_leavers + c_leavers.value;
420 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',15) ;
421 end if;
422 --
423 -- As for this assignment, we can't tell whether it's a leaver from
424 -- this record alone - we have to get the next record and compare the
425 -- two. Store the assgt_id.
426 --
427 l_prev_assgt_id := c_leavers.assignment_id;
428 else
429 --
430 -- It's another record for the same assignment. Compare it with the
431 -- previous one: increment the counter if the assgt record does not
432 -- follow on immediately from the previous one. As the cursor only picks
433 -- up rows with one position_id, a gap in the dates means the position_id
434 -- must have just changed in the meantime. Also increment the counter
435 -- if the assgt status has changed to TERM_ASSIGN.
436 --
437 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',20) ;
438 if (c_leavers.effective_start_date - 1 <> l_prev_assgt_end) or
439 (c_leavers.per_system_status = 'TERM_ASSIGN' and
440 l_prev_assgt_status <> 'TERM_ASSIGN') then
441 x_leavers := x_leavers + c_leavers.value;
442 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',25) ;
443 end if;
444 end if;
445 --
446 -- Note end date and assgt status for comparison with the next rec. Also
447 -- save the assgt's budget value, as we may need it outside the cursor loop.
448 --
449 l_prev_assgt_end := c_leavers.effective_end_date;
450 l_prev_assgt_status := c_leavers.per_system_status;
451 l_prev_assgt_value := c_leavers.value;
452 --
453 END LOOP;
454
455 --
456 -- Now check the last record retrieved, in the same way we checked
457 -- records when the assgt id changed.
458 --
459 --
460 --
461 -- BUG. 572545. Removed call to TO_DATE() function for X_END_DATE.
462 -- PASHUN. 31-OCT-1997.
463 --
464 --
465 if (l_prev_assgt_id <> 0 and
466 l_prev_assgt_end <= x_end_date and
467 l_prev_assgt_status <> 'TERM_ASSIGN'
468 ) then
469 x_leavers := x_leavers + l_prev_assgt_value;
470 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',30) ;
471 end if;
472 hr_utility.set_location ( 'PER_POS_BGT_PKG.GET_LEAVERS',35) ;
473 --
474 END GET_LEAVERS;
475 --
476 --
477 -- PROCEDURE POPULATE_FIELDS: Calls all the other procedures within
478 -- the package allowing for only one
479 -- server side trip.
480 --
481 --
482 -- Changed datatype from VARCHAR2 to DATE for X_START_DATE and X_END_DATE.
483 -- PASHUN. 31-10-1997. BUG : 572545.
484 --
485 --
486
487 PROCEDURE POPULATE_FIELDS(X_VARIANCE IN OUT NUMBER,
488 X_LEAVERS IN OUT NUMBER,
489 X_STARTERS IN OUT NUMBER,
490 X_PERIOD_END IN OUT NUMBER,
491 X_PERIOD_START IN OUT NUMBER,
492 X_BUDGET_VALUE IN OUT NUMBER,
493 X_BUDGET_VALUE_ID IN OUT NUMBER,
494 X_POSITION_ID NUMBER,
495 X_BUSINESS_GROUP_ID NUMBER,
496 X_START_DATE DATE,
497 X_END_DATE DATE,
498 X_UNIT VARCHAR2,
499 X_BUDGET_VERSION_ID NUMBER,
500 X_TIME_PERIOD_ID NUMBER) IS
501 --
502 BEGIN
503 GET_LEAVERS(X_LEAVERS,
504 X_POSITION_ID,
505 X_BUSINESS_GROUP_ID ,
506 X_START_DATE ,
507 X_END_DATE ,
508 X_UNIT );
509 GET_STARTERS(X_STARTERS ,
510 X_POSITION_ID,
511 X_BUSINESS_GROUP_ID ,
512 X_START_DATE ,
513 X_END_DATE ,
514 X_UNIT );
515 GET_PERIOD_START(X_PERIOD_START ,
516 X_POSITION_ID,
517 X_BUSINESS_GROUP_ID ,
518 X_START_DATE ,
519 X_UNIT );
520 GET_PERIOD_END(X_PERIOD_END ,
521 X_POSITION_ID,
522 X_BUSINESS_GROUP_ID ,
523 X_END_DATE ,
524 X_UNIT );
525 IF X_BUDGET_VERSION_ID IS NOT NULL THEN
526 -- Can only obtain a budget value if a budget has been selected
527 -- in the control block
528 --
529 GET_BUDGET_VALUE(X_BUDGET_VALUE ,
530 X_BUDGET_VALUE_ID ,
531 X_POSITION_ID,
532 X_BUDGET_VERSION_ID ,
533 X_TIME_PERIOD_ID );
534 X_VARIANCE := X_PERIOD_END - X_BUDGET_VALUE;
535 END IF;
536 END POPULATE_FIELDS;
537 --
538 END PER_POS_BGT_PKG;