DBA Data[Home] [Help]

PACKAGE BODY: APPS.AHL_UC_POS_NECES_PVT

Source


1 PACKAGE BODY AHL_UC_POS_NECES_PVT AS
2 /* $Header: AHLVNECB.pls 120.2 2007/12/21 13:29:24 sathapli ship $ */
3 
4   G_PKG_NAME   CONSTANT  VARCHAR2(30) := 'AHL_UC_POS_NECES_PVT';
5 
6 
7 ----------------------------------------
8 -- Begin Local Procedures Declaration--
9 ----------------------------------------
10 -------------------------------------
11 -- End Local Procedures Declaration--
12 -------------------------------------
13 
14 ------------------------
15 -- Define  Procedures --
16 ------------------------
17 --------------------------------------------------------------------------------------------
18 --  Start of Comments  --
19 --
20 --  Procedure name  : List_Extra_Nodes
21 --  Type        	: Private
22 --  Function    	: List all the nodes in the unit configuration which are extra.
23 --                    i.e. with no corresponding position reference
24 --  Pre-reqs    	:
25 --
26 --  Standard IN  Parameters :
27 --      p_api_version                   IN      NUMBER                      Required
28 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
29 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
30 --  Standard OUT Parameters :
31 --      x_return_status                 OUT     VARCHAR2                    Required
32 --      x_msg_count                     OUT     NUMBER                      Required
33 --      x_msg_data                      OUT     VARCHAR2                    Required
34 --
35 --  List_Extra_Nodes parameters :
36 --  p_uc_header_id    	IN  NUMBER Required
37 --   			The header id of the unit configuration
38 --  p_csi_instance_id  IN NUMBER the starting intance id. It's the
39 --                    alternative to p_uc_header_id
40 --  x_evaluation_status OUT VARCHAR2
41 --                      The flag which indicates whether the unit has extra nodes or not.
42 -- p_x_error_table        IN OUT AHL_UC_POS_NECES_PVT.Error_Tbl_Type
43 --                      An output table with the list of all the extra nodes.
44 --
45 --  History:
46 --      05/19/03       SBethi       CREATED
47 --
48 --  Version :
49 --      Initial Version   1.0
50 --
51 --  End of Comments.
52 --------------------------------------------------------------------------------------------
53 
54 PROCEDURE List_Extra_Nodes(
55   p_api_version           IN  NUMBER,
56   p_init_msg_list         IN  VARCHAR2  := FND_API.G_TRUE,
57   p_validation_level      IN  NUMBER    := FND_API.G_VALID_LEVEL_FULL,
58   x_return_status         OUT NOCOPY VARCHAR2,
59   x_msg_count             OUT NOCOPY NUMBER,
60   x_msg_data              OUT NOCOPY VARCHAR2,
61   p_uc_header_id          IN  NUMBER,
62   p_csi_instance_id       IN  NUMBER,
63   p_x_error_table         IN OUT NOCOPY AHL_UC_VALIDATION_PUB.Error_Tbl_Type,
64   x_evaluation_status     OUT NOCOPY VARCHAR2
65   )
66   IS
67 ----
68  CURSOR get_uc_header_rec_csr(p_uc_header_id IN NUMBER) IS
69   SELECT csi_item_instance_id
70    FROM   ahl_unit_config_headers
71   WHERE  unit_config_header_id = p_uc_header_id
72   AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
73   AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
74 ---
75   --To get extra nodes
76   CURSOR get_extra_nodes_csr(p_csi_item_instance_id IN NUMBER) IS
77     SELECT subject_id
78     FROM   csi_ii_relationships
79     WHERE position_reference is null
80     START WITH object_id = p_csi_item_instance_id
81         AND relationship_type_code = 'COMPONENT-OF'
82         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
83         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
84     CONNECT BY PRIOR subject_id = object_id
85         AND relationship_type_code = 'COMPONENT-OF'
86         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
87         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
88 
89   --To get extra node children nodes
90   CURSOR get_extra_node_child_csr(p_csi_item_instance_id IN NUMBER) IS
91     SELECT subject_id
92     FROM   csi_ii_relationships
93     START WITH object_id = p_csi_item_instance_id
94         AND relationship_type_code = 'COMPONENT-OF'
95         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
96         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
97     CONNECT BY PRIOR subject_id = object_id
98         AND relationship_type_code = 'COMPONENT-OF'
99         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
100         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
101 --
102   CURSOR get_node_details_csr (p_csi_instance_id IN NUMBER) IS
103     SELECT M.concatenated_segments, C.serial_number
104       FROM csi_item_instances C,
105            mtl_system_items_kfv M
106      WHERE instance_id = p_csi_instance_id
107        AND M.inventory_item_id = C.inventory_item_id
108        AND M.organization_id = c.inv_master_organization_id;
109 --
110 --Extra nodes can not be top nodes, so no need to check that.
111  CURSOR get_unit_instance_csr  (p_csi_instance_id IN NUMBER) IS
112     SELECT object_id
113      FROM csi_ii_relationships
114      WHERE object_id IN
115       ( SELECT csi_item_instance_id
116 	 FROM ahl_unit_config_headers
117         WHERE trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
118           AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)))
119      START WITH subject_id = p_csi_instance_id
120         AND relationship_type_code = 'COMPONENT-OF'
121         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
122         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
123      CONNECT BY subject_id = PRIOR object_id
124         AND relationship_type_code = 'COMPONENT-OF'
125         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
126         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
127 --
128 --With unit instance id, fetch the unit name.
129 CURSOR get_node_unit_csr  (p_csi_instance_id IN NUMBER) IS
130  SELECT uch.name
131     FROM   ahl_unit_config_headers uch
132     WHERE uch.csi_item_instance_id=p_csi_instance_id;
133 
134 --
135     l_api_version      CONSTANT NUMBER := 1.0;
136     l_api_name         CONSTANT VARCHAR2(30) := 'List_Extra_Nodes';
137     l_top_instance_id    NUMBER;
138     l_csi_id             NUMBER;
139     l_unit_csi_id        NUMBER;
140     l_unit_name          ahl_unit_config_headers.name%TYPE;
141     l_item_number        mtl_system_items_kfv.concatenated_segments%TYPE;
142     l_serial_number      csi_item_instances.serial_number%TYPE;
143 --
144   BEGIN
145 
146   -- Standard call to check for call compatibility
147   IF NOT FND_API.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
148                                      G_PKG_NAME) THEN
149     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
150   END IF;
151 
152   -- Initialize message list if p_init_msg_list is set to TRUE
153   IF FND_API.To_Boolean(p_init_msg_list) THEN
154     FND_MSG_PUB.Initialize;
155   END IF;
156 
157   -- Initialize API return status to success
158   x_return_status := FND_API.G_RET_STS_SUCCESS;
159 
160   -- Begin Processing
161   x_evaluation_status := FND_API.G_TRUE;
162 
163 
164   --Call procedure to validate the uc header id
165   IF (p_csi_instance_id IS NOT NULL AND
166       p_uc_header_id IS NULL) THEN
167    l_top_instance_id := p_csi_instance_id;
168   ELSE
169    OPEN get_uc_header_rec_csr(p_uc_header_id);
170    FETCH get_uc_header_rec_csr INTO l_top_instance_id;
171    IF ( get_uc_header_rec_csr%NOTFOUND ) THEN
172       FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
173       FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
174       FND_MSG_PUB.add;
175       CLOSE get_uc_header_rec_csr;
176       RAISE FND_API.G_EXC_ERROR;
177    END IF;
178    CLOSE get_uc_header_rec_csr;
179   END IF;
180 
181   OPEN  get_extra_nodes_csr(l_top_instance_id);
182   LOOP
183      FETCH get_extra_nodes_csr into l_csi_id;
184      EXIT WHEN get_extra_nodes_csr%NOTFOUND;
185 
186 
187      --Fetch the instance details for the error message
188      OPEN get_node_details_csr(l_csi_id);
189      FETCH get_node_details_csr into l_item_number, l_serial_number;
190      CLOSE get_node_details_csr;
191 
192      OPEN get_unit_instance_csr(l_csi_id);
193      FETCH  get_unit_instance_csr into l_unit_csi_id;
194      IF (get_unit_instance_csr%FOUND) THEN
195         OPEN get_node_unit_csr(l_unit_csi_id);
196         FETCH  get_node_unit_csr into l_unit_name;
197         CLOSE get_node_unit_csr;
198      END IF;
199      CLOSE get_unit_instance_csr;
200 
201      --Build the error message
202      FND_MESSAGE.Set_Name('AHL','AHL_UC_EXTRA_NODE');
203      FND_MESSAGE.Set_Token('ITEM_NO', l_item_number);
204      FND_MESSAGE.Set_Token('SERIAL_NO', l_serial_number);
205      FND_MESSAGE.Set_Token('UNIT_NAME', l_unit_name);
206 
207      --Get the extra node childrens and list them.
208      OPEN  get_extra_node_child_csr(l_csi_id);
209      LOOP
210        FETCH get_extra_node_child_csr into l_csi_id;
211        EXIT WHEN get_extra_node_child_csr%NOTFOUND;
212 
213        --Fetch the instance details for the error message
214        OPEN get_node_details_csr(l_csi_id);
215        FETCH get_node_details_csr into l_item_number, l_serial_number;
216        CLOSE get_node_details_csr;
217 
218        --Build the error message
219        FND_MESSAGE.Set_Name('AHL','AHL_UC_EXTRA_NODE');
220        FND_MESSAGE.Set_Token('ITEM_NO', l_item_number);
221        FND_MESSAGE.Set_Token('SERIAL_NO', l_serial_number);
222        FND_MESSAGE.Set_Token('UNIT_NAME', l_unit_name);
223 
224      END LOOP;
225      CLOSE get_extra_node_child_csr;
226 
227      -- Write the error message to the error table.
228      IF (p_x_error_table.COUNT >0) THEN
229        p_x_error_table(p_x_error_table.LAST+1) := FND_MESSAGE.get;
230      ELSE
231        p_x_error_table(0) := FND_MESSAGE.get;
232      END IF;
233      x_evaluation_status := FND_API.G_FALSE;
234 
235   END LOOP;
236   CLOSE get_extra_nodes_csr;
237 
238   -- Check Error Message stack.
239   x_msg_count := FND_MSG_PUB.count_msg;
240   IF x_msg_count > 0 THEN
241     RAISE  FND_API.G_EXC_ERROR;
242   END IF;
243 
244   -- Standard call to get message count and if count is 1, get message info
245   FND_MSG_PUB.Count_And_Get
246     ( p_count => x_msg_count,
247       p_data  => x_msg_data,
248       p_encoded => fnd_api.g_false
249     );
250 
251   EXCEPTION
252     WHEN FND_API.G_EXC_ERROR THEN
253       x_return_status := FND_API.G_RET_STS_ERROR;
254       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
255                                  p_data  => x_msg_data,
256                                  p_encoded => fnd_api.g_false);
257     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
258       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
259       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
260                                  p_data  => x_msg_data,
261                                  p_encoded => fnd_api.g_false);
262     WHEN OTHERS THEN
263       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
264       FND_MSG_PUB.add_exc_msg( p_pkg_name       => G_PKG_NAME,
265                                p_procedure_name => l_api_name,
266                                p_error_text     => SQLERRM);
267 
268       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
269                                  p_data  => x_msg_data,
270                                  p_encoded => fnd_api.g_false);
271 
272 END List_Extra_Nodes;
273 
274 --------------------------------------------------------------------------------------------
275 --  Start of Comments  --
276 --
277 --  Procedure name  : Check_Extra_Nodes
278 --  Type        	: Private
279 --  Function    	: Checks if there are any extra nodes in a unit configuration.
280 --  Pre-reqs    	:
281 --
282 --  Standard IN  Parameters :
283 --      p_api_version                   IN      NUMBER                      Required
284 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
285 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
286 --  Standard OUT Parameters :
287 --      x_return_status                 OUT     VARCHAR2                    Required
288 --      x_msg_count                     OUT     NUMBER                      Required
289 --      x_msg_data                      OUT     VARCHAR2                    Required
290 --
291 --  check_extra_nodes parameters :
292 --  p_uc_header_id    	IN  Required
293 --   			The header id of the unit configuration
294 --  x_evaluation_status OUT VARCHAR2
295 --                      The flag which indicates whether the unit configuration
296 --                      has any extra nodes and returns FND_API.G_TRUE ot FND_API.G_FALSE accordingly.
297 --  History:
298 --      05/19/03       SBethi       CREATED
299 --
300 --  Version :
301 --      Initial Version   1.0
302 --
303 --  End of Comments.
304 --------------------------------------------------------------------------------------------
305 
306 PROCEDURE Check_Extra_Nodes(
307   p_api_version           IN  NUMBER,
308   p_init_msg_list         IN  VARCHAR2  := FND_API.G_TRUE,
309   p_validation_level      IN  NUMBER    := FND_API.G_VALID_LEVEL_FULL,
310   x_return_status         OUT NOCOPY VARCHAR2,
311   x_msg_count             OUT NOCOPY NUMBER,
312   x_msg_data              OUT NOCOPY VARCHAR2,
313   p_uc_header_id          IN  NUMBER,
314   x_evaluation_status     OUT NOCOPY VARCHAR2
315   )
316   IS
317 --
318  CURSOR get_uc_header_rec_csr(p_uc_header_id IN NUMBER) IS
319   SELECT csi_item_instance_id
320    FROM   ahl_unit_config_headers
321   WHERE  unit_config_header_id = p_uc_header_id
322   AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
323   AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
324 ---
325   --To get extra nodes
326   CURSOR get_extra_nodes_csr(p_csi_item_instance_id IN NUMBER) IS
327     SELECT 'X'
328     FROM   csi_ii_relationships
329     WHERE position_reference is null
330     START WITH object_id = p_csi_item_instance_id
331         AND relationship_type_code = 'COMPONENT-OF'
332         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
333         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
334     CONNECT BY PRIOR subject_id = object_id
335         AND relationship_type_code = 'COMPONENT-OF'
336         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
337         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
338 
339 --
340    l_api_version      CONSTANT NUMBER := 1.0;
341    l_api_name         CONSTANT VARCHAR2(30) := 'Check_Extra_Nodes';
342    l_top_instance_id   NUMBER;
343    l_dummy         VARCHAR2(1);
344 --
345 BEGIN
346 
347 
348   -- Standard call to check for call compatibility
349   IF NOT FND_API.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
350                                      G_PKG_NAME) THEN
351     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
352   END IF;
353 
354     -- Initialize message list if p_init_msg_list is set to TRUE
355   IF FND_API.To_Boolean(p_init_msg_list) THEN
356     FND_MSG_PUB.Initialize;
357   END IF;
358 
359   -- Initialize API return status to success
360   x_return_status := FND_API.G_RET_STS_SUCCESS;
361 
362   -- Begin Processing
363  --Call procedure to validate the uc header id
364   OPEN get_uc_header_rec_csr(p_uc_header_id);
365   FETCH get_uc_header_rec_csr INTO l_top_instance_id;
366   IF ( get_uc_header_rec_csr%NOTFOUND ) THEN
367       FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
368       FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
369       FND_MSG_PUB.add;
370       CLOSE get_uc_header_rec_csr;
371       RAISE FND_API.G_EXC_ERROR;
372   END IF;
373   CLOSE get_uc_header_rec_csr;
374 
375 
376   OPEN  get_extra_nodes_csr(l_top_instance_id);
377   FETCH get_extra_nodes_csr INTO l_dummy;
378   IF (get_extra_nodes_csr%FOUND) THEN
379     x_evaluation_status := FND_API.G_FALSE;
380   ELSE
381     x_evaluation_status := FND_API.G_TRUE;
382   END IF;
383   CLOSE get_extra_nodes_csr;
384   --Completed Processing
385 
386   -- Check Error Message stack.
387   x_msg_count := FND_MSG_PUB.count_msg;
388   IF x_msg_count > 0 THEN
389     RAISE  FND_API.G_EXC_ERROR;
390   END IF;
391 
392   -- Standard call to get message count and if count is 1, get message info
393   FND_MSG_PUB.Count_And_Get
394     ( p_count => x_msg_count,
395       p_data  => x_msg_data,
396       p_encoded => fnd_api.g_false
397     );
398   EXCEPTION
399     WHEN FND_API.G_EXC_ERROR THEN
400       x_return_status := FND_API.G_RET_STS_ERROR;
401       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
402                                  p_data  => x_msg_data,
403                                  p_encoded => fnd_api.g_false);
404     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
405       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
406       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
407                                  p_data  => x_msg_data,
408                                  p_encoded => fnd_api.g_false);
409     WHEN OTHERS THEN
410       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
411       FND_MSG_PUB.add_exc_msg( p_pkg_name       => G_PKG_NAME,
412                                p_procedure_name => l_api_name,
413                                p_error_text     => SQLERRM);
414 
415       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
416                                  p_data  => x_msg_data,
417                                  p_encoded => fnd_api.g_false);
418 END Check_Extra_Nodes;
419 
420 --------------------------------------------------------------------------------------------
421 --  Start of Comments  --
422 --
423 --  Procedure name  : Check_Missing_Positions
424 --  Type        	: Private
425 --  Function    	: List all the checks if the unit config has any missing
426 --                    positions.
427 --  Pre-reqs    	:
428 --
429 --  Standard IN  Parameters :
430 --      p_api_version                   IN      NUMBER                      Required
431 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
432 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
433 --  Standard OUT Parameters :
434 --      x_return_status                 OUT     VARCHAR2                    Required
435 --      x_msg_count                     OUT     NUMBER                      Required
436 --      x_msg_data                      OUT     VARCHAR2                    Required
437 --
438 --  list_missing_positions parameters :
439 --  p_uc_header_id    	IN  Required
440 --   			The header id of the unit configuration
441 --  x_evaluation_status OUT VARCHAR2
442 --                      The flag which indicates whether the unit configuration
443 --                      has any missing positions and returns FND_API.G_TRUE ot FND_API.G_FALSE accordingly.
444 --  History:
445 --      05/19/03       SBethi       CREATED
446 --
447 --  Version :
448 --      Initial Version   1.0
449 --
450 --  End of Comments.
451 --------------------------------------------------------------------------------------------
452 
453 PROCEDURE Check_Missing_Positions(
454   p_api_version           IN  NUMBER,
455   p_init_msg_list         IN  VARCHAR2  := FND_API.G_TRUE,
456   p_validation_level      IN  NUMBER    := FND_API.G_VALID_LEVEL_FULL,
457   x_return_status         OUT NOCOPY VARCHAR2,
458   x_msg_count             OUT NOCOPY NUMBER,
459   x_msg_data              OUT NOCOPY VARCHAR2,
460   p_uc_header_id          IN  NUMBER,
461   x_evaluation_status     OUT NOCOPY VARCHAR2
462   )
463   IS
464 --
465  CURSOR get_uc_header_rec_csr(p_uc_header_id IN NUMBER) IS
466   SELECT csi_item_instance_id
467    FROM   ahl_unit_config_headers
468   WHERE  unit_config_header_id = p_uc_header_id
469   AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
470   AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
471 --
472 --Get all of the unit's instances/positions that are NOT extra nodes
473 CURSOR get_unit_tree_csr(c_csi_instance_id IN NUMBER) IS
474   SELECT c_csi_instance_id FROM dual
475  UNION ALL
476   SELECT subject_id
477     FROM   csi_ii_relationships
478     START WITH object_id = c_csi_instance_id
479         AND relationship_type_code = 'COMPONENT-OF'
480         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
481         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
482     CONNECT BY PRIOR subject_id = object_id
483         AND relationship_type_code = 'COMPONENT-OF'
484         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
485         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
486         AND position_reference is not null;
487 
488 
489 --Get the relationship id if instance is a uc header
490 CURSOR get_relnship_id_csr(c_csi_instance_id IN  NUMBER) IS
491   SELECT  mc.relationship_id
492     FROM  ahl_unit_config_headers uc, ahl_mc_relationships mc
493     WHERE uc.master_config_id = mc.mc_header_id
494        AND mc.parent_relationship_id is null
495        AND uc.csi_item_instance_id = c_csi_instance_id
496        AND trunc(nvl(uc.active_start_date,sysdate)) <= trunc(sysdate)
497        AND trunc(sysdate) < trunc(nvl(uc.active_end_date, sysdate+1));
498 
499 --If instance is not uc header, then get it based on instance
500 CURSOR get_pos_ref_reln_csr (c_csi_instance_id IN NUMBER) IS
501   SELECT TO_NUMBER(position_reference)
502    FROM csi_ii_relationships csi
503   WHERE position_reference is not null
504     AND  subject_id = c_csi_instance_id
505     AND relationship_type_code = 'COMPONENT-OF'
506     AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
507     AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
508 
509 --
510 --Check mandatory children
511  CURSOR check_mand_child_missing_csr(c_relationship_id IN NUMBER,
512 				    c_parent_instance_id IN NUMBER) IS
513      SELECT 'X'
514      FROM ahl_mc_relationships mc
515      WHERE mc.parent_relationship_id = c_relationship_id
516        AND mc.position_necessity_code = 'MANDATORY'
517        AND trunc(nvl(mc.active_start_date,sysdate)) <= trunc(sysdate)
518        AND trunc(sysdate) < trunc(nvl(mc.active_end_date, sysdate+1))
519        AND  NOT EXISTS (
520        SELECT 'X'
521          FROM   csi_ii_relationships csi
522         WHERE  object_id = c_parent_instance_id
523           AND TO_NUMBER(position_reference) = mc.relationship_id
524           AND relationship_type_code = 'COMPONENT-OF'
525           AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
526           AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)));
527 --
528     l_api_version      CONSTANT NUMBER := 1.0;
529     l_api_name         CONSTANT VARCHAR2(30) := 'Check_Missing_Positions';
530     l_top_instance_id  NUMBER;
531     l_csi_ii_id        NUMBER;
532     l_rel_id           NUMBER;
533     l_dummy                VARCHAR2(1);
534 --
535 BEGIN
536 
537 
538   -- Standard call to check for call compatibility
539   IF NOT FND_API.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
540                                      G_PKG_NAME) THEN
541     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
542   END IF;
543 
544     -- Initialize message list if p_init_msg_list is set to TRUE
545   IF FND_API.To_Boolean(p_init_msg_list) THEN
546     FND_MSG_PUB.Initialize;
547   END IF;
548 
549   -- Initialize API return status to success
550   x_return_status := FND_API.G_RET_STS_SUCCESS;
551   x_evaluation_status := FND_API.G_TRUE;
552 
553   -- Begin Processing
554   --Call procedure to validate the uc header id
555   OPEN get_uc_header_rec_csr(p_uc_header_id);
556   FETCH get_uc_header_rec_csr INTO l_top_instance_id;
557   IF ( get_uc_header_rec_csr%NOTFOUND ) THEN
558       FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
559       FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
560       FND_MSG_PUB.add;
561       CLOSE get_uc_header_rec_csr;
562       RAISE FND_API.G_EXC_ERROR;
563   END IF;
564   CLOSE get_uc_header_rec_csr;
565 
566   OPEN  get_unit_tree_csr(l_top_instance_id);
567   <<l_unit_tree_loop>>
568   LOOP
569    FETCH get_unit_tree_csr into l_csi_ii_id;
570     EXIT WHEN get_unit_tree_csr%NOTFOUND;
571 
572     --Fetch instance position if it is subunit
573     OPEN get_relnship_id_csr(l_csi_ii_id);
574     FETCH get_relnship_id_csr INTO l_rel_id;
575 
576     --If not subunit, just fetch assuming instance.
577     IF (get_relnship_id_csr%NOTFOUND) THEN
578        OPEN get_pos_ref_reln_csr(l_csi_ii_id);
579        FETCH get_pos_ref_reln_csr INTO l_rel_id;
580        CLOSE get_pos_ref_reln_csr;
581     END IF;
582     CLOSE get_relnship_id_csr;
583 
584     -- Check if all the mandatory positions have item instances mapped.
585     OPEN  check_mand_child_missing_csr( l_rel_id,l_csi_ii_id);
586     FETCH check_mand_child_missing_csr INTO l_dummy;
587 
588     --If found, then there are missing positions
589     IF (check_mand_child_missing_csr%FOUND) THEN
590         x_evaluation_status := FND_API.G_FALSE;
591         EXIT l_unit_tree_loop;
592     END IF;
593     CLOSE check_mand_child_missing_csr;
594 
595   END LOOP;
596   CLOSE get_unit_tree_csr;
597 
598   --Completed Processing
599 
600   -- Check Error Message stack.
601   x_msg_count := FND_MSG_PUB.count_msg;
602   IF x_msg_count > 0 THEN
603     RAISE  FND_API.G_EXC_ERROR;
604   END IF;
605 
606   -- Standard call to get message count and if count is 1, get message info
607   FND_MSG_PUB.Count_And_Get
608     ( p_count => x_msg_count,
609       p_data  => x_msg_data,
610       p_encoded => fnd_api.g_false
611     );
612 
613 
614   EXCEPTION
615     WHEN FND_API.G_EXC_ERROR THEN
616       x_return_status := FND_API.G_RET_STS_ERROR;
617       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
618                                  p_data  => x_msg_data,
619                                  p_encoded => fnd_api.g_false);
620 
621     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
622       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
623       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
624                                  p_data  => x_msg_data,
625                                  p_encoded => fnd_api.g_false);
626 
627     WHEN OTHERS THEN
628       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
629       FND_MSG_PUB.add_exc_msg( p_pkg_name       => G_PKG_NAME,
630                                p_procedure_name => l_api_name,
631                                p_error_text     => SQLERRM);
632 
633       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
634                                  p_data  => x_msg_data,
635                                  p_encoded => fnd_api.g_false);
636 
637 END Check_Missing_Positions;
638 
639 --------------------------------------------------------------------------------------------
640 --  Start of Comments  --
641 --
642 --  Procedure name  : List_Missing_Positions
643 --  Type        	: Private
644 --  Function    	: List all the mandatory positions that dont have instances mapped to it.
645 --  Pre-reqs    	:
646 --
647 --  Standard IN  Parameters :
648 --      p_api_version                   IN      NUMBER                      Required
649 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
650 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
651 --  Standard OUT Parameters :
652 --      x_return_status                 OUT     VARCHAR2                    Required
653 --      x_msg_count                     OUT     NUMBER                      Required
654 --      x_msg_data                      OUT     VARCHAR2                    Required
655 --
656 --  list_missing_positions parameters :
657 --  p_uc_header_id    	IN  Required
658 --   			The header id of the unit configuration
659 --  x_evaluation_status OUT VARCHAR2
660 --                      The flag which indicates whether the unit has any missing positions
661 --  History:
662 --      05/19/03       SBethi       CREATED
663 --
664 --  Version :
665 --      Initial Version   1.0
666 --
667 --  End of Comments.
668 --------------------------------------------------------------------------------------------
669 
670 PROCEDURE List_Missing_Positions(
671   p_api_version           IN  NUMBER,
672   p_init_msg_list         IN  VARCHAR2  := FND_API.G_TRUE,
673   p_validation_level      IN  NUMBER    := FND_API.G_VALID_LEVEL_FULL,
674   x_return_status         OUT NOCOPY VARCHAR2,
675   x_msg_count             OUT NOCOPY NUMBER,
676   x_msg_data              OUT NOCOPY VARCHAR2,
677   p_uc_header_id          IN  NUMBER,
678   p_csi_instance_id       IN  NUMBER,
679   p_x_error_table         IN  OUT NOCOPY AHL_UC_VALIDATION_PUB.Error_Tbl_Type,
680   x_evaluation_status     OUT NOCOPY VARCHAR2
681   )  IS
682 ----
683  CURSOR get_uc_header_rec_csr(p_uc_header_id IN NUMBER) IS
684   SELECT csi_item_instance_id
685    FROM   ahl_unit_config_headers
686   WHERE  unit_config_header_id = p_uc_header_id
687   AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
688   AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
689 --
690 --Get all of the unit's instances/positions. Get all non-extra nodes
691 CURSOR get_unit_tree_csr(c_csi_instance_id IN NUMBER) IS
692   SELECT c_csi_instance_id FROM dual
693  UNION ALL
694   SELECT subject_id
695     FROM   csi_ii_relationships
696     START WITH object_id = c_csi_instance_id
697         AND relationship_type_code = 'COMPONENT-OF'
698         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
699         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
700     CONNECT BY PRIOR subject_id = object_id
701         AND relationship_type_code = 'COMPONENT-OF'
702         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
703         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
704 	AND position_reference is not null;
705 
706 --Get the relationship id if instance is a uc header
707 CURSOR get_relnship_id_csr(c_csi_instance_id IN  NUMBER) IS
708   SELECT  mc.relationship_id
709     FROM  ahl_unit_config_headers uc, ahl_mc_relationships mc
710     WHERE uc.master_config_id = mc.mc_header_id
711        AND mc.parent_relationship_id is null
712        AND uc.csi_item_instance_id = c_csi_instance_id
713        AND trunc(nvl(uc.active_start_date,sysdate)) <= trunc(sysdate)
714        AND trunc(sysdate) < trunc(nvl(uc.active_end_date, sysdate+1));
715 
716 --If instance is not uc header, then get it based on instance
717 CURSOR get_pos_ref_reln_csr (c_csi_instance_id IN NUMBER) IS
718   SELECT TO_NUMBER(position_reference)
719    FROM csi_ii_relationships csi
720   WHERE position_reference is not null
721     AND  subject_id = c_csi_instance_id
722     AND relationship_type_code = 'COMPONENT-OF'
723     AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
724     AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
725 
726 --
727 --Check mandatory children
728  CURSOR check_mand_child_missing_csr(c_relationship_id IN NUMBER,
729 				    c_parent_instance_id IN NUMBER) IS
730      SELECT mc.relationship_id, mc.position_ref_code
731      FROM ahl_mc_relationships mc
732      WHERE mc.parent_relationship_id = c_relationship_id
733        AND mc.position_necessity_code = 'MANDATORY'
734        AND trunc(nvl(mc.active_start_date,sysdate)) <= trunc(sysdate)
735        AND trunc(sysdate) < trunc(nvl(mc.active_end_date, sysdate+1))
736        AND  NOT EXISTS (
737        SELECT 'X'
738          FROM   csi_ii_relationships csi
739         WHERE  object_id = c_parent_instance_id
740           AND TO_NUMBER(position_reference) = mc.relationship_id
741           AND relationship_type_code = 'COMPONENT-OF'
742           AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
743           AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)));
744 --
745    --Get mandatory children for missing position
746    CURSOR get_mand_pos_desc_csr(c_relationship_id IN  NUMBER) IS
747      SELECT  position_ref_code
748      FROM ahl_mc_relationships
749      START WITH parent_relationship_id = c_relationship_id
750         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
751         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
752      CONNECT BY PRIOR relationship_id = parent_relationship_id
753         AND trunc(nvl(active_start_date,sysdate)) <= trunc(sysdate)
754         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
755         AND position_necessity_code = 'MANDATORY';
756 --
757     l_api_version      CONSTANT NUMBER := 1.0;
758     l_api_name         CONSTANT VARCHAR2(30) := 'List_Missing_Positions';
759     l_top_instance_id  NUMBER;
760     l_csi_ii_id        NUMBER;
761     l_rel_id           NUMBER;
762     l_miss_rel_id      NUMBER;
763     l_return_val         BOOLEAN DEFAULT TRUE;
764     l_pos_ref_code   fnd_lookups.lookup_code%TYPE;
765     l_pos_ref_meaning   fnd_lookups.meaning%TYPE;
766 
767 BEGIN
768 
769   -- Standard call to check for call compatibility
770   IF NOT FND_API.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
771                                      G_PKG_NAME) THEN
772     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
773   END IF;
774 
775     -- Initialize message list if p_init_msg_list is set to TRUE
776   IF FND_API.To_Boolean(p_init_msg_list) THEN
777     FND_MSG_PUB.Initialize;
778   END IF;
779 
780   -- Initialize API return status to success
781   x_return_status := FND_API.G_RET_STS_SUCCESS;
782   --Setting output parameters
783   x_evaluation_status := FND_API.G_TRUE;
784 
785   -- Begin Processing
786   IF (p_csi_instance_id IS NOT NULL AND
787       p_uc_header_id IS NULL) THEN
788    l_top_instance_id := p_csi_instance_id;
789   ELSE
790    --Call procedure to validate the uc header id
791    OPEN get_uc_header_rec_csr(p_uc_header_id);
792    FETCH get_uc_header_rec_csr INTO l_top_instance_id;
793    IF ( get_uc_header_rec_csr%NOTFOUND ) THEN
794       FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
795       FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
796       FND_MSG_PUB.add;
797       CLOSE get_uc_header_rec_csr;
798       RAISE FND_API.G_EXC_ERROR;
799    END IF;
800    CLOSE get_uc_header_rec_csr;
801   END IF;
802 
803   OPEN  get_unit_tree_csr(l_top_instance_id);
804   LOOP
805     FETCH get_unit_tree_csr into l_csi_ii_id;
806     EXIT WHEN get_unit_tree_csr%NOTFOUND;
807 
808     --Fetch instance position if it is subunit
809     OPEN get_relnship_id_csr(l_csi_ii_id);
810     FETCH get_relnship_id_csr INTO l_rel_id;
811 
812     --If not subunit, just fetch assuming instance.
813     IF (get_relnship_id_csr%NOTFOUND) THEN
814        OPEN get_pos_ref_reln_csr(l_csi_ii_id);
815        FETCH get_pos_ref_reln_csr INTO l_rel_id;
816        CLOSE get_pos_ref_reln_csr;
817     END IF;
818     CLOSE get_relnship_id_csr;
819 
820     -- Check if all the mandatory positions have item instances mapped.
821     OPEN  check_mand_child_missing_csr(l_rel_id, l_csi_ii_id);
822     LOOP
823        FETCH check_mand_child_missing_csr INTO l_miss_rel_id, l_pos_ref_code;
824        EXIT WHEN check_mand_child_missing_csr%NOTFOUND;
825 
826        AHL_UTIL_MC_PKG.Convert_To_LookupMeaning('AHL_POSITION_REFERENCE',
827                                                  l_pos_ref_code,
828                                                  l_pos_ref_meaning,
829                                                  l_return_val);
830         IF NOT(l_return_val) THEN
831             l_pos_ref_meaning := l_pos_ref_code;
832         END IF;
833 
834         --Building the error message
835         FND_MESSAGE.Set_Name('AHL','AHL_UC_NOTASSIGN_MANDATORY');
836         FND_MESSAGE.Set_Token('POSN_REF',l_pos_ref_meaning);
837 
838         --Writing the message to the error table
839         IF (p_x_error_table.COUNT >0) THEN
840            p_x_error_table(p_x_error_table.LAST+1) := FND_MESSAGE.get;
841         ELSE
842            p_x_error_table(0) := FND_MESSAGE.get;
843         END IF;
844 
845         x_evaluation_status := FND_API.G_FALSE;
846 
847         --Now fetch the mandatory descendents of the mandatory position
848         OPEN get_mand_pos_desc_csr(l_miss_rel_id);
849         LOOP
850           FETCH get_mand_pos_desc_csr INTO l_pos_ref_code;
851           EXIT WHEN get_mand_pos_desc_csr%NOTFOUND;
852 
853           AHL_UTIL_MC_PKG.Convert_To_LookupMeaning('AHL_POSITION_REFERENCE',
854                                                   l_pos_ref_code,
855                                                   l_pos_ref_meaning,
856                                                   l_return_val);
857           IF NOT(l_return_val) THEN
858              l_pos_ref_meaning := l_pos_ref_code;
859           END IF;
860 
861           --Building the error message
862           FND_MESSAGE.Set_Name('AHL','AHL_UC_NOTASSIGN_MANDATORY');
863           FND_MESSAGE.Set_Token('POSN_REF',l_pos_ref_meaning);
864 
865           --Writing the message to the error table
866            IF (p_x_error_table.COUNT >0) THEN
867             p_x_error_table(p_x_error_table.LAST+1) := FND_MESSAGE.get;
868           ELSE
869            p_x_error_table(0) := FND_MESSAGE.get;
870           END IF;
871 
872         END LOOP;
873 	CLOSE get_mand_pos_desc_csr;
874 
875     END LOOP; -- End of missing mandatory nodes
876     CLOSE check_mand_child_missing_csr;
877 
878  END LOOP;
879  CLOSE get_unit_tree_csr;
880 
881   --Completed Processing
882 
883   -- Check Error Message stack.
884   x_msg_count := FND_MSG_PUB.count_msg;
885   IF x_msg_count > 0 THEN
886     RAISE  FND_API.G_EXC_ERROR;
887   END IF;
888 
889   -- Standard call to get message count and if count is 1, get message info
890   FND_MSG_PUB.Count_And_Get
891     ( p_count => x_msg_count,
892       p_data  => x_msg_data,
893       p_encoded => fnd_api.g_false
894     );
895 
896 
897   EXCEPTION
898     WHEN FND_API.G_EXC_ERROR THEN
899       x_return_status := FND_API.G_RET_STS_ERROR;
900       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
901                                  p_data  => x_msg_data,
902                                  p_encoded => fnd_api.g_false);
903     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
904       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
905       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
906                                  p_data  => x_msg_data,
907                                  p_encoded => fnd_api.g_false);
908     WHEN OTHERS THEN
909       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
910       FND_MSG_PUB.add_exc_msg( p_pkg_name       => G_PKG_NAME,
911                                p_procedure_name => l_api_name,
912                                p_error_text     => SQLERRM);
913 
914       FND_MSG_PUB.count_and_get( p_count => x_msg_count,
915                                  p_data  => x_msg_data,
916                                  p_encoded => fnd_api.g_false);
917 END List_Missing_Positions;
918 
919 -- SATHAPLI::FP OGMA Issue# 105 - Non-Serialized Item Maintenance, 05-Dec-2007
920 -- This procedure adds a Quantity specific message to the Error Table.
921 PROCEDURE Add_Qty_Message(p_position_ref_code IN     VARCHAR2,
922                           p_inst_qty          IN     NUMBER,
923                           p_qty_less_flag     IN     VARCHAR2,
924                           p_x_error_table     IN OUT NOCOPY AHL_UC_VALIDATION_PUB.Error_Tbl_Type) IS
925 
926 l_return_val      BOOLEAN DEFAULT TRUE;
927 l_pos_ref_code    fnd_lookups.lookup_code%TYPE;
928 l_pos_ref_meaning fnd_lookups.meaning%TYPE;
929 
930 BEGIN
931   AHL_UTIL_MC_PKG.Convert_To_LookupMeaning('AHL_POSITION_REFERENCE',
932                                            p_position_ref_code,
933                                            l_pos_ref_meaning,
934                                            l_return_val);
935   IF NOT(l_return_val) THEN
936     l_pos_ref_meaning := p_position_ref_code;
937   END IF;
938   -- Build the error message
939   IF (p_qty_less_flag = 'Y') THEN
940     FND_MESSAGE.Set_Name('AHL', 'AHL_UC_POS_QTY_LESS');
941   ELSE
942     FND_MESSAGE.Set_Name('AHL', 'AHL_UC_POS_QTY_MORE');
943   END IF;
944   FND_MESSAGE.Set_Token('POSN_REF', l_pos_ref_meaning);
945   --Writing the message to the error table
946   IF (p_x_error_table.COUNT > 0) THEN
947     p_x_error_table(p_x_error_table.LAST + 1) := FND_MESSAGE.get;
948   ELSE
949     p_x_error_table(0) := FND_MESSAGE.get;
950   END IF;
951 
952 END Add_Qty_Message;
953 
954 -- SATHAPLI::FP OGMA Issue# 105 - Non-Serialized Item Maintenance, 05-Dec-2007
955 -- This function checks if a Quantity type rule exists for the given instance's position
956 -- p_instance_id is the Parent Instance and is used to derive the Position Path to Rule Existence Check.
957 -- It returns 'Y' if a rule exists and 'N' if not.
958 FUNCTION Quantity_Rule_Exists(p_instance_id IN NUMBER) RETURN VARCHAR2 IS
959 
960   CURSOR rule_exists_csr IS
961   SELECT distinct rul.rule_id, rul.rule_name, rul.mc_header_id
962   FROM AHL_MC_RULES_B rul, AHL_MC_RULE_STATEMENTS rst,
963        AHL_APPLICABLE_INSTANCES ap
964    WHERE  rst.rule_id = rul.rule_id
965      AND rul.rule_type_code = 'MANDATORY'
966      AND rst.subject_type = 'POSITION'
967      AND rst.subject_id =  ap.position_id
968      AND rst.object_type = 'TOT_CHILD_QUANTITY'
969      AND rst.operator = 'MUST_HAVE'
970      AND TRUNC(nvl(rul.ACTIVE_START_DATE, sysdate-1)) <= TRUNC(sysdate)
971      AND TRUNC(nvl(rul.ACTIVE_END_DATE, sysdate+1)) > TRUNC(sysdate);
972 
973   --check that the instance is installed in a UC derived from the Rule's MC_HEADER_ID
974   CURSOR check_inst_in_uc_ofmc_csr(c_csi_instance_id IN NUMBER, c_mc_header_id IN NUMBER) IS
975   SELECT uch.csi_item_instance_id
976    FROM ahl_unit_config_headers uch
977    WHERE uch.master_config_id = c_mc_header_id
978    AND uch.csi_item_instance_id = c_csi_instance_id
979   UNION ALL
980   SELECT csi_ii.object_id
981     FROM csi_ii_relationships csi_ii
982     WHERE csi_ii.object_id IN
983     (SELECT csi_item_instance_id
984      FROM ahl_unit_config_headers
985           WHERE trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
986             AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
987       AND  master_config_id = c_mc_header_id)
988     START WITH csi_ii.subject_id = c_csi_instance_id
989       AND CSI_II.RELATIONSHIP_TYPE_CODE  = 'COMPONENT-OF'
990       AND TRUNC(nvl(CSI_II.ACTIVE_START_DATE, sysdate)) <= TRUNC(sysdate)
991       AND TRUNC(nvl(CSI_II.ACTIVE_END_DATE, sysdate+1)) > TRUNC(sysdate)
992     CONNECT BY csi_ii.subject_id = PRIOR csi_ii.object_id
993       AND CSI_II.RELATIONSHIP_TYPE_CODE  = 'COMPONENT-OF'
994       AND TRUNC(nvl(CSI_II.ACTIVE_START_DATE, sysdate)) <= TRUNC(sysdate)
995       AND TRUNC(nvl(CSI_II.ACTIVE_END_DATE, sysdate+1)) > TRUNC(sysdate);
996 
997   l_return_status     VARCHAR2(1);
998   l_msg_count         NUMBER;
999   l_msg_data          VARCHAR2(2000);
1000   l_path_position_id  NUMBER;
1001   l_rule_id           NUMBER;
1002   l_rule_name         AHL_MC_RULES_B.RULE_NAME%TYPE;
1003   l_rule_uc_top_inst_id NUMBER;
1004   l_ret_val           VARCHAR2(1) DEFAULT 'N';
1005   l_mc_header_id      NUMBER;
1006   L_DEBUG_KEY         VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.Quantity_Rule_Exists';
1007 
1008 BEGIN
1009   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1010     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.begin',
1011                    'At the start of the function, p_instance_id = ' || p_instance_id);
1012   END IF;
1013   EXECUTE IMMEDIATE 'DELETE FROM AHL_APPLICABLE_INSTANCES';
1014   -- Get all the Position Paths associated with the instance p_instance_id into AHL_APPLICABLE_INSTANCES.
1015   -- If there is a configuration like A.1-B.1-C.1 and path positions exist for C.1, B.1-C.1, A.1-B.1-C.1 all these
1016   -- will be picked up after the call below
1017   AHL_MC_PATH_POSITION_PVT.Map_Instance_To_Positions(p_api_version => 1.0,
1018                          x_return_status => l_return_status,
1019                          x_msg_count => l_msg_count,
1020                          x_msg_data => l_msg_data,
1021                          p_csi_item_instance_id => p_instance_id);
1022 
1023   -- Check that a quantity rule exists at the installed poisition
1024   /*
1025     1. The rule_exists_csr returns all the rules for each of the path position applicable to the instance. Consider the case where
1026     a rule is defined for the position A.1-B.1-C.1 and it is NON-version specific for all the segments.
1027     For a case like A.2-B.2-C.2, the rule_exists_csr returns records. But this rule is actually applicable only to
1028     A.1-B.X-C.X. We check in the check_inst_in_uc_ofmc_csr that the instance under examination is derived from an UC got from an MC for which the rule is defined.
1029 
1030     2. Additionally, say we have a rule 'RULE1' defined at B.1-C.X and a rule RULE2 defined at C.1 (as NON version specific)
1031     RULE1 will be applicable for B.1-C.2, but RULE2 will not be applicable to B.1-C.2
1032     But rule_exists_csr, will return both of the above rules when looking at B.1-C.2. But check_inst_in_uc_ofmc_csr will filter out
1033     RULE2 as we want.
1034   */
1035   OPEN rule_exists_csr;
1036   LOOP
1037     FETCH rule_exists_csr INTO l_rule_id, l_rule_name, l_mc_header_id;
1038     EXIT WHEN rule_exists_csr%NOTFOUND;
1039 
1040     IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1041       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1042                     'Quantity Type Rule Exists: l_rule_id: ' || l_rule_id ||
1043                     ', l_mc_header_id: ' || l_mc_header_id ||
1044                     ', l_rule_name: ' || l_rule_name);
1045     END IF;
1046 
1047     OPEN check_inst_in_uc_ofmc_csr(p_instance_id, l_mc_header_id);
1048     FETCH check_inst_in_uc_ofmc_csr INTO l_rule_uc_top_inst_id;
1049 
1050     --Verify that the rule is applicable to currently installed instance
1051     IF (check_inst_in_uc_ofmc_csr%FOUND) THEN
1052       IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1053         FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1054                       'Rule is applicable to the UC top instance: l_rule_uc_top_inst_id: ' || l_rule_uc_top_inst_id);
1055       END IF;
1056       l_ret_val := 'Y';
1057       CLOSE check_inst_in_uc_ofmc_csr;
1058       --It is enough if there exists at least one quantity rule for the position.
1059       EXIT;
1060     END IF;
1061     CLOSE check_inst_in_uc_ofmc_csr;
1062   END LOOP;
1063   CLOSE rule_exists_csr;
1064 
1065   IF (l_ret_val = 'N') THEN
1066     IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1067       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY, 'Quantity Rule does not exist?');
1068     END IF;
1069   END IF;
1070 
1071   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1072     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.end',
1073                    'At the end of the function, About to return ' || l_ret_val);
1074   END IF;
1075   RETURN l_ret_val;
1076 END Quantity_Rule_Exists;
1077 
1078 --------------------------------------------------------------------------------------------
1079 --  Start of Comments  --
1080 --
1081 --  Procedure name      : Validate_Position_Quantities
1082 --  Type                : Private
1083 --  Function            : This procedure was added for the FP OGMA Issue 105 to support Non Serialized Items.
1084 --                        It validates the instance quantity against the position/item group.
1085 --                        If there is a Quantity type rule at the Parent position, the floor validation
1086 --                        is not done (Only ceiling validation is done). Since in this case the Rule
1087 --                        overrides and obviates any need for Quantity validation and validating quantity
1088 --                        based on position may actually contradict the rule.
1089 --
1090 --  Pre-reqs
1091 --
1092 --  Standard IN  Parameters :
1093 --      p_api_version                   IN      NUMBER                      Required
1094 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
1095 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
1096 --  Standard OUT Parameters :
1097 --      x_return_status                 OUT     VARCHAR2                    Required
1098 --      x_msg_count                     OUT     NUMBER                      Required
1099 --      x_msg_data                      OUT     VARCHAR2                    Required
1100 --
1101 --  Validate_Position_Quantities Parameters :
1102 --  p_uc_header_id                      IN      NUMBER     Conditionally Required
1103 --                   The header id of the unit configuration. Not required if p_csi_instance_id is given.
1104 --  p_csi_instance_id                   IN      NUMBER     Conditionally Required
1105 --                   The instance where the Quantity needs to be checked.  Not required if p_uc_header_id is given.
1106 --  x_evaluation_status                 OUT     VARCHAR2   The flag which indicates whether the unit has any Quantity mismatch.
1107 --  p_x_error_table                     IN OUT  AHL_UC_POS_NECES_PVT.Error_Tbl_Type
1108 --                   The output table with the list of Quantity based validation failures
1109 --
1110 --  History:
1111 --    05-Dec-2007       SATHAPLI       Created
1112 --
1113 --  Version:
1114 --      Initial Version   1.0
1115 --
1116 --  End of Comments.
1117 --------------------------------------------------------------------------------------------
1118 
1119 PROCEDURE Validate_Position_Quantities(
1120   p_api_version           IN            NUMBER,
1121   p_init_msg_list         IN            VARCHAR2 := FND_API.G_TRUE,
1122   p_validation_level      IN            NUMBER   := FND_API.G_VALID_LEVEL_FULL,
1123   x_return_status         OUT NOCOPY    VARCHAR2,
1124   x_msg_count             OUT NOCOPY    NUMBER,
1125   x_msg_data              OUT NOCOPY    VARCHAR2,
1126   p_uc_header_id          IN            NUMBER,
1127   p_csi_instance_id       IN            NUMBER,
1128   p_x_error_table         IN OUT NOCOPY AHL_UC_VALIDATION_PUB.Error_Tbl_Type,
1129   x_evaluation_status     OUT NOCOPY    VARCHAR2) IS
1130 
1131 -- Validate the UC and get the top instance
1132   CURSOR get_uc_header_rec_csr IS
1133    SELECT csi_item_instance_id
1134      FROM ahl_unit_config_headers
1135     WHERE unit_config_header_id = p_uc_header_id
1136       AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1137       AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
1138 
1139 -- Get all leaf non-extra nodes and do not get sub-config root nodes, as these do not need the position quantity validation.
1140 -- Also such instances are inflection points for which get_pos_dtls_csr will not return any records.
1141   CURSOR get_unit_tree_csr(c_csi_instance_id IN NUMBER) IS
1142    SELECT c_csi_instance_id FROM dual
1143     WHERE NOT EXISTS (SELECT 1
1144                         FROM csi_ii_relationships
1145                        WHERE object_id = c_csi_instance_id
1146                          AND relationship_type_code = 'COMPONENT-OF'
1147                          AND trunc(nvl(active_start_date, sysdate-1)) <= trunc(sysdate)
1148                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1149                       UNION ALL
1150                       SELECT 1
1151                         FROM ahl_unit_config_headers
1152                        WHERE csi_item_instance_id = c_csi_instance_id
1153                          AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1154                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)))
1155    UNION ALL
1156    SELECT OUTER.subject_id
1157      FROM csi_ii_relationships OUTER
1158     WHERE NOT EXISTS (SELECT 1
1159                         FROM csi_ii_relationships
1160                        WHERE object_id = OUTER.subject_id
1161                          AND relationship_type_code = 'COMPONENT-OF'
1162                          AND trunc(nvl(active_start_date, sysdate-1)) <= trunc(sysdate)
1163                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1164                       UNION ALL
1165                       SELECT 1
1166                         FROM ahl_unit_config_headers
1167                        WHERE csi_item_instance_id = OUTER.subject_id
1168                          AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1169                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)))
1170     START WITH object_id = c_csi_instance_id
1171         AND relationship_type_code = 'COMPONENT-OF'
1172         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
1173         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1174         AND position_reference is not null
1175     CONNECT BY PRIOR subject_id = object_id
1176         AND relationship_type_code = 'COMPONENT-OF'
1177         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
1178         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1179         AND position_reference is not null;
1180 
1181 -- Get the Relationship of the instance
1182   CURSOR get_pos_ref_reln_csr(c_csi_instance_id IN NUMBER) IS
1183    SELECT TO_NUMBER(position_reference)
1184     FROM csi_ii_relationships csi
1185    WHERE position_reference is not null
1186      AND subject_id = c_csi_instance_id
1187      AND relationship_type_code = 'COMPONENT-OF'
1188      AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1189      AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
1190 
1191 -- Get the Position Quantity Details
1192   CURSOR get_pos_dtls_csr(c_mc_relationship_id IN NUMBER,
1193                           c_instance_id        IN NUMBER) IS
1194    SELECT iasso.quantity Itm_qty,
1195           iasso.uom_code Itm_uom_code,
1196           iasso.revision Itm_revision,
1197           iasso.item_association_id,
1198           reln.quantity Posn_qty,
1199           reln.uom_code Posn_uom_code,
1200           reln.parent_relationship_id,
1201           reln.position_ref_code,
1202           csi.INVENTORY_ITEM_ID,
1203           csi.QUANTITY Inst_qty,
1204           csi.UNIT_OF_MEASURE Inst_uom_code,
1205           (select object_id from csi_ii_relationships
1206             where subject_id = c_instance_id
1207               and relationship_type_code = 'COMPONENT-OF'
1208               and trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1209               and trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))) parent_instance_id
1210      FROM ahl_mc_relationships reln, ahl_item_associations_b iasso, csi_item_instances csi
1211     WHERE csi.INSTANCE_ID = c_instance_id
1212       AND reln.relationship_id = c_mc_relationship_id
1213       AND iasso.item_group_id = reln.item_group_id
1214       AND iasso.inventory_item_id = CSI.INVENTORY_ITEM_ID
1215       AND (iasso.revision IS NULL OR iasso.revision = CSI.INVENTORY_REVISION)
1216       AND iasso.interchange_type_code IN ('1-WAY INTERCHANGEABLE', '2-WAY INTERCHANGEABLE')
1217       AND trunc(nvl(reln.active_start_date, sysdate)) <= trunc(sysdate)
1218       AND trunc(nvl(reln.active_end_date, sysdate+1)) > trunc(sysdate);
1219 
1220   l_pos_dtls_rec      get_pos_dtls_csr%ROWTYPE;
1221 
1222   L_DEBUG_KEY         CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.Validate_Position_Quantities';
1223   L_API_VERSION       CONSTANT NUMBER := 1.0;
1224   L_API_NAME          CONSTANT VARCHAR2(30) := 'Validate_Position_Quantities';
1225   TYPE T_ID_TBL IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
1226   l_parent_rule_tbl   T_ID_TBL;
1227   l_top_instance_id   NUMBER;
1228   l_csi_ii_id         NUMBER;
1229   l_rel_id            NUMBER;
1230   l_rule_exists_flag  VARCHAR2(1);
1231   l_quantity          NUMBER;
1232 
1233 BEGIN
1234 
1235   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1236     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.begin',
1237                    'At the start of the procedure, p_csi_instance_id = ' || p_csi_instance_id ||
1238                    ', p_uc_header_id = ' || p_uc_header_id ||
1239                    ', p_x_error_table.COUNT = ' || p_x_error_table.COUNT);
1240   END IF;
1241   -- Standard call to check for call compatibility
1242   IF NOT FND_API.Compatible_API_Call(L_API_VERSION, p_api_version, L_API_NAME,
1243                                      G_PKG_NAME) THEN
1244     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1245   END IF;
1246 
1247   -- Initialize message list if p_init_msg_list is set to TRUE
1248   IF FND_API.To_Boolean(p_init_msg_list) THEN
1249     FND_MSG_PUB.Initialize;
1250   END IF;
1251 
1252   -- Initialize API return status to success
1253   x_return_status := FND_API.G_RET_STS_SUCCESS;
1254 
1255   -- Begin Processing
1256   x_evaluation_status := FND_API.G_TRUE;
1257 
1258   -- Call procedure to validate the uc header id
1259   IF (p_csi_instance_id IS NOT NULL AND p_uc_header_id IS NULL) THEN
1260     l_top_instance_id := p_csi_instance_id;
1261   ELSE
1262     OPEN get_uc_header_rec_csr;
1263     FETCH get_uc_header_rec_csr INTO l_top_instance_id;
1264     IF (get_uc_header_rec_csr%NOTFOUND) THEN
1265       FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
1266       FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
1267       FND_MSG_PUB.add;
1268       CLOSE get_uc_header_rec_csr;
1269       RAISE FND_API.G_EXC_ERROR;
1270     END IF;
1271     CLOSE get_uc_header_rec_csr;
1272   END IF;
1273 
1274   OPEN get_unit_tree_csr(l_top_instance_id);
1275   LOOP
1276     FETCH get_unit_tree_csr into l_csi_ii_id;
1277     EXIT WHEN get_unit_tree_csr%NOTFOUND;
1278 
1279     l_rel_id := NULL;
1280     OPEN get_pos_ref_reln_csr(l_csi_ii_id);
1281     FETCH get_pos_ref_reln_csr INTO l_rel_id;
1282     CLOSE get_pos_ref_reln_csr;
1283 
1284     IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1285       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1286                      'Checking Quantity for Instance ' || l_csi_ii_id ||
1287                      ', l_rel_id = ' || l_rel_id);
1288     END IF;
1289     IF (l_rel_id IS NOT NULL) THEN
1290       OPEN get_pos_dtls_csr(c_mc_relationship_id => l_rel_id,
1291                             c_instance_id        => l_csi_ii_id);
1292       FETCH get_pos_dtls_csr INTO l_pos_dtls_rec;
1293       CLOSE get_pos_dtls_csr;
1294 
1295       IF (l_pos_dtls_rec.Itm_qty IS NULL OR l_pos_dtls_rec.Itm_qty = 0) THEN
1296         -- Pick the Quantity and UOM from Position level.
1297         l_pos_dtls_rec.Itm_qty      := l_pos_dtls_rec.Posn_qty;
1298         l_pos_dtls_rec.Itm_uom_code := l_pos_dtls_rec.Posn_uom_code;
1299       END IF;
1300 
1301       IF (l_pos_dtls_rec.Itm_uom_code <> l_pos_dtls_rec.Inst_uom_code) THEN
1302         -- UOMs are different: Convert Item UOM Qty to Inst UOM Qty
1303         l_quantity := inv_convert.inv_um_convert(item_id       => l_pos_dtls_rec.INVENTORY_ITEM_ID,
1304                                                  precision     => 6,
1305                                                  from_quantity => l_pos_dtls_rec.Itm_qty,
1306                                                  from_unit     => l_pos_dtls_rec.Itm_uom_code,
1307                                                  to_unit       => l_pos_dtls_rec.Inst_uom_code,
1308                                                  from_name     => NULL,
1309                                                  to_name       => NULL);
1310         l_pos_dtls_rec.Itm_qty := l_quantity;
1311         l_pos_dtls_rec.Itm_uom_code := l_pos_dtls_rec.Inst_uom_code;
1312       END IF;
1313 
1314       -- Now Compare and Validate the Quantities
1315       IF (l_pos_dtls_rec.Inst_qty = l_pos_dtls_rec.Itm_qty) THEN
1316         -- Quantity matches: Don't raise error
1317         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1318           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1319                         'Quantities Match: ' || l_pos_dtls_rec.Itm_qty);
1320         END IF;
1321       ELSIF (l_pos_dtls_rec.Inst_qty > l_pos_dtls_rec.Itm_qty) THEN
1322         -- Instance Quantity can never be greater the Position quantity: Throw error
1323         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1324           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1325                          'Instance Qty (' || l_pos_dtls_rec.Inst_qty || ') > Position Quantity (' || l_pos_dtls_rec.Itm_qty || ')');
1326         END IF;
1327         Add_Qty_Message(p_position_ref_code => l_pos_dtls_rec.position_ref_code,
1328                         p_inst_qty          => l_pos_dtls_rec.Inst_qty,
1329                         p_qty_less_flag     => 'N',  -- Quantity is more
1330                         p_x_error_table     => p_x_error_table);
1331         x_evaluation_status := FND_API.G_FALSE;
1332 
1333       ELSE
1334         -- Instance Quantity is less than Position Quantity
1335         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1336           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1337                          'Need to check for rules: Instance Qty (' || l_pos_dtls_rec.Inst_qty || ') < Position Quantity (' || l_pos_dtls_rec.Itm_qty || ')');
1338         END IF;
1339 
1340         -- Check l_parent_rule_tbl to see if an entry exists for the index l_pos_dtls_rec.parent_relationship_id
1341         IF (NOT (l_parent_rule_tbl.EXISTS(l_pos_dtls_rec.parent_instance_id))) THEN
1342           -- No entry exists in l_parent_rule_tbl
1343           l_rule_exists_flag := Quantity_Rule_Exists(p_instance_id => l_pos_dtls_rec.parent_instance_id);
1344           IF (l_rule_exists_flag = 'Y') THEN
1345             l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) := 1;
1346             -- Ignore the quantity shortage.
1347           ELSE
1348             l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) := -1;
1349           END IF;
1350         END IF;  -- NOT of l_parent_rule_tbl.EXISTS
1351 
1352         -- Raise error only if there is no Quantity Rule at Parent position
1353         IF (l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) > 0) THEN
1354           -- A 'Quantity type' rule exists at the parent position: Ignore the quantity shortage.
1355           IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1356             FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1357                            'Quantity Rule Exists. So not throwing error.');
1358           END IF;
1359         ELSE
1360           -- No 'Quantity type' rule exists at the parent position. So raise a validation error
1361           IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1362             FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1363                            'Quantity Rule Does not Exist. So throwing error.');
1364           END IF;
1365           Add_Qty_Message(p_position_ref_code => l_pos_dtls_rec.position_ref_code,
1366                           p_inst_qty          => l_pos_dtls_rec.Inst_qty,
1367                           p_qty_less_flag     => 'Y',  -- Quantity is less
1368                           p_x_error_table     => p_x_error_table);
1369           x_evaluation_status := FND_API.G_FALSE;
1370         END IF;  -- l_parent_rule_tbl entry is +ve or -ve
1371       END IF; -- Inst_qty checks
1372     END IF;  -- l_rel_id IS NOT NULL
1373   END LOOP; -- All leaf non-extra nodes
1374   CLOSE get_unit_tree_csr;
1375 
1376   -- Completed Processing
1377 
1378   -- Check Error Message stack.
1379   x_msg_count := FND_MSG_PUB.count_msg;
1380   IF x_msg_count > 0 THEN
1381     RAISE  FND_API.G_EXC_ERROR;
1382   END IF;
1383 
1384   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1385     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.end',
1386                    'At the end of the procedure, About to return x_evaluation_status as ' || x_evaluation_status ||
1387                    ', p_x_error_table.COUNT = ' || p_x_error_table.COUNT);
1388   END IF;
1389 
1390   -- Standard call to get message count and if count is 1, get message info
1391   FND_MSG_PUB.Count_And_Get
1392     ( p_count => x_msg_count,
1393       p_data  => x_msg_data,
1394       p_encoded => fnd_api.g_false
1395     );
1396 
1397 EXCEPTION
1398   WHEN FND_API.G_EXC_ERROR THEN
1399     x_return_status := FND_API.G_RET_STS_ERROR;
1400     FND_MSG_PUB.count_and_get( p_count => x_msg_count,
1401                                p_data  => x_msg_data,
1402                                p_encoded => fnd_api.g_false);
1403   WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1404     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1405     FND_MSG_PUB.count_and_get( p_count => x_msg_count,
1406                                p_data  => x_msg_data,
1407                                p_encoded => fnd_api.g_false);
1408   WHEN OTHERS THEN
1409     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1410     FND_MSG_PUB.add_exc_msg( p_pkg_name       => G_PKG_NAME,
1411                              p_procedure_name => l_api_name,
1412                              p_error_text     => SQLERRM);
1413 
1414     FND_MSG_PUB.count_and_get( p_count => x_msg_count,
1415                                p_data  => x_msg_data,
1416                                p_encoded => fnd_api.g_false);
1417 END Validate_Position_Quantities;
1418 
1419 --------------------------------------------------------------------------------------------
1420 --  Start of Comments  --
1421 --
1422 --  Procedure name      : Check_Position_Quantities
1423 --  Type                : Private
1424 --  Function            : This procedure was added for the FP OGMA Issue 105 to support Non Serialized Items.
1425 --                        It checks the instance quantity against the position/item group.
1426 --                        If there is a Quantity type rule at the Parent position, the floor check
1427 --                        is not done (Only ceiling check is done). Since in this case the Rule
1428 --                        overrides and obviates any need for Quantity check and checking quantity
1429 --                        based on position may actually contradict the rule.
1430 --
1431 --  Pre-reqs
1432 --
1433 --  Standard IN  Parameters :
1434 --      p_api_version                   IN      NUMBER                      Required
1435 --      p_init_msg_list                 IN      VARCHAR2                    Default  FND_API.G_TRUE
1436 --      p_validation_level              IN      NUMBER                      Default  FND_API.G_VALID_LEVEL_FULL
1437 --  Standard OUT Parameters :
1438 --      x_return_status                 OUT     VARCHAR2                    Required
1439 --      x_msg_count                     OUT     NUMBER                      Required
1440 --      x_msg_data                      OUT     VARCHAR2                    Required
1441 --
1442 --  Check_Position_Quantities Parameters :
1443 --  p_uc_header_id                      IN      NUMBER                      Required
1444 --                   The header id of the unit configuration.
1445 --  x_evaluation_status                 OUT     VARCHAR2   The OUT flag which indicates whether the unit has any Quantity mismatch.
1446 --
1447 --  History:
1448 --    05-Dec-2007       SATHAPLI       Created
1449 --
1450 --  Version:
1451 --      Initial Version   1.0
1452 --
1453 --  End of Comments.
1454 --------------------------------------------------------------------------------------------
1455 
1456 PROCEDURE Check_Position_Quantities(
1457   p_api_version           IN            NUMBER,
1458   p_init_msg_list         IN            VARCHAR2 := FND_API.G_TRUE,
1459   p_validation_level      IN            NUMBER   := FND_API.G_VALID_LEVEL_FULL,
1460   x_return_status         OUT NOCOPY    VARCHAR2,
1461   x_msg_count             OUT NOCOPY    NUMBER,
1462   x_msg_data              OUT NOCOPY    VARCHAR2,
1463   p_uc_header_id          IN            NUMBER,
1464   x_evaluation_status     OUT NOCOPY    VARCHAR2) IS
1465 
1466 -- Validate the UC and get the top instance
1467   CURSOR get_uc_header_rec_csr IS
1468    SELECT csi_item_instance_id
1469      FROM ahl_unit_config_headers
1470     WHERE unit_config_header_id = p_uc_header_id
1471       AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1472       AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
1473 
1474 -- Get all leaf non-extra nodes and do not get sub-config root nodes, as these do not need the position quantity validation.
1475 -- Also such instances are inflection points for which get_pos_dtls_csr will not return any records.
1476   CURSOR get_unit_tree_csr(c_csi_instance_id IN NUMBER) IS
1477    SELECT c_csi_instance_id FROM dual
1478     WHERE NOT EXISTS (SELECT 1
1479                         FROM csi_ii_relationships
1480                        WHERE object_id = c_csi_instance_id
1481                          AND relationship_type_code = 'COMPONENT-OF'
1482                          AND trunc(nvl(active_start_date, sysdate-1)) <= trunc(sysdate)
1483                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1484                       UNION ALL
1485                       SELECT 1
1486                         FROM ahl_unit_config_headers
1487                        WHERE csi_item_instance_id = c_csi_instance_id
1488                          AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1489                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)))
1490    UNION ALL
1491    SELECT OUTER.subject_id
1492      FROM csi_ii_relationships OUTER
1493     WHERE NOT EXISTS (SELECT 1
1494                         FROM csi_ii_relationships
1495                        WHERE object_id = OUTER.subject_id
1496                          AND relationship_type_code = 'COMPONENT-OF'
1497                          AND trunc(nvl(active_start_date, sysdate-1)) <= trunc(sysdate)
1498                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1499                       UNION ALL
1500                       SELECT 1
1501                         FROM ahl_unit_config_headers
1502                        WHERE csi_item_instance_id = OUTER.subject_id
1503                          AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1504                          AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1)))
1505     START WITH object_id = c_csi_instance_id
1506         AND relationship_type_code = 'COMPONENT-OF'
1507         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
1508         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1509         AND position_reference is not null
1510     CONNECT BY PRIOR subject_id = object_id
1511         AND relationship_type_code = 'COMPONENT-OF'
1512         AND trunc(nvl(active_start_date,sysdate-1)) <= trunc(sysdate)
1513         AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))
1514         AND position_reference is not null;
1515 
1516 -- Get the Relationship of the instance
1517   CURSOR get_pos_ref_reln_csr(c_csi_instance_id IN NUMBER) IS
1518    SELECT TO_NUMBER(position_reference)
1519     FROM csi_ii_relationships csi
1520    WHERE position_reference is not null
1521      AND subject_id = c_csi_instance_id
1522      AND relationship_type_code = 'COMPONENT-OF'
1523      AND trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1524      AND trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1));
1525 
1526 -- Get the Position Quantity Details
1527   CURSOR get_pos_dtls_csr(c_mc_relationship_id IN NUMBER,
1528                           c_instance_id        IN NUMBER) IS
1529    SELECT iasso.quantity Itm_qty,
1530           iasso.uom_code Itm_uom_code,
1531           iasso.revision Itm_revision,
1532           iasso.item_association_id,
1533           reln.quantity Posn_qty,
1534           reln.uom_code Posn_uom_code,
1535           reln.parent_relationship_id,
1536           reln.position_ref_code,
1537           csi.INVENTORY_ITEM_ID,
1538           csi.QUANTITY Inst_qty,
1539           csi.UNIT_OF_MEASURE Inst_uom_code,
1540           (select object_id from csi_ii_relationships
1541             where subject_id = c_instance_id
1542               and relationship_type_code = 'COMPONENT-OF'
1543               and trunc(nvl(active_start_date, sysdate)) <= trunc(sysdate)
1544               and trunc(sysdate) < trunc(nvl(active_end_date, sysdate+1))) parent_instance_id
1545      FROM ahl_mc_relationships reln, ahl_item_associations_b iasso, csi_item_instances csi
1546     WHERE csi.INSTANCE_ID = c_instance_id
1547       AND reln.relationship_id = c_mc_relationship_id
1548       AND iasso.item_group_id = reln.item_group_id
1549       AND iasso.inventory_item_id = CSI.INVENTORY_ITEM_ID
1550       AND (iasso.revision IS NULL OR iasso.revision = CSI.INVENTORY_REVISION)
1551       AND iasso.interchange_type_code IN ('1-WAY INTERCHANGEABLE', '2-WAY INTERCHANGEABLE')
1552       AND trunc(nvl(reln.active_start_date, sysdate)) <= trunc(sysdate)
1553       AND trunc(nvl(reln.active_end_date, sysdate+1)) > trunc(sysdate);
1554 
1555   l_pos_dtls_rec      get_pos_dtls_csr%ROWTYPE;
1556 
1557   L_DEBUG_KEY         CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.Check_Position_Quantities';
1558   L_API_VERSION       CONSTANT NUMBER := 1.0;
1559   L_API_NAME          CONSTANT VARCHAR2(30) := 'Check_Position_Quantities';
1560   TYPE T_ID_TBL IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
1561   l_parent_rule_tbl   T_ID_TBL;
1562   l_top_instance_id   NUMBER;
1563   l_csi_ii_id         NUMBER;
1564   l_rel_id            NUMBER;
1565   l_rule_exists_flag  VARCHAR2(1);
1566   l_quantity          NUMBER;
1567 
1568 BEGIN
1569 
1570   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1571     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.begin',
1572                    'At the start of the procedure, p_uc_header_id = ' || p_uc_header_id);
1573   END IF;
1574   -- Standard call to check for call compatibility
1575   IF NOT FND_API.Compatible_API_Call(L_API_VERSION, p_api_version, L_API_NAME,
1576                                      G_PKG_NAME) THEN
1577     RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1578   END IF;
1579 
1580   -- Initialize message list if p_init_msg_list is set to TRUE
1581   IF FND_API.To_Boolean(p_init_msg_list) THEN
1582     FND_MSG_PUB.Initialize;
1583   END IF;
1584 
1585   -- Initialize API return status to success
1586   x_return_status := FND_API.G_RET_STS_SUCCESS;
1587 
1588   -- Begin Processing
1589   x_evaluation_status := FND_API.G_TRUE;
1590 
1591   -- Call procedure to validate the uc header id
1592   OPEN get_uc_header_rec_csr;
1593   FETCH get_uc_header_rec_csr INTO l_top_instance_id;
1594   IF (get_uc_header_rec_csr%NOTFOUND) THEN
1595     FND_MESSAGE.set_name('AHL', 'AHL_UC_HEADER_ID_INVALID');
1596     FND_MESSAGE.set_token('UC_HEADER_ID', p_uc_header_id);
1597     FND_MSG_PUB.add;
1598     CLOSE get_uc_header_rec_csr;
1599     RAISE FND_API.G_EXC_ERROR;
1600   END IF;
1601   CLOSE get_uc_header_rec_csr;
1602 
1603   OPEN get_unit_tree_csr(l_top_instance_id);
1604   LOOP
1605     FETCH get_unit_tree_csr into l_csi_ii_id;
1606     EXIT WHEN get_unit_tree_csr%NOTFOUND;
1607 
1608     l_rel_id := NULL;
1609     OPEN get_pos_ref_reln_csr(l_csi_ii_id);
1610     FETCH get_pos_ref_reln_csr INTO l_rel_id;
1611     CLOSE get_pos_ref_reln_csr;
1612 
1613     IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1614       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1615                      'Checking Quantity for Instance ' || l_csi_ii_id ||
1616                      ', l_rel_id = ' || l_rel_id);
1617     END IF;
1618     IF (l_rel_id IS NOT NULL) THEN
1619       OPEN get_pos_dtls_csr(c_mc_relationship_id => l_rel_id,
1620                             c_instance_id        => l_csi_ii_id);
1621       FETCH get_pos_dtls_csr INTO l_pos_dtls_rec;
1622       CLOSE get_pos_dtls_csr;
1623 
1624       IF (l_pos_dtls_rec.Itm_qty IS NULL OR l_pos_dtls_rec.Itm_qty = 0) THEN
1625         -- Pick the Quantity and UOM from Position level.
1626         l_pos_dtls_rec.Itm_qty      := l_pos_dtls_rec.Posn_qty;
1627         l_pos_dtls_rec.Itm_uom_code := l_pos_dtls_rec.Posn_uom_code;
1628       END IF;
1629 
1630       IF (l_pos_dtls_rec.Itm_uom_code <> l_pos_dtls_rec.Inst_uom_code) THEN
1631         -- UOMs are different: Convert Item UOM Qty to Inst UOM Qty
1632         l_quantity := inv_convert.inv_um_convert(item_id       => l_pos_dtls_rec.INVENTORY_ITEM_ID,
1633                                                  precision     => 6,
1634                                                  from_quantity => l_pos_dtls_rec.Itm_qty,
1635                                                  from_unit     => l_pos_dtls_rec.Itm_uom_code,
1636                                                  to_unit       => l_pos_dtls_rec.Inst_uom_code,
1637                                                  from_name     => NULL,
1638                                                  to_name       => NULL);
1639         l_pos_dtls_rec.Itm_qty := l_quantity;
1640         l_pos_dtls_rec.Itm_uom_code := l_pos_dtls_rec.Inst_uom_code;
1641       END IF;
1642 
1643       -- Now Compare and Validate the Quantities
1644       IF (l_pos_dtls_rec.Inst_qty = l_pos_dtls_rec.Itm_qty) THEN
1645         -- Quantity matches: Don't raise error
1646         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1647           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1648                          'Quantities Match: ' || l_pos_dtls_rec.Itm_qty);
1649         END IF;
1650       ELSIF (l_pos_dtls_rec.Inst_qty > l_pos_dtls_rec.Itm_qty) THEN
1651         -- Instance Quantity can never be greater the Position quantity: Return error
1652         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1653           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1654                          'Exiting Early: Instance Qty (' || l_pos_dtls_rec.Inst_qty || ') > Position Quantity (' || l_pos_dtls_rec.Itm_qty || ')');
1655         END IF;
1656         x_evaluation_status := FND_API.G_FALSE;
1657         EXIT; -- No need to process remaining instances
1658       ELSE
1659         -- Instance Quantity is less than Position Quantity
1660         IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1661           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1662                          'Need to check for rules: Instance Qty (' || l_pos_dtls_rec.Inst_qty || ') < Position Quantity (' || l_pos_dtls_rec.Itm_qty || ')');
1663         END IF;
1664         -- Raise error only if there is no Quantity Rule at Parent position
1665         -- Check l_parent_rule_tbl to see if an entry exists for the index l_pos_dtls_rec.parent_relationship_id
1666         IF (NOT(l_parent_rule_tbl.EXISTS(l_pos_dtls_rec.parent_instance_id))) THEN
1667           -- No entry exists in l_parent_rule_tbl
1668           l_rule_exists_flag := Quantity_Rule_Exists(p_instance_id => l_pos_dtls_rec.parent_instance_id);
1669           IF (l_rule_exists_flag = 'Y') THEN
1670             l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) := 1;
1671           ELSE
1672             l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) := -1;
1673           END IF;
1674         END IF;  -- NOT of l_parent_rule_tbl entry exists
1675 
1676         IF (l_parent_rule_tbl(l_pos_dtls_rec.parent_instance_id) > 0) THEN
1677           -- A 'Quantity type' rule exists at the parent position: Ignore the quantity shortage.
1678           IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1679             FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1680                            'Quantity Rule Exists. So not throwing error.');
1681           END IF;
1682         ELSE
1683           -- No 'Quantity type' rule exists at the parent position. So return a validation error
1684           IF (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1685             FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, L_DEBUG_KEY,
1686                            'Early Exit: Quantity Rule Does not Exist. So throwing error.');
1687           END IF;
1688           x_evaluation_status := FND_API.G_FALSE;
1689           EXIT; -- No need to process remaining instances
1690         END IF;  -- l_parent_rule_tbl entry is +ve or -ve
1691       END IF; -- Inst_qty checks
1692     END IF;  -- l_rel_id IS NOT NULL
1693   END LOOP; -- All leaf non-extra nodes
1694   CLOSE get_unit_tree_csr;
1695 
1696   -- Completed Processing
1697 
1698   -- Check Error Message stack.
1699   x_msg_count := FND_MSG_PUB.count_msg;
1700   IF x_msg_count > 0 THEN
1701     RAISE  FND_API.G_EXC_ERROR;
1702   END IF;
1703 
1704   IF (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) THEN
1705     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, L_DEBUG_KEY || '.end',
1706                    'At the end of the procedure, About to return x_evaluation_status as ' || x_evaluation_status);
1707   END IF;
1708 
1709   -- Standard call to get message count and if count is 1, get message info
1710   FND_MSG_PUB.Count_And_Get
1711     ( p_count => x_msg_count,
1712       p_data  => x_msg_data,
1713       p_encoded => fnd_api.g_false
1714     );
1715 
1716 EXCEPTION
1717   WHEN FND_API.G_EXC_ERROR THEN
1718     x_return_status := FND_API.G_RET_STS_ERROR;
1719     FND_MSG_PUB.count_and_get(p_count => x_msg_count,
1720                               p_data  => x_msg_data,
1721                               p_encoded => fnd_api.g_false);
1722   WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1723     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1724     FND_MSG_PUB.count_and_get(p_count => x_msg_count,
1725                               p_data  => x_msg_data,
1726                               p_encoded => fnd_api.g_false);
1727   WHEN OTHERS THEN
1728     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1729     FND_MSG_PUB.add_exc_msg(p_pkg_name       => G_PKG_NAME,
1730                             p_procedure_name => l_api_name,
1731                             p_error_text     => SQLERRM);
1732 
1733     FND_MSG_PUB.count_and_get(p_count => x_msg_count,
1734                               p_data  => x_msg_data,
1735                               p_encoded => fnd_api.g_false);
1736 END Check_Position_Quantities;
1737 
1738 END AHL_UC_POS_NECES_PVT;