DBA Data[Home] [Help]

PACKAGE BODY: APPS.PV_MATCH_V3_PUB

Source


1 PACKAGE BODY PV_MATCH_V3_PUB AS
2 /* $Header: pvxmtv3b.pls 120.15 2006/09/21 22:27:38 amaram noship $*/
3 
4 G_PKG_NAME CONSTANT VARCHAR2(30):= 'PV_MATCH_V3_PUB';
5 G_FILE_NAME CONSTANT VARCHAR2(12) := 'pvxmtv3b.pls';
6 
7 /*************************************************************
8 Almost all of this code has been taken from PV_MATCH_V2_PUB
9 and PV_OPP_MATCH_PUB. Small modifications have been made to them
10 to remove the preferred partner logic. This code was duplicated
11 so that we could have a new set of PL/SQL APIs to handle the new
12 OA UIs. These UIs expect slightly different things from the APIs
13 So even thought most of the funtionality is the same it was not
14 possible to stictly call the older APIs. So we wrote this new set
15 which for most part is the old code but has the minor mosifications
16 to cater to the new functionality.
17 **************************************************************/
18 
19 g_no_more_rules          CONSTANT NUMBER := 100000000000000;
20 g_rule_engine_trace_flag VARCHAR2(1);
21 g_failure_code           VARCHAR2(100) := null;
22 g_matching_engine_type   VARCHAR2(50);
23 
24 g_e_buffer_too_small EXCEPTION;
25 PRAGMA EXCEPTION_INIT(g_e_buffer_too_small, -6502);
26 
27 PROCEDURE debug(p_msg_string       IN VARCHAR2) IS
28 BEGIN
29       FND_MESSAGE.Set_Name('PV', 'PV_DEBUG_MESSAGE');
30       FND_MESSAGE.Set_Token('TEXT', p_msg_string);
31       FND_MSG_PUB.Add;
32 END debug;
33 
34 
35 PROCEDURE Cache_Rules;
36 
37 FUNCTION Get_Next_Rule_Index(
38    p_current_index     NUMBER,
39    p_opp_selection_tab t_opp_selection_tab
40 )
41 RETURN NUMBER;
42 
43 -- --------------------------------------------------------------------
44 -- Tie-breaking API
45 -- --------------------------------------------------------------------
46 PROCEDURE Tie_Breaker(
47    p_api_version            IN  NUMBER,
48    p_init_msg_list          IN  VARCHAR2  := FND_API.g_false,
49    p_commit                 IN  VARCHAR2  := FND_API.g_false,
50    p_validation_level       IN  NUMBER    := FND_API.g_valid_level_full,
51    p_process_rule_id        IN  NUMBER,
52    x_partner_tbl            IN OUT NOCOPY JTF_NUMBER_TABLE,
53    x_return_status          OUT NOCOPY VARCHAR2,
54    x_msg_count              OUT NOCOPY NUMBER,
55    x_msg_data               OUT NOCOPY VARCHAR2
56 );
57 
58 -- -----------------------------------------------------------------------------------
59 -- The following private routines are used by the tie-breaking API.
60 -- -----------------------------------------------------------------------------------
61 PROCEDURE Set_Message(
62     p_msg_level     IN      NUMBER,
63     p_msg_name      IN      VARCHAR2,
64     p_token1        IN      VARCHAR2,
65     p_token1_value  IN      VARCHAR2,
66     p_token2        IN      VARCHAR2 := NULL,
67     p_token2_value  IN      VARCHAR2 := NULL,
68     p_token3        IN      VARCHAR2 := NULL,
69     p_token3_value  IN      VARCHAR2 := NULL
70 );
71 
72 PROCEDURE Get_Attr_Length(
73    p_attr_value    IN  VARCHAR2,
74    p_left_length   OUT NOCOPY NUMBER,
75    p_right_length  OUT NOCOPY NUMBER)
76 ;
77 
78 FUNCTION Convert_To_String(
79    p_attr_value             NUMBER,
80    p_max_left_length        NUMBER,
81    p_max_right_length       NUMBER,
82    p_format_string          VARCHAR2,
83    p_positive_format_string VARCHAR2,
84    p_min_max                VARCHAR2)
85 RETURN VARCHAR2;
86 
87 
88 FUNCTION Build_Format_String (
89    p_max_left_length  NUMBER,
90    p_max_right_length NUMBER)
91 RETURN VARCHAR2;
92 
93 -- The Procudures Start Here =================================================
94 
95 -- ===========================End of Opportunity_Selection=========================
96 PROCEDURE Opportunity_Selection
97 (
98    p_api_version            IN  NUMBER,
99    p_init_msg_list          IN  VARCHAR2  := FND_API.g_false,
100    p_commit                 IN  VARCHAR2  := FND_API.g_false,
101    p_validation_level       IN  NUMBER    := FND_API.g_valid_level_full,
102    p_entity_id              IN  NUMBER,
103    p_entity                 IN  VARCHAR2,
104    p_user_name              IN  VARCHAR2  := NULL,
105    p_resource_id            IN  NUMBER    := NULL,
106    x_selected_rule_id       OUT NOCOPY NUMBER,
107    x_matched_partner_count  OUT NOCOPY NUMBER,
108    x_failure_code           OUT NOCOPY VARCHAR2,
109    x_return_status          OUT NOCOPY VARCHAR2,
110    x_msg_count              OUT NOCOPY NUMBER,
111    x_msg_data               OUT NOCOPY VARCHAR2
112 ) IS
113    l_api_name           VARCHAR2(30) := 'Opportunity_Selection';
114    l_return_status      VARCHAR2(100);
115    l_msg_count          NUMBER;
116    l_msg_data           VARCHAR2(500);
117    l_partner_cnt        NUMBER;
118    l_partner_details    JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
119    l_flagcount          JTF_VARCHAR2_TABLE_100  := JTF_VARCHAR2_TABLE_100();
120    l_distance_tbl       JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
121    l_distance_uom       VARCHAR2(30);
122    l_distance_uom_returned VARCHAR2(30);
123 
124 
125 BEGIN
126    g_failure_code := NULL;
127    g_matching_engine_type := 'BACKGROUND_PARTNER_MATCHING';
128 
129    Opportunity_Selection(
130       p_api_version            => p_api_version,
131       p_init_msg_list          => p_init_msg_list,
132       p_commit                 => p_commit,
133       p_validation_level       => p_validation_level,
134       p_entity_id              => p_entity_id,
135       p_entity                 => p_entity,
136       p_user_name              => p_user_name,
137       p_resource_id            => p_resource_id,
138       p_routing_flag           => 'Y',
139       x_partner_cnt            => l_partner_cnt,
140       x_partner_details        => l_partner_details,
141       x_flagcount              => l_flagcount,
142       x_distance_tbl           => l_distance_tbl,
143       x_distance_uom_returned  => l_distance_uom_returned,
144       x_selected_rule_id       => x_selected_rule_id,
145       x_return_status          => x_return_status,
146       x_msg_count              => x_msg_count,
147       x_msg_data               => x_msg_data
148    );
149 
150    x_matched_partner_count := l_partner_cnt;
151 
152    -- ----------------------------------------------------------------------
153    -- Set the failure_code so the caller would know what exactly went wrong.
154    -- ----------------------------------------------------------------------
155    x_failure_code          := g_failure_code;
156 
157    IF (x_return_status = FND_API.G_RET_STS_ERROR) THEN
158       RAISE FND_API.G_EXC_ERROR;
159 
160    ELSIF (x_return_status = FND_API.g_ret_sts_unexp_error) THEN
161       RAISE FND_API.g_exc_unexpected_error;
162    END IF;
163 
164    -------------------- Exception --------------------------
165    EXCEPTION
166       WHEN FND_API.G_EXC_ERROR THEN
167          x_return_status := FND_API.G_RET_STS_ERROR;
168          FND_MSG_PUB.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
169                                     p_count     =>  x_msg_count,
170                                     p_data      =>  x_msg_data);
171 
172       WHEN FND_API.g_exc_unexpected_error THEN
173          x_return_status := FND_API.g_ret_sts_unexp_error;
174          FND_MSG_PUB.count_and_get(
175                p_encoded => FND_API.g_false,
176                p_count   => x_msg_count,
177                p_data    => x_msg_data
178          );
179 
180       WHEN OTHERS THEN
181         IF FND_MSG_PUB.check_msg_level(FND_MSG_PUB.g_msg_lvl_unexp_error) THEN
182            FND_MSG_PUB.add_exc_msg(g_pkg_name, l_api_name);
183         END IF;
184 
185         x_return_status := FND_API.G_RET_STS_ERROR;
186         FND_MSG_PUB.count_and_get(
187               p_encoded => FND_API.g_false,
188               p_count   => x_msg_count,
189               p_data    => x_msg_data
190         );
191 END Opportunity_Selection;
192 -- ===========================End of Opportunity_Selection=========================
193 
194 
195 --=============================================================================+
196 --|  Procedure                                                                 |
197 --|                                                                            |
198 --|    Opportunity_Selection                                                   |
199 --|                                                                            |
200 --|                                                                            |
201 --|  Parameters                                                                |
202 --|  IN                                                                        |
203 --|  OUT                                                                       |
204 --|                                                                            |
205 --|                                                                            |
206 --| NOTES                                                                      |
207 --|                                                                            |
208 --| HISTORY                                                                    |
209 --|                                                                            |
210 --==============================================================================
211 PROCEDURE Opportunity_Selection(
212    p_api_version            IN  NUMBER,
213    p_init_msg_list          IN  VARCHAR2  := FND_API.g_false,
214    p_commit                 IN  VARCHAR2  := FND_API.g_false,
215    p_validation_level       IN  NUMBER    := FND_API.g_valid_level_full,
216    p_entity_id              IN  NUMBER,
217    p_entity                 IN  VARCHAR2,
218    p_user_name              IN  VARCHAR2  := NULL,
219    p_resource_id            IN  NUMBER    := NULL,
220    p_routing_flag           IN  VARCHAR2  := 'N',
221    x_partner_cnt            OUT NOCOPY NUMBER,
222    x_partner_details        OUT NOCOPY JTF_VARCHAR2_TABLE_4000,
223    x_flagcount              OUT NOCOPY JTF_VARCHAR2_TABLE_100,
224    x_distance_tbl           OUT NOCOPY JTF_NUMBER_TABLE,
225    x_distance_uom_returned  OUT NOCOPY VARCHAR2,
226    x_selected_rule_id       OUT NOCOPY NUMBER,
227    x_return_status          OUT NOCOPY VARCHAR2,
228    x_msg_count              OUT NOCOPY NUMBER,
229    x_msg_data               OUT NOCOPY VARCHAR2
230 )
231 IS
232    l_api_version        NUMBER := 1.0;
233    l_api_name           VARCHAR2(30) := 'Opportunity_Selection';
234 
235    l_entity_attr_value  pv_check_match_pub.t_entity_attr_value;
236    l_input_filter       pv_check_match_pub.t_input_filter;
237    i                    NUMBER := 1;
238    j                    NUMBER;
239    l_next_index         NUMBER;
240    l_next_rule_id       NUMBER;
241    l_stop_flag          BOOLEAN := FALSE;
242    l_matched            BOOLEAN;
243    l_start              NUMBER;
244    l_stop_at_index      NUMBER;
245    l_concat_attr_val    VARCHAR2(4000);
246    l_concat_to_attr_val VARCHAR2(4000);
247    l_dummy              VARCHAR2(4000);
248    l_count              NUMBER;
249    l_attribute_id       NUMBER;
250    l_return_status      VARCHAR2(100);
251    l_msg_count          NUMBER;
252    l_msg_data           VARCHAR2(500);
253    l_delimiter          VARCHAR2(10) := '+++';
254    l_partner_cnt        NUMBER;
255 
256    -- -----------------------------------------------------------------
257    -- Retrieve from a system profile, indicating the type of matching
258    -- to be used. Values to be determined:
259    --
260    -- EXHAUST_ALL_RULES
261    -- STOP_AT_FIRST_RULE
262    -- -----------------------------------------------------------------
263    l_matching_type      VARCHAR2(30);
264 
265    l_winning_rule_flag      VARCHAR2(10);
266    l_entity_rule_applied_id NUMBER;
267    l_attr_val_temp varchar2(4000);
268 
269 BEGIN
270    -------------------- initialize -------------------------
271    IF FND_API.to_boolean(p_init_msg_list) THEN
272       FND_MSG_PUB.initialize;
273    END IF;
274 
275    IF NOT FND_API.compatible_api_call(
276          l_api_version,
277          p_api_version,
278          l_api_name,
279          g_pkg_name
280    ) THEN
281       RAISE FND_API.g_exc_unexpected_error;
282    END IF;
283 
284    x_return_status := FND_API.G_RET_STS_SUCCESS;
285 
286    -------------------------- Source code --------------------
287 
288    -- ------------------------------------------------------------------------
289    -- Make sure that either p_user_name or p_resource IS NOT NULL.
290    -- ------------------------------------------------------------------------
291    IF (p_user_name IS NULL AND p_resource_id IS NULL) THEN
292       Set_Message(p_msg_level    => FND_MSG_PUB.G_MSG_LVL_ERROR,
293                   p_msg_name     => 'PV_NO_USERNAME_ID_DEFINED',
294                   p_token1       => null,
295                   p_token1_value => null,
296                   p_token2       => null,
297                   p_token2_value => null);
298 
299       g_failure_code := 'OTHER';
300       RAISE FND_API.G_EXC_ERROR;
301    END IF;
302 
303    -- ------------------------------------------------------------------------
304    -- Initialize OUT parameters.
305    -- ------------------------------------------------------------------------
306    x_partner_details    := JTF_VARCHAR2_TABLE_4000();
307    x_flagcount          := JTF_VARCHAR2_TABLE_100();
308    x_distance_tbl       := JTF_NUMBER_TABLE();
309 
310    -- ------------------------------------------------------------------------
311    -- Retrieve profile value for stack trace profile option.
312    -- ------------------------------------------------------------------------
313    --g_rule_engine_trace_flag := NVL(FND_PROFILE.VALUE('PV_RULE_ENGINE_TRACE_ON'), 'N');
314 
315    -- --------------------------------------------------------------------------
316    -- Retrieving Matching Type Profile Value, which can be one of the following:
317    --
318    -- EXHAUST_ALL_RULES
319    -- STOP_AT_FIRST_RULE
320    -- --------------------------------------------------------------------------
321    l_matching_type := NVL(FND_PROFILE.VALUE('PV_PARTNER_MATCHING_TYPE'), 'STOP_AT_FIRST_RULE');
322 
323 
324    -- ---------------------------------------------------------------------------------
325    -- Cache all the opportunity selection rules (attributes-values) in a global
326    -- PL/SQL table, g_opp_selection_tab.
327    -- ---------------------------------------------------------------------------------
328    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
329       Debug('----------------------------------------------------------------');
330       Debug('g_matching_engine_type: ' || g_matching_engine_type);
331       Debug('Matching Type:          ' || l_matching_type);
332       Debug('----------------------------------------------------------------');
333 
334       Debug('Clear Rules Cache.......................................');
335    END IF;
336 
337    Clear_Rules_Cache;
338 
339    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
340       Debug('Rule Caching............................................');
341    END IF;
342 
343    l_start := dbms_utility.get_time;
344    Cache_Rules;
345 
346    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
347       Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
348    END IF;
349 
350    l_count := g_opp_selection_tab.COUNT;
351 
352    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
353       Debug('Number of Rule items Cached: ' || l_count);
354    END IF;
355 
356    i := 1;
357 
358    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
359       Debug('Opportunity Rule Selection Starts....................................');
360    END IF;
361 
362    l_start := dbms_utility.get_time;
363 
364    WHILE (i <= l_count AND (NOT l_stop_flag)) LOOP
365       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
366          Debug('******************************************************');
367          Debug('Rule # :::' || g_opp_selection_tab(i).process_rule_id);
368       END IF;
369 
370       -- ---------------------------------------------------------------------------
371       -- If the opportunity's attribute value is not already retrieved, retrieve it.
372       -- ---------------------------------------------------------------------------
373       l_attribute_id := g_opp_selection_tab(i).attribute_id;
374 
375       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
376          Debug('Attribute ID:   ' || l_attribute_id);
377          Debug('Opportunity ID: ' || p_entity_id);
378       END IF;
379 
380       pv_check_match_pub.Get_Entity_Attr_Values(
381          p_api_version_number => 1.0,
382          p_attribute_id       => l_attribute_id,
383          p_entity             => p_entity,
384          p_entity_id          => p_entity_id,
385          p_delimiter          => l_delimiter,
386          x_entity_attr_value  => l_entity_attr_value,
387          x_return_status      => l_return_status,
388          x_msg_count          => l_msg_count,
389          x_msg_data           => l_msg_data
390       );
391 
392       IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
393          RAISE FND_API.G_EXC_ERROR;
394 
395       ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
396          RAISE FND_API.g_exc_unexpected_error;
397       END IF;
398 
399       -- ---------------------------------------------------------------------------
400       -- If the attribute value for this entity doesn't exist (which is different
401       -- from a NULL), there's a problem. It should have been caught in
402       -- Get_Entity_Attr_Values.
403       --
404       -- Advance to the next rule for evaluation.
405       -- ---------------------------------------------------------------------------
406       IF (NOT l_entity_attr_value.EXISTS(l_attribute_id)) THEN
407          i := Get_Next_Rule_Index(i, g_opp_selection_tab);
408 
409          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
410             Debug('No attribute value for this attribute ' || l_attribute_id);
411             Debug('There is something wrong in the attribute setup.');
412          END IF;
413 
414       ELSE
415 
416 			-- ---------------------------------------------------------------------------
417 			-- Now we have the attribute value for this attribute, let's compare it with
418 			-- the attribute value specified in the opportunity selection.
419 			-- ---------------------------------------------------------------------------
420 			l_matched := FALSE;
421 
422 			-- ---------------------------------------------------------------------------
423 			-- AND logic...
424 			-- ---------------------------------------------------------------------------
425 			IF (g_opp_selection_tab(i).count = 1) THEN
426 				-- ------------------------------------------------------------------------
427 				-- Use operator to do the match. If the match fails, go to the next rule
428 				-- until all rules are exhausted.
429 				-- If the match succeeds, check if last_attr_flag = TRUE. If yes, there's
430 				-- a match. set l_stop_flag = TRUE
431 				-- ------------------------------------------------------------------------
432 				IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
433 					Debug('Calling Check_Match...AND LOGIC...');
434 					Debug('p_attribute_id:      ' || l_attribute_id);
435 					--Debug('p_entity_attr_value: ' || l_entity_attr_value(l_attribute_id).attribute_value);
436 
437 					l_attr_val_temp := l_entity_attr_value(l_attribute_id).attribute_value;
438 					while (l_attr_val_temp is not null) loop
439 						Debug('p_entity_attr_value: ' || substr( l_attr_val_temp, 1, 1800 ) );
440 						l_attr_val_temp := substr( l_attr_val_temp, 1801 );
441 					end loop;
442 
443 					--Debug('p_rule_attr_value:   ' || g_opp_selection_tab(i).attribute_value);
444 					l_attr_val_temp := g_opp_selection_tab(i).attribute_value;
445 					while (l_attr_val_temp is not null) loop
446 						Debug('p_rule_attr_value: ' || substr( l_attr_val_temp, 1, 1800 ) );
447 						l_attr_val_temp := substr( l_attr_val_temp, 1801 );
448 					end loop;
449 
450 					Debug('p_operator:          ' || g_opp_selection_tab(i).operator);
451 					Debug('p_delimiter:         ' || l_delimiter);
452 					Debug('p_return_type:   '     || l_entity_attr_value(l_attribute_id).return_type);
453 				END IF;
454 
455 				l_matched := pv_check_match_pub.Check_Match(
456                          p_attribute_id       => l_attribute_id,
457                          p_entity_attr_value  => l_entity_attr_value(l_attribute_id).attribute_value,
458                          p_rule_attr_value    => g_opp_selection_tab(i).attribute_value,
459                          p_rule_to_attr_value => g_opp_selection_tab(i).attribute_to_value,
460                          p_operator           => g_opp_selection_tab(i).operator,
461                          p_input_filter       => l_input_filter,
462                          p_delimiter          => l_delimiter,
463                          p_return_type        => l_entity_attr_value(l_attribute_id).return_type,
464                          p_rule_currency_code => g_opp_selection_tab(i).currency_code
465                       );
466 
467 				IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
468 					IF (l_matched) THEN
469 						Debug('Check_Match TRUE!');
470 					ELSE
471 						Debug('Check_Match FALSE!');
472 					END IF;
473 				END IF;
474 
475 				-- ---------------------------------------------------------------------------
476 				-- We have an OR logic here. Need special processing...Concatenate all the
477 				-- attribute values involved in the OR logic into one long string, and pass
478 				-- this string as the attribute value into Check_Match function.
479 				-- ---------------------------------------------------------------------------
480          ELSE
481             -- -------------------------------------------------------------
482             -- l_stop_at_index is the index where the current OR logic ends.
483             -- -------------------------------------------------------------
484             l_stop_at_index   := i + g_opp_selection_tab(i).count - 1;
485             l_concat_attr_val := l_delimiter;
486 
487             FOR j IN i..l_stop_at_index LOOP
488                l_concat_attr_val := l_concat_attr_val ||
489                                     g_opp_selection_tab(j).attribute_value || l_delimiter;
490 
491                l_concat_to_attr_val := l_concat_to_attr_val ||
492                                        g_opp_selection_tab(j).attribute_to_value || l_delimiter;
493             END LOOP;
494 
495 				IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
496 					Debug('Calling Check_Match...OR Logic');
497 					Debug('p_attribute_id:      ' || l_attribute_id);
498 					--Debug('p_entity_attr_value: ' || l_entity_attr_value(l_attribute_id).attribute_value);
499 					l_attr_val_temp := l_entity_attr_value(l_attribute_id).attribute_value;
500 					while (l_attr_val_temp is not null) loop
501 						Debug('p_entity_attr_value: ' || substr( l_attr_val_temp, 1, 1800 ) );
502 						l_attr_val_temp := substr( l_attr_val_temp, 1801 );
503 					end loop;
504 
505 					--Debug('p_rule_attr_value:   ' || l_concat_attr_val);
506 					l_attr_val_temp := l_concat_attr_val;
507 					while (l_attr_val_temp is not null) loop
508 						Debug('p_rule_attr_value: ' || substr( l_attr_val_temp, 1, 1800 ) );
509 						l_attr_val_temp := substr( l_attr_val_temp, 1801 );
510 					end loop;
511 
512                Debug('p_operator:          ' || g_opp_selection_tab(i).operator);
513                Debug('p_delimiter:         ' || l_delimiter);
514                Debug('p_return_type:       ' || l_entity_attr_value(l_attribute_id).return_type);
515             END IF;
516 
517             l_matched := pv_check_match_pub.Check_Match(
518                             p_attribute_id       => l_attribute_id,
519                             p_entity_attr_value  => l_entity_attr_value(l_attribute_id).attribute_value,
520                             p_rule_attr_value    => l_concat_attr_val,
521                             p_rule_to_attr_value => l_concat_to_attr_val,
522                             p_operator           => g_opp_selection_tab(i).operator,
523                             p_input_filter       => l_input_filter,
524                             p_delimiter          => l_delimiter,
525                             p_return_type        => l_entity_attr_value(l_attribute_id).return_type,
526                             p_rule_currency_code => g_opp_selection_tab(i).currency_code
527                          );
528 
529 				IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
530 					IF (l_matched) THEN
531 						Debug('Check_Match TRUE!');
532 					ELSE
533 						Debug('Check_Match FALSE!');
534 					END IF;
535 				END IF;
536 
537             -- ------------------------------------------------------
538             -- Advance i to the last record involved in the OR logic.
539             -- ------------------------------------------------------
540             i := l_stop_at_index;
541 			END IF;
542 
543          -- ------------------------------------------------------------------------
544          -- The attribute value match fails. Advance to the next rule.
545          -- ------------------------------------------------------------------------
546 			IF (NOT l_matched) THEN
547             -- ---------------------------------------------------------------------------
548             -- If there are no more rules in the group, it will be set to g_no_more_rules.
549             -- ---------------------------------------------------------------------------
550             i := Get_Next_Rule_Index(i, g_opp_selection_tab);
551 
552 				-- ------------------------------------------------------------------------
553 				-- The attribute value match succeeds. Check if the current record is the
554 				-- last record/attribute in the rule.  If yes, there's a match between
555 				-- this opportunity and the rule. Set l_stop_flag to TRUE to stop processing.
556 				-- ------------------------------------------------------------------------
557 			ELSE
558 				IF (g_opp_selection_tab(i).last_attr_flag = 'Y') THEN
559 					IF (l_matching_type = 'STOP_AT_FIRST_RULE') THEN
560                   l_stop_flag := TRUE;
561                END IF;
562 
563                -- -------------------------------------------------------------
564                -- The current rule is selected for this opportunity.
565                -- -------------------------------------------------------------
566                x_selected_rule_id := g_opp_selection_tab(i).process_rule_id;
567 
568                IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
569                   Debug('%%%%%%%Selected Rule ID: ' || x_selected_rule_id);
570                   Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
571                   Debug('Number of rule items scanned/evaluated before finding a matching rule: ' || i);
572                END IF;
573 
574                -- -------------------------------------------------------------
575                -- Perform Partner Selection - call matching engine.
576                -- pv_match_pub package.form_where_clause --> pass in a record
577                -- of tables (operator, attribute, attribute_value) +
578                -- "selection mode" --> Only partners which match all search
579                -- attributes are returned.
580                -- -------------------------------------------------------------
581                IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
582                   Debug('..........................................................');
583                   Debug('Calling Partner_Selection................................');
584                END IF;
585 
586                Partner_Selection(
587                   p_api_version     => 1.0,
588                   p_process_rule_id => x_selected_rule_id,
589                   p_entity_id       => p_entity_id,
590                   p_entity          => p_entity,
591                   p_user_name       => p_user_name,
592                   p_resource_id     => p_resource_id,
593                   p_routing_flag    => p_routing_flag,
594                   x_partner_cnt     => l_partner_cnt,
595                   x_return_status   => l_return_status,
596                   x_msg_count       => l_msg_count,
597                   x_msg_data        => l_msg_data
598 					);
599 
600 					IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
601 						RAISE FND_API.G_EXC_ERROR;
602 
603 					ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
604 						RAISE FND_API.g_exc_unexpected_error;
605 					END IF;
606 
607 					-- ------------------------------------------------------------
608 					-- Log the selected rules if the matching engine type is
609 					-- 'BACKGROUND PARTNER MATCHING'. This provides a snapshot of what
610 					-- actually occurred in partner matching.
611 					-- ------------------------------------------------------------
612 					IF (g_matching_engine_type = 'BACKGROUND_PARTNER_MATCHING') THEN
613 						IF (l_partner_cnt > 0) THEN
614 							l_winning_rule_flag := 'Y';
615 						ELSE
616 							l_winning_rule_flag := 'N';
617 						END IF;
618 
619 						l_entity_rule_applied_id := null;
620 
621 						PV_ENTITY_RULES_APPLIED_PKG.Insert_Row(
622 						px_ENTITY_RULE_APPLIED_ID => l_entity_rule_applied_id,
623 						p_LAST_UPDATE_DATE        => SYSDATE,
624 						p_LAST_UPDATED_BY         => p_resource_id,
625 						p_CREATION_DATE           => SYSDATE,
626 						p_CREATED_BY              => p_resource_id,
627 						p_LAST_UPDATE_LOGIN       => p_resource_id,
628 						p_OBJECT_VERSION_NUMBER   => 1,
629 						p_REQUEST_ID              => FND_API.G_MISS_NUM,
630 						p_PROGRAM_APPLICATION_ID  => FND_API.G_MISS_NUM,
631 						p_PROGRAM_ID              => FND_API.G_MISS_NUM,
632 						p_PROGRAM_UPDATE_DATE     => SYSDATE,
633 						p_ENTITY                  => p_entity,
634 						p_ENTITY_ID               => p_entity_id,
635 						p_PROCESS_RULE_ID         => x_selected_rule_id,
636 						p_PARENT_PROCESS_RULE_ID  => FND_API.G_MISS_NUM,
637 						p_LATEST_FLAG             => FND_API.G_MISS_CHAR,
638 						p_ACTION_VALUE            => FND_API.G_MISS_CHAR,
639 						p_PROCESS_TYPE            => 'BACKGROUND_PARTNER_MATCHING',
640 						p_WINNING_RULE_FLAG       => l_winning_rule_flag,
641 						p_entity_detail           => FND_API.G_MISS_CHAR,
642 						p_ATTRIBUTE_CATEGORY      => FND_API.G_MISS_CHAR,
643 						p_ATTRIBUTE1              => FND_API.G_MISS_CHAR,
644 						p_ATTRIBUTE2              => FND_API.G_MISS_CHAR,
645 						p_ATTRIBUTE3              => FND_API.G_MISS_CHAR,
646 						p_ATTRIBUTE4              => FND_API.G_MISS_CHAR,
647 						p_ATTRIBUTE5              => FND_API.G_MISS_CHAR,
648 						p_ATTRIBUTE6              => FND_API.G_MISS_CHAR,
649 						p_ATTRIBUTE7              => FND_API.G_MISS_CHAR,
650 						p_ATTRIBUTE8              => FND_API.G_MISS_CHAR,
651 						p_ATTRIBUTE9              => FND_API.G_MISS_CHAR,
652 						p_ATTRIBUTE10             => FND_API.G_MISS_CHAR,
653 						p_ATTRIBUTE11             => FND_API.G_MISS_CHAR,
654 						p_ATTRIBUTE12             => FND_API.G_MISS_CHAR,
655 						p_ATTRIBUTE13             => FND_API.G_MISS_CHAR,
656 						p_ATTRIBUTE14             => FND_API.G_MISS_CHAR,
657 						p_ATTRIBUTE15             => FND_API.G_MISS_CHAR,
658 						p_PROCESS_STATUS          => FND_API.G_MISS_CHAR
659 						);
660 					END IF;
661 
662 					-- ------------------------------------------------------------
663 					-- If there are no partners returned, go on to the next rule
664 					-- to find a matching partner until all rules are exhausted.
665 					-- ------------------------------------------------------------
666                IF (l_matching_type = 'EXHAUST_ALL_RULES') THEN
667 						IF (l_partner_cnt = 0) THEN
668 							-- reset failure code
669 							g_failure_code := NULL;
670 							i := i + 1;
671 
672 						ELSIF (l_partner_cnt > 0) THEN
673 							l_stop_flag := TRUE;
674 						END IF;
675 					END IF;
676 
677 				ELSE
678                -- ------------------------------
679                -- Advance to the next attribute
680                -- ------------------------------
681                i := i + 1;
682             END IF;
683 
684 			END IF;
685 		END IF;
686 	END LOOP;
687 
688 	IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
689 		Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
690 	END IF;
691 
692 	IF (NOT l_stop_flag) THEN
693 		IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
694 			Debug('No matching rules found!!!!!');
695 		END IF;
696 	END IF;
697 
698   x_partner_cnt := l_partner_cnt;
699 
700    IF (g_rule_engine_trace_flag = 'Y') THEN
701       FND_MSG_PUB.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
702                                  p_count     =>  x_msg_count,
703                                  p_data      =>  x_msg_data);
704    END IF;
705 
706    -------------------- Exception --------------------------
707    EXCEPTION
708       WHEN FND_API.G_EXC_ERROR THEN
709          x_return_status := FND_API.G_RET_STS_ERROR;
710          FND_MSG_PUB.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
711                                     p_count     =>  x_msg_count,
712                                     p_data      =>  x_msg_data);
713 
714       WHEN FND_API.g_exc_unexpected_error THEN
715          x_return_status := FND_API.g_ret_sts_unexp_error;
716          FND_MSG_PUB.count_and_get(
717                p_encoded => FND_API.g_false,
718                p_count   => x_msg_count,
719                p_data    => x_msg_data
720          );
721 
722       WHEN g_e_buffer_too_small THEN
723          x_return_status := l_return_status;
724 
725       WHEN OTHERS THEN
726         IF FND_MSG_PUB.check_msg_level(FND_MSG_PUB.g_msg_lvl_unexp_error) THEN
727            FND_MSG_PUB.add_exc_msg(g_pkg_name, l_api_name);
728         END IF;
729 
730         x_return_status := FND_API.G_RET_STS_ERROR;
731         FND_MSG_PUB.count_and_get(
732               p_encoded => FND_API.g_false,
733               p_count   => x_msg_count,
734               p_data    => x_msg_data
735         );
736 
737 
738 END Opportunity_Selection;
739 -- ===========================End of Opportunity_Selection===========================
740 
741 
742 -- ===========================End of Partner_Selection=============================
743 PROCEDURE Partner_Selection(
744    p_api_version            IN  NUMBER,
745    p_init_msg_list          IN  VARCHAR2  := FND_API.g_false,
746    p_commit                 IN  VARCHAR2  := FND_API.g_false,
747    p_validation_level       IN  NUMBER    := FND_API.g_valid_level_full,
748    p_process_rule_id        IN  NUMBER,
749    p_entity_id              IN  NUMBER,
750    p_entity                 IN  VARCHAR2,
751    p_user_name              IN  VARCHAR2  := NULL,
752    p_resource_id            IN  NUMBER    := NULL,
753    p_routing_flag           IN  VARCHAR2,
754    x_partner_cnt            OUT NOCOPY NUMBER,
755    x_return_status          OUT NOCOPY VARCHAR2,
756    x_msg_count              OUT NOCOPY NUMBER,
757    x_msg_data               OUT NOCOPY VARCHAR2
758 ) IS
759    -- -------------------------------------------------------------------------
760    -- Cursor for retrieving partner-to-opportunity mapping for a process rule.
761    -- -------------------------------------------------------------------------
762    CURSOR lc_partner_mapping IS
763       SELECT a.source_attr_id, a.target_attr_id, a.operator, b.return_type
764       FROM   pv_entity_attr_mappings a,
765              pv_attributes_vl b
766       WHERE  a.target_attr_id   = b.attribute_id AND
767              a.process_rule_id  = p_process_rule_id AND
768              a.source_attr_type = 'LEAD' AND
769              --a.source_attr_type = 'OPPORTUNITY' AND
770              a.target_attr_type = 'PARTNER';
771 
772    -- -------------------------------------------------------------------------
773    -- Cursor for retrieving partner selection attribute-value pairs.
774    -- -------------------------------------------------------------------------
775    CURSOR lc_partner_selection IS
776       SELECT a.attribute_id, a.operator,
777              b.attribute_value, b.attribute_to_value,
778              a.selection_criteria_id,
779              c.return_type
780       FROM   pv_enty_select_criteria a,
781              pv_selected_attr_values b,
782              pv_attributes_vl c
783       WHERE  a.attribute_id          = c.attribute_id AND
784              a.selection_criteria_id = b.selection_criteria_id (+) AND
785              a.selection_type_code   = 'PARTNER_SELECTION' AND
786              a.process_rule_id       = p_process_rule_id
787       ORDER  BY a.attribute_id, b.selection_criteria_id;
788 
789    -- -------------------------------------------------------------------------
790    -- Cursor for retrieving geo proximity and routing information.
791    -- -------------------------------------------------------------------------
792    CURSOR lc_entity_routings (p_selected_rule_id IN NUMBER) IS
793       SELECT entity_routing_id, max_nearest_partner, distance_from_customer,
794              distance_uom_code, routing_type,
795              NVL(bypass_cm_ok_flag, 'N') bypass_cm_ok_flag
796       FROM   pv_entity_routings
797       WHERE  process_rule_id = p_selected_rule_id;
798 
799    -- -------------------------------------------------------------------------
800    -- Cursor for retrieving location_id for the opportunity (customer).
801    -- -------------------------------------------------------------------------
802    CURSOR lc_get_location_id (p_entity_id IN NUMBER) IS
803       SELECT b.location_id
804       FROM   as_leads_all   a,
805              hz_party_sites b,
806              hz_locations   l
807       WHERE  a.lead_id       = p_entity_id AND
808              a.customer_id   = b.party_id AND
809              b.party_site_id = a.address_id AND
810              b.location_id   = l.location_id AND
811              l.geometry IS NOT NULL;
812 
813    -- -------------------------------------------------------------------------
814    -- Cursor for retrieving the process rule name.
815    -- -------------------------------------------------------------------------
816    CURSOR lc_get_process_rule_name (p_process_rule_id IN NUMBER) IS
817       SELECT process_rule_name
818       FROM   pv_process_rules_vl
819       WHERE  process_rule_id = p_process_rule_id;
820 
821    x_partner_tbl           JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
822    x_distance_uom_returned VARCHAR2(30);
823    x_distance_tbl          JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
824 
825    l_entity_routing     lc_entity_routings%ROWTYPE;
826 
827    l_api_version         NUMBER := 1.0;
828    l_api_name            VARCHAR2(30) := 'Partner_Selection';
829    l_entity_attr_value   pv_check_match_pub.t_entity_attr_value;
830    l_temp                VARCHAR2(4000);
831    l_num_of_tokens       NUMBER;
832    l_attribute_id        NUMBER;
833    l_attribute_value     VARCHAR2(4000);
834    l_return_status       VARCHAR2(100);
835    l_msg_count           NUMBER;
836    l_msg_data            VARCHAR2(500);
837    l_delimiter           VARCHAR2(10) := '+++';
838    l_start               NUMBER;
839    i                     NUMBER := 1;
840    j                     NUMBER;
841    k                     NUMBER := 1;
842    l_resource_id         NUMBER;
843    l_user_name           VARCHAR2(100);
844    l_first_record        BOOLEAN := TRUE;
845    l_previous_attr_id    NUMBER;
846    l_previous_sc_id      NUMBER;
847    l_previous_operator   VARCHAR2(100);
848    l_previous_return_type VARCHAR2(100);
849 
850    l_customer_address    pv_locator.party_address_rec_type;
851    l_distance_uom        VARCHAR2(30);
852    --l_distance_uom_returned VARCHAR2(30);
853 
854    l_attr_id_tbl         JTF_NUMBER_TABLE       := JTF_NUMBER_TABLE();
855    l_attr_value_tbl      JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
856    l_attr_operator_tbl   JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
857    l_attr_data_type_tbl  JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
858 
859    l_source_tbl          JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
860    l_rank_tbl            JTF_NUMBER_TABLE       := JTF_NUMBER_TABLE();
861    l_extra_partner_details JTF_VARCHAR2_TABLE_1000 := JTF_VARCHAR2_TABLE_1000();
862 
863    -- l_partner_tbl_temp    JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
864    l_partner_tbl         JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
865 -- vansub
866    l_partner_id_tbl      JTF_NUMBER_TABLE        := JTF_NUMBER_TABLE();
867 --
868    l_partner_details     JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
869    l_flagcount           JTF_VARCHAR2_TABLE_100  := JTF_VARCHAR2_TABLE_100();
870 
871    l_stop_flag           BOOLEAN := FALSE;
872 
873    l_partner_distance_tbl       DBMS_SQL.NUMBER_TABLE;
874    l_preferred_partner_party_id NUMBER;
875    l_distance_tbl               JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
876    l_rule_currency_code         VARCHAR2(15);
877    l_entity_routings_exists     BOOLEAN := TRUE;
878    l_preferred_idx              NUMBER;
879    l_process_rule_name          VARCHAR2(100);
880       l_attr_val_temp		VARCHAR2(4000);
881 BEGIN
882    -------------------- initialize -------------------------
883    IF FND_API.to_boolean(p_init_msg_list) THEN
884       FND_MSG_PUB.initialize;
885    END IF;
886 
887    IF NOT FND_API.compatible_api_call(
888          l_api_version,
889          p_api_version,
890          l_api_name,
891          g_pkg_name
892    ) THEN
893       RAISE FND_API.g_exc_unexpected_error;
894    END IF;
895 
896    x_return_status := FND_API.G_RET_STS_SUCCESS;
897 
898    -------------------------- Source code --------------------
899 
900    -- ------------------------------------------------------------------------
901    -- Make sure that either p_user_name or p_resource IS NOT NULL.
902    -- ------------------------------------------------------------------------
903    IF (p_user_name IS NULL AND p_resource_id IS NULL) THEN
904       Set_Message(p_msg_level    => FND_MSG_PUB.G_MSG_LVL_ERROR,
905                   p_msg_name     => 'PV_NO_USERNAME_ID_DEFINED',
906                   p_token1       => null,
907                   p_token1_value => null,
908                   p_token2       => null,
909                   p_token2_value => null);
910 
911       g_failure_code := 'OTHER';
912       RAISE FND_API.G_EXC_ERROR;
913    END IF;
914 
915 
916    -- ------------------------------------------------------------------------
917    -- Retrieve profile value for stack trace profile option.
918    -- ------------------------------------------------------------------------
919    --g_rule_engine_trace_flag := NVL(FND_PROFILE.VALUE('PV_RULE_ENGINE_TRACE_ON'), 'N');
920 
921    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
922       Debug('............................................................');
923       Debug('Stack trace turned on? ' || g_rule_engine_trace_flag);
924       Debug('............................................................');
925 
926       Debug('  ');
927       Debug('Routing Flag is ' || p_routing_flag);
928       Debug('***Rule ID Selected Is: ' || p_process_rule_id || '***');
929    END IF;
930 
931    -- -------------------------------------------------------------
932    -- Retrieve Entity Routings info (geo proximity and routings)
933    -- -------------------------------------------------------------
934    OPEN  lc_entity_routings(p_process_rule_id);
935    FETCH lc_entity_routings INTO l_entity_routing;
936 
937    IF (lc_entity_routings%NOTFOUND) THEN
938       l_entity_routings_exists := FALSE;
939    END IF;
940 
941    CLOSE lc_entity_routings;
942 
943    -- -------------------------------------------------------------
944    -- Retrieve location_id for the opportunity (customer).
945    -- -------------------------------------------------------------
946    FOR x IN lc_get_location_id(p_entity_id) LOOP
947       l_customer_address.location_id := x.location_id;
948    END LOOP;
949 
950    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
951       Debug('***l_entity_routing.max_nearest_partner: ' || l_entity_routing.max_nearest_partner || '***');
952       Debug('***l_entity_routing.distance_from_customer: ' || l_entity_routing.distance_from_customer || '***');
953    END IF;
954 
955    IF (l_entity_routings_exists AND
956       (l_entity_routing.max_nearest_partner IS NOT NULL OR
957        l_entity_routing.distance_from_customer IS NOT NULL) AND
958        l_customer_address.location_id IS NULL)
959    THEN
960       Set_Message(p_msg_level    => FND_MSG_PUB.G_MSG_LVL_ERROR,
961                   p_msg_name     => 'PV_NO_GEOMETRY_INFO',
962                   p_token1       => 'TEXT',
963                   p_token1_value => 'Entity ID: ' || p_entity_id,
964                   p_token2       => null,
965                   p_token2_value => null);
966 
967       g_failure_code := 'OTHER';
968       RAISE FND_API.G_EXC_ERROR;
969    END IF;
970 
971 
972    -- ------------------------------------------------------------------------
973    -- Retrieve the rule's currency_code.
974    -- ------------------------------------------------------------------------
975 
976    BEGIN
977       SELECT currency_code
978       INTO   l_rule_currency_code
979       FROM   pv_process_rules_b
980       WHERE  process_rule_id = p_process_rule_id;
981 
982       EXCEPTION
983        WHEN NO_DATA_FOUND THEN
984         IF (l_process_rule_name IS NULL) THEN
985            FOR x IN lc_get_process_rule_name(p_process_rule_id) LOOP
986               l_process_rule_name := x.process_rule_name;
987            END LOOP;
988         END IF;
989 
990         Set_Message(p_msg_level    => FND_MSG_PUB.G_MSG_LVL_ERROR,
991                     p_msg_name     => 'PV_DEBUG_MSG',
992                     p_token1       => 'TEXT',
993                     p_token1_value => 'This rule "' || l_process_rule_name ||
994                                       '" (ID: ' || p_process_rule_id || ') does not exist',
995                     p_token2       => null,
996                     p_token2_value => null);
997 
998         g_failure_code := 'OTHER';
999         RAISE FND_API.G_EXC_ERROR;
1000    END;
1001 
1002    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1003       Debug('Rule Currency is: ' || l_rule_currency_code);
1004    END IF;
1005 
1006    -- ========================================================================
1007    -- Opportunity-Partner Attribute Mapping                                  =
1008    -- ========================================================================
1009    -- ------------------------------------------------------------------------
1010    -- Loop through opportunity-partner attribute mappings and retrieve the
1011    -- attribute values of each of the attributes in mapping.
1012    -- ------------------------------------------------------------------------
1013    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1014       Debug('Retrieve opportunity-to-partner attribute mapping..................');
1015    END IF;
1016 
1017    FOR lc_cursor IN lc_partner_mapping LOOP
1018       l_attribute_id := lc_cursor.source_attr_id;
1019 
1020       -- ---------------------------------------------------------------------
1021       -- Retrieve opportunity's attribute value if it hasn't already been
1022       -- retrieved.
1023       -- ---------------------------------------------------------------------
1024       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1025          Debug('Attribute ID before calling Get_Entity_Attr_Values: ' || l_attribute_id);
1026          --Debug('Entity Type: ' || p_entity);
1027       END IF;
1028 
1029       pv_check_match_pub.Get_Entity_Attr_Values(
1030          p_api_version_number => 1.0,
1031          p_attribute_id       => l_attribute_id,
1032          p_entity             => p_entity,
1033          p_entity_id          => p_entity_id,
1034          p_delimiter          => l_delimiter,
1035          p_expand_attr_flag   => 'N',
1036          x_entity_attr_value  => l_entity_attr_value,
1037          x_return_status      => l_return_status,
1038          x_msg_count          => l_msg_count,
1039          x_msg_data           => l_msg_data
1040       );
1041 
1042       IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
1043          g_failure_code := 'OTHER';
1044          RAISE FND_API.G_EXC_ERROR;
1045 
1046       ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
1047          g_failure_code := 'OTHER';
1048          RAISE FND_API.g_exc_unexpected_error;
1049 
1050       ELSE
1051          -- ---------------------------------------------------------------------
1052          -- Note that l_entity_attr_value stores concatenated attribute values
1053          -- with delimiters in the beginning and end of the string.
1054          -- e.g. +++USA+++UK+++
1055          --
1056          -- However, pv_match_pub.form_where_clause API expects a string without
1057          -- leading and trailing delimiters:
1058          -- e.g. USA+++UK
1059          --
1060          -- Therefore, we need to take these two delimiters out of the string
1061          -- before passing it to the API as a parameter.
1062          -- ---------------------------------------------------------------------
1063          l_temp := l_entity_attr_value(l_attribute_id).attribute_value;
1064 
1065          -- ---------------------------------------------------------------------
1066          -- Populate PL/SQL table only when the attribute value string IS NOT NULL.
1067          -- ---------------------------------------------------------------------
1068          IF (l_temp IS NOT NULL AND l_temp <> '++++++') THEN
1069             l_num_of_tokens := pv_check_match_pub.Get_Num_Of_Tokens(l_delimiter, l_temp);
1070 
1071             l_attr_id_tbl.EXTEND(l_num_of_tokens);
1072             l_attr_value_tbl.EXTEND(l_num_of_tokens);
1073             l_attr_operator_tbl.EXTEND(l_num_of_tokens);
1074             l_attr_data_type_tbl.EXTEND(l_num_of_tokens);
1075 
1076             -- ------------------------------------------------------------------
1077             -- Everything under the mapping section should be treated as AND
1078             -- condition, which requires one table element per item.
1079             -- ------------------------------------------------------------------
1080             FOR j IN 1..l_num_of_tokens LOOP
1081                l_attribute_value := pv_check_match_pub.Retrieve_Token(
1082                                        p_delimiter         => l_delimiter,
1083                                        p_attr_value_string => l_temp,
1084                                        p_input_type        => 'STD TOKEN',
1085                                        p_index             => j
1086                                     );
1087 
1088 /*
1089                IF (lc_cursor.return_type = 'CURRENCY') THEN
1090                   l_attribute_value := l_attribute_value || ':::' || l_rule_currency_code ||
1091                                        TO_CHAR(SYSDATE, 'yyyymmddhh24miss');
1092                END IF;
1093 */
1094                l_attr_id_tbl(i)        := lc_cursor.target_attr_id;
1095                l_attr_value_tbl(i)     := l_attribute_value;
1096                l_attr_operator_tbl(i)  := lc_cursor.operator;
1097                l_attr_data_type_tbl(i) := lc_cursor.return_type;
1098 
1099                i := i + 1;
1100             END LOOP;
1101          END IF;
1102       END IF;
1103    END LOOP;
1104 
1105    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1106       Debug('Partner Matching/Mapping Attributes...');
1107 
1108       FOR i IN 1..l_attr_id_tbl.COUNT LOOP
1109 
1110 	    l_attr_val_temp := l_attr_value_tbl(i);
1111    	        while (l_attr_val_temp is not null) loop
1112 		Debug(i || '-->' ||l_attr_id_tbl(i) || ': ' || substr( l_attr_val_temp, 1, 1800 ) ||
1113 	            ':::' || l_attr_operator_tbl(i) || ':::' || l_attr_data_type_tbl(i));
1114 		l_attr_val_temp := substr( l_attr_val_temp, 1801 );
1115 		end loop;
1116       END LOOP;
1117 
1118       Debug('-----------------------------------------');
1119 
1120       Debug('Appending Partner Selection Attributes...');
1121    END IF;
1122 
1123    k := i;
1124 
1125    -- ========================================================================
1126    -- Partner Selection Attributes                                           =
1127    -- ========================================================================
1128    -- ------------------------------------------------------------------------
1129    -- Get partner selection attribute value and append them to the record
1130    -- of tables, l_match_attr_rec.
1131    -- The following code also performs AND/OR logic.  Attribute values
1132    -- involved in an OR logic will be concatenated in a string separated
1133    -- by a delimiter.
1134    -- ------------------------------------------------------------------------
1135    FOR x IN lc_partner_selection LOOP
1136       IF (l_previous_attr_id = x.attribute_id AND
1137           l_previous_sc_id   = x.selection_criteria_id)
1138       THEN
1139          l_attr_value_tbl(i - 1) := l_attr_value_tbl(i - 1) ||
1140                                     l_delimiter || x.attribute_value;
1141 
1142          IF (x.return_type = 'CURRENCY') THEN
1143             l_attr_value_tbl(i - 1) := l_attr_value_tbl(i - 1) || ':::' ||
1144                l_rule_currency_code || ':::' || TO_CHAR(SYSDATE, 'yyyymmddhh24miss');
1145          END IF;
1146 
1147       ELSE
1148          l_attr_id_tbl.EXTEND;
1149          l_attr_value_tbl.EXTEND;
1150          l_attr_operator_tbl.EXTEND;
1151          l_attr_data_type_tbl.EXTEND;
1152 
1153          l_attr_value_tbl(i)      := x.attribute_value;
1154          l_attr_id_tbl(i)         := x.attribute_id;
1155          l_attr_data_type_tbl(i)  := x.return_type;
1156          l_attr_operator_tbl(i)   := x.operator;
1157 
1158          IF (x.return_type = 'CURRENCY') THEN
1159             l_attr_value_tbl(i) := l_attr_value_tbl(i) || ':::' ||
1160                l_rule_currency_code || ':::' || TO_CHAR(SYSDATE, 'yyyymmddhh24miss');
1161          END IF;
1162 
1163          IF (x.operator = 'BETWEEN') THEN
1164             l_attr_operator_tbl(i) := '>=';
1165 
1166             i := i + 1;
1167             l_attr_id_tbl.EXTEND;
1168             l_attr_value_tbl.EXTEND;
1169             l_attr_operator_tbl.EXTEND;
1170             l_attr_data_type_tbl.EXTEND;
1171             l_attr_operator_tbl(i)   := '<=';
1172             l_attr_id_tbl(i)         := x.attribute_id;
1173             l_attr_data_type_tbl(i)  := x.return_type;
1174             l_attr_value_tbl(i)      := x.attribute_to_value;
1175 
1176             IF (x.return_type = 'CURRENCY') THEN
1177                l_attr_value_tbl(i) := l_attr_value_tbl(i) ||
1178                                       ':::' || 'USD' || ':::' ||
1179                                       TO_CHAR(SYSDATE, 'yyyymmddhh24miss');
1180             END IF;
1181          END IF;
1182 
1183          i := i + 1;
1184       END IF;
1185 
1186       l_previous_attr_id := x.attribute_id;
1187       l_previous_sc_id   := x.selection_criteria_id;
1188    END LOOP;
1189 
1190 
1191    -- ------------------------------------------------------------------------
1192    -- For debugging only...
1193    -- ------------------------------------------------------------------------
1194    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1195       FOR i IN k..l_attr_id_tbl.COUNT LOOP
1196          --since fnd_msg_pub supports debiug message of length 1972
1197 	 -- we are passing split of attribute value as it may exceed 2000 length
1198 	 l_attr_val_temp := l_attr_value_tbl(i);
1199 	 while (l_attr_val_temp is not null) loop
1200 	    Debug(i || '-->' || l_attr_id_tbl(i) || ': ' || substr( l_attr_val_temp, 1, 1800 ) ||
1201             ':::' || l_attr_operator_tbl(i) || ':::' || l_attr_data_type_tbl(i));
1202 	    l_attr_val_temp := substr( l_attr_val_temp, 1801 );
1203          end loop;
1204       END LOOP;
1205    END IF;
1206 
1207    -- ------------------------------------------------------------------------
1208    -- Perform Partner Matching...
1209    -- ------------------------------------------------------------------------
1210    IF (p_resource_id IS NULL) THEN
1211       SELECT resource_id
1212       INTO   l_resource_id
1213       FROM   fnd_user a, jtf_rs_resource_extns b
1214       WHERE  a.user_id   = b.user_id AND
1215              a.user_name = p_user_name;
1216    ELSE
1217       l_resource_id := p_resource_id;
1218    END IF;
1219 
1220    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1221       Debug('..........................................................');
1222       Debug('Calling Form_Where_Clause.......................');
1223    END IF;
1224 
1225    l_start := DBMS_UTILITY.get_time;
1226 
1227    pv_match_v2_pub.Form_Where_Clause(
1228      p_api_version_number  => p_api_version,
1229      p_attr_id_tbl         => l_attr_id_tbl,
1230      p_attr_value_tbl      => l_attr_value_tbl,
1231      p_attr_operator_tbl   => l_attr_operator_tbl,
1232      p_attr_data_type_tbl  => l_attr_data_type_tbl,
1233      p_attr_selection_mode => 'OR',
1234      p_att_delmter         => l_delimiter,
1235      p_selection_criteria  => 'ALL',
1236      p_resource_id         => l_resource_id,
1237      p_lead_id             => p_entity_id,
1238      p_auto_match_flag     => 'N',
1239      x_matched_id          => x_partner_tbl,
1240      x_return_status       => l_return_status,
1241      x_msg_count           => l_msg_count,
1242      x_msg_data            => l_msg_data
1243    );
1244 
1245    -- -----------------------------------------------------------
1246    -- RULE_FOUND_NO_PARTNER...
1247    -- -----------------------------------------------------------
1248    IF (NOT x_partner_tbl.EXISTS(1)) THEN
1249       g_failure_code := 'RULE_FOUND_NO_PARTNER';
1250    END IF;
1251 
1252    IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
1253       RAISE FND_API.G_EXC_ERROR;
1254 
1255    ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
1256       RAISE FND_API.g_exc_unexpected_error;
1257    END IF;
1258 
1259    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1260       Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
1261 
1262       Debug('# of Partners Matched: ' || x_partner_tbl.COUNT);
1263       Debug('Partners Matched: ');
1264 
1265       FOR i IN 1..x_partner_tbl.COUNT LOOP
1266          Debug(x_partner_tbl(i) || ',');
1267       END LOOP;
1268 
1269       Debug('..........................................................');
1270       Debug('Retrieving GEO Proximity and Routings Info...');
1271    END IF;
1272 
1273 
1274    -- -------------------------------------------------------------
1275    -- Geographic proximity restrictions.
1276    -- -------------------------------------------------------------
1277    IF (l_entity_routing.entity_routing_id IS NOT NULL) THEN
1278       IF (l_entity_routing.distance_uom_code = 'KILOMETERS') THEN
1279          l_distance_uom := pv_locator.g_distance_unit_km;
1280 
1281          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1282             Debug('Distance Unit: ' || l_distance_uom);
1283          END IF;
1284 
1285       ELSIF (l_entity_routing.distance_uom_code = 'MILES') THEN
1286          l_distance_uom := pv_locator.g_distance_unit_mile;
1287 
1288          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1289             Debug('Distance Unit: ' || l_distance_uom);
1290          END IF;
1291 
1292       ELSE
1293          --l_distance_uom := pv_locator.g_distance_unit_mile;
1294 
1295          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1296             Debug('No Distance Unit Specified. Use the default from the pv_locator profile.');
1297          END IF;
1298       END IF;
1299 
1300    ELSE
1301       --l_distance_uom := pv_locator.g_distance_unit_mile;
1302 
1303       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1304          Debug('No Distance Unit Specified. Use the default from the pv_locator profile.');
1305       END IF;
1306    END IF;
1307 
1308 
1309    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1310       Debug('Geo Proximity and Routing Parameters..............................');
1311       Debug('Location ID: ' || l_customer_address.location_id);
1312       Debug('Distance from partner: ' || l_entity_routing.distance_from_customer);
1313       Debug('Max # of partners to be returned: ' || l_entity_routing.max_nearest_partner);
1314       Debug('Distance UOM Code: ' || l_entity_routing.distance_uom_code);
1315       Debug('Routing Type: ' || l_entity_routing.routing_type);
1316    END IF;
1317 
1318    -- ------------------------------------------------------------------------
1319    -- Perform Geo Proximity Restrictions...
1320    --
1321    -- Execute Geo Proximity API only when there is at least one partner
1322    -- returned from Partner Matching above.
1323    -- ------------------------------------------------------------------------
1324 
1325    l_partner_id_tbl := x_partner_tbl;
1326 
1327    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1328       Debug('# of Partners Sent: ' || x_partner_tbl.COUNT);
1329    END IF;
1330 
1331 
1332    IF (l_partner_id_tbl.EXISTS(1) AND l_partner_id_tbl.COUNT > 0) THEN
1333       -- -------------------------------------------------------------
1334       -- Execute geo proximity API.
1335       -- -------------------------------------------------------------
1336       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1337          Debug('..........................................................');
1338          Debug('Calling pv_locator.Get_Partners..........................');
1339          Debug('# of Partners Sent: ' || l_partner_id_tbl.COUNT);
1340       END IF;
1341 
1342       l_start := DBMS_UTILITY.get_time;
1343 
1344       pv_locator.Get_Partners (
1345          p_api_version      => p_api_version,
1346          p_customer_address => l_customer_address,
1347          p_partner_tbl      => l_partner_id_tbl,
1348          p_max_no_partners  => l_entity_routing.max_nearest_partner,
1349          p_distance         => l_entity_routing.distance_from_customer,
1350          p_distance_unit    => l_distance_uom,
1351          x_partner_tbl      => x_partner_tbl,
1352          x_distance_tbl     => x_distance_tbl,
1353          x_distance_unit    => x_distance_uom_returned,
1354          x_return_status    => l_return_status,
1355          x_msg_count        => l_msg_count,
1356          x_msg_data         => l_msg_data
1357       );
1358 
1359       IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
1360          g_failure_code := 'ELOCATION_LOOKUP_FAILURE';
1361          RAISE FND_API.G_EXC_ERROR;
1362 
1363       ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
1364          g_failure_code := 'ELOCATION_LOOKUP_FAILURE';
1365          RAISE FND_API.g_exc_unexpected_error;
1366       END IF;
1367 
1368       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1369          Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
1370       END IF;
1371 
1372       IF (x_distance_uom_returned = pv_locator.g_distance_unit_km) THEN
1373          x_distance_uom_returned := 'KILOMETERS';
1374 
1375       ELSIF (x_distance_uom_returned = pv_locator.g_distance_unit_mile) THEN
1376          x_distance_uom_returned := 'MILES';
1377       END IF;
1378 
1379       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1380          Debug('Distance UOM returned is: ' || x_distance_uom_returned);
1381          Debug('# of Partners Returned: ' || x_partner_tbl.COUNT);
1382          Debug('Partners Matched and distance to customer: ');
1383       END IF;
1384 
1385 
1386       -- -------------------------------------------------------------
1387       -- Store partners' distance to customer.
1388       -- -------------------------------------------------------------
1389       FOR i IN 1..x_partner_tbl.COUNT LOOP
1390          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1391             Debug(x_partner_tbl(i) || ':::' || TRUNC(x_distance_tbl(i), 2));
1392          END IF;
1393 
1394          l_partner_distance_tbl(x_partner_tbl(i)) := x_distance_tbl(i);
1395       END LOOP;
1396 
1397 
1398       --Debug('...........Saved partner distance info..............');
1399       i := l_partner_distance_tbl.FIRST;
1400 
1401       WHILE (i <= l_partner_distance_tbl.LAST) LOOP
1402          --Debug(i || ':::' || TRUNC(l_partner_distance_tbl(i), 2));
1403          i := l_partner_distance_tbl.NEXT(i);
1404       END LOOP;
1405    END IF;
1406 
1407    -- -------------------------------------------------------------
1408    -- Tie-breaker
1409    -- -------------------------------------------------------------
1410    -- IF (l_entity_routing.routing_type IN ('SERIAL', 'SINGLE') AND
1411    IF (x_partner_tbl.EXISTS(1) AND x_partner_tbl.COUNT > 1) THEN
1412       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1413          Debug('..........................................................');
1414          Debug('Calling Tie_Breaker......................................');
1415          Debug('# of Partners Sent: ' || x_partner_tbl.COUNT);
1416       END IF;
1417 
1418       l_start := DBMS_UTILITY.get_time;
1419 
1420        Tie_Breaker(
1421           p_api_version     => p_api_version,
1422           p_process_rule_id => p_process_rule_id,
1423           x_partner_tbl     => x_partner_tbl,
1424           x_return_status   => l_return_status,
1425           x_msg_count       => l_msg_count,
1426           x_msg_data        => l_msg_data
1427        );
1428 
1429       IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
1430          g_failure_code := 'OTHER';
1431          RAISE FND_API.G_EXC_ERROR;
1432 
1433       ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
1434          g_failure_code := 'OTHER';
1435          RAISE FND_API.g_exc_unexpected_error;
1436       END IF;
1437 
1438       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1439          Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
1440       END IF;
1441    END IF;
1442 
1443    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1444       Debug('# of Partners Returned: ' || x_partner_tbl.COUNT);
1445    END IF;
1446 
1447    -- ------------------------------------------------------------------------------
1448    -- Retreive partner's detail info.
1449    -- ------------------------------------------------------------------------------
1450    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1451       Debug('Retrieve partners detail info.................................................');
1452    END IF;
1453 
1454    IF (x_partner_tbl.EXISTS(1)) THEN
1455       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1456          Debug('..........................................................');
1457          Debug('Calling Get_Matched_Partner_Details..........................');
1458       END IF;
1459 
1460       l_start := DBMS_UTILITY.get_time;
1461 
1462       IF (x_distance_tbl.EXISTS(1)) THEN
1463          FOR i IN 1..x_partner_tbl.COUNT LOOP
1464             x_distance_tbl(i) := l_partner_distance_tbl(x_partner_tbl(i));
1465          END LOOP;
1466 
1467          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1468             Debug('Partner Details and distance info...........................');
1469             FOR i IN 1..x_partner_tbl.COUNT LOOP
1470                Debug(x_partner_tbl(i) || ':::' || TRUNC(x_distance_tbl(i), 2));
1471                --Debug(x_partner_details(i));
1472             END LOOP;
1473          END IF;
1474       END IF;
1475 
1476       Get_Matched_Partner_Details(
1477             p_api_version_number    => 1.0,
1478             p_init_msg_list         => FND_API.G_FALSE,
1479             p_commit                => FND_API.G_FALSE,
1480             p_validation_level      => FND_API.G_VALID_LEVEL_FULL,
1481             p_lead_id               => p_entity_id,
1482             p_matched_id            => x_partner_tbl,
1483             p_distance_tbl          => x_distance_tbl,
1484             x_return_status         => l_return_status,
1485             x_msg_count             => l_msg_count,
1486             x_msg_data              => l_msg_data
1487       );
1488 
1489       IF (l_return_status = FND_API.G_RET_STS_ERROR) THEN
1490          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1491             Debug('Return Status: ' || l_return_status);
1492          END IF;
1493 
1494          g_failure_code := 'OTHER';
1495          RAISE FND_API.G_EXC_ERROR;
1496 
1497       ELSIF (l_return_status = FND_API.g_ret_sts_unexp_error) THEN
1498          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1499             Debug('Return Status: ' || l_return_status);
1500          END IF;
1501 
1502          g_failure_code := 'OTHER';
1503          RAISE FND_API.g_exc_unexpected_error;
1504       END IF;
1505 
1506       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1507          Debug('Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
1508       END IF;
1509 
1510       -- ------------------------------------------------------------------
1511       -- Reassign distance to each partner.
1512       -- ------------------------------------------------------------------
1513       IF (NOT x_distance_tbl.EXISTS(1)) THEN
1514          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1515             Debug('Initialize x_distance_tbl...');
1516          END IF;
1517 
1518          x_distance_tbl := JTF_NUMBER_TABLE();
1519       END IF;
1520 
1521    END IF;
1522 
1523    x_partner_cnt := x_partner_tbl.count;
1524 
1525    -- ---------------------------------------------------------------------------
1526    -- Get message count if the stack trace flag is turned on.
1527    -- ---------------------------------------------------------------------------
1528    IF (g_rule_engine_trace_flag = 'Y') THEN
1529       FND_MSG_PUB.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1530                                  p_count     =>  x_msg_count,
1531                                  p_data      =>  x_msg_data);
1532    END IF;
1533 
1534 
1535    -------------------- Exception --------------------------
1536    EXCEPTION
1537       WHEN FND_API.G_EXC_ERROR THEN
1538          IF (g_failure_code IS NULL) THEN
1539             g_failure_code := 'OTHER';
1540          END IF;
1541 
1542          x_return_status := FND_API.G_RET_STS_ERROR;
1543          FND_MSG_PUB.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1544                                     p_count     =>  x_msg_count,
1545                                     p_data      =>  x_msg_data);
1546 
1547          -- Cause the calling program to raise the same exception!
1548          --RAISE;
1549 
1550       WHEN FND_API.g_exc_unexpected_error THEN
1551          IF (g_failure_code IS NULL) THEN
1552             g_failure_code := 'OTHER';
1553          END IF;
1554 
1555          x_return_status := FND_API.g_ret_sts_unexp_error;
1556          FND_MSG_PUB.count_and_get(
1557                p_encoded => FND_API.g_false,
1558                p_count   => x_msg_count,
1559                p_data    => x_msg_data
1560          );
1561 
1562       WHEN OTHERS THEN
1563          IF (g_failure_code IS NULL) THEN
1564             g_failure_code := 'OTHER';
1565          END IF;
1566 
1567         IF FND_MSG_PUB.check_msg_level(FND_MSG_PUB.g_msg_lvl_unexp_error) THEN
1568            FND_MSG_PUB.add_exc_msg(g_pkg_name, l_api_name);
1569         END IF;
1570 
1571         x_return_status := FND_API.G_RET_STS_ERROR;
1572         FND_MSG_PUB.count_and_get(
1573               p_encoded => FND_API.g_false,
1574               p_count   => x_msg_count,
1575               p_data    => x_msg_data
1576         );
1577 
1578 END Partner_Selection;
1579 -- ===========================End of Partner_Selection=========================
1580 
1581 
1582 -- ===========================Begin of Manual_match============================
1583 Procedure Manual_match(
1584     p_api_version_number    IN     NUMBER,
1585     p_init_msg_list         IN     VARCHAR2 := FND_API.G_FALSE,
1586     p_commit                IN     VARCHAR2 := FND_API.G_FALSE,
1587     p_validation_level      IN     NUMBER   := FND_API.G_VALID_LEVEL_FULL,
1588     p_attr_id_tbl           IN OUT NOCOPY   JTF_NUMBER_TABLE,
1589     p_attr_value_tbl        IN OUT NOCOPY   JTF_VARCHAR2_TABLE_4000,
1590     p_attr_operator_tbl     IN OUT NOCOPY   JTF_VARCHAR2_TABLE_100,
1591     p_attr_data_type_tbl    IN OUT NOCOPY   JTF_VARCHAR2_TABLE_100,
1592     p_attr_selection_mode   IN     VARCHAR2,
1593     p_att_delmter           IN     VARCHAR2,
1594     p_selection_criteria    IN     VARCHAR2,
1595     p_resource_id           IN     NUMBER,
1596     p_lead_id               IN     NUMBER,
1597     p_auto_match_flag       IN     VARCHAR2,
1598     p_get_distance_flag     IN     VARCHAR2 := 'F',
1599     x_return_status         OUT    NOCOPY VARCHAR2,
1600     x_msg_count             OUT    NOCOPY NUMBER,
1601     x_msg_data              OUT    NOCOPY VARCHAR2,
1602     p_top_n_rows_by_profile IN     VARCHAR2 := 'T'
1603 ) IS
1604 
1605     l_api_name        CONSTANT VARCHAR2(30) := 'Manual_Match';
1606     l_api_version_number  CONSTANT NUMBER       := 1.0;
1607 
1608     CURSOR lc_get_incumbent_pt (pc_lead_id NUMBER) IS
1609       SELECT asla.INCUMBENT_PARTNER_PARTY_ID
1610       FROM as_leads_all asla
1611       WHERE asla.lead_id = pc_lead_id;
1612 
1613     l_matched_id                JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
1614     l_new_matched_id            JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
1615 
1616     l_incumbent_pt_party_id     NUMBER;
1617     l_matched_tbl_last_idx      NUMBER := 0;
1618     l_incumbent_idx             NUMBER := 0;
1619 
1620     l_distance_uom              VARCHAR2(100);
1621     l_customer_address          pv_locator.party_address_rec_type;
1622 
1623     x_matched_id                JTF_NUMBER_TABLE;
1624     x_partner_details           JTF_VARCHAR2_TABLE_4000;
1625     x_distance_tbl              JTF_NUMBER_TABLE;
1626     x_distance_uom_returned     VARCHAR2(30);
1627     x_flagcount                 JTF_VARCHAR2_TABLE_100;
1628 
1629     l_no_of_prefered_pts        NUMBER := 0;
1630     l_prefered_pt_id_tbl        JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
1631     l_prefered_partner_distance NUMBER;
1632     l_prefered_dist_tbl         JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
1633     l_prefered_dist_uom         VARCHAR2(200);
1634 
1635     l_partner_dist_tbl          JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
1636     l_tokenize_attr_tbl         JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
1637 
1638     l_locator_flag              VARCHAR2(1) := 'Y';
1639 BEGIN
1640 
1641     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1642         debug('In '||l_api_name);
1643     END IF;
1644 
1645     IF NOT FND_API.Compatible_API_Call (l_api_version_number,
1646                        p_api_version_number,
1647                        l_api_name,
1648                        G_PKG_NAME) THEN
1649         RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1650 
1651     END IF;
1652 
1653     x_matched_id      := JTF_NUMBER_TABLE();
1654     x_partner_details := JTF_VARCHAR2_TABLE_4000();
1655     x_distance_tbl    := JTF_NUMBER_TABLE();
1656     x_flagcount       := JTF_VARCHAR2_TABLE_100();
1657 
1658    -- Initialize message list if p_init_msg_list is set to TRUE.
1659    IF FND_API.to_Boolean( p_init_msg_list ) THEN
1660       fnd_msg_pub.initialize;
1661    END IF;
1662 
1663    x_return_status := FND_API.G_RET_STS_SUCCESS ;
1664 
1665     -- ================================================================================
1666     -- Get matched Partner ID's for the specified attributes
1667     -- ================================================================================
1668 
1669     PV_MATCH_V2_PUB.Form_Where_clause(
1670          p_api_version_number    => l_api_version_number
1671         ,p_init_msg_list         => p_init_msg_list
1672         ,p_commit                => p_commit
1673         ,p_validation_level      => FND_API.G_VALID_LEVEL_FULL
1674         ,p_attr_id_tbl           => p_attr_id_tbl
1675         ,p_attr_value_tbl        => p_attr_value_tbl
1676         ,p_attr_operator_tbl     => p_attr_operator_tbl
1677         ,p_attr_data_type_tbl    => p_attr_data_type_tbl
1678         ,p_attr_selection_mode   => p_attr_selection_mode
1679         ,p_att_delmter           => p_att_delmter
1680         ,p_selection_criteria    => p_selection_criteria
1681         ,p_resource_id           => p_resource_id
1682         ,p_lead_id               => p_lead_id
1683         ,p_auto_match_flag       => p_auto_match_flag
1684         ,p_top_n_rows_by_profile => p_top_n_rows_by_profile
1685         ,x_matched_id            => x_matched_id
1686         ,x_return_status         => x_return_status
1687         ,x_msg_count             => x_msg_count
1688         ,x_msg_data              => x_msg_data
1689      );
1690 
1691     -- l_matched_id and x_matched_id are 2 tables which maintain matched partners.
1692     -- They are identical tables to begin with. Refer to the below statement.
1693     --
1694     -- One of them (l_matched_id) is sent as an IN parameter to elocation  and the
1695     -- x_matched_id returns from elocation with distance information. The x_matched_id
1696     -- x_matched_id table could be in a different order than l_matched_id when it returns.
1697     -- So l_matched_id table contains partner list as we got it from FORM_WHERE_CALUSE
1698     -- and x_matched_id contains partner list as we had it from Elocation.
1699     l_matched_id := x_matched_id;
1700 
1701     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1702          Debug('Partner from FORM_WHERE_CLAUSE '||x_matched_id.COUNT);
1703     END IF;
1704 
1705    /******************Begin of preferred partner Code comments ****************
1706    -- Rivendell UI does not have Preferred partner as a part of the Matching LOV
1707    -- The preferred partner is directly added to the matching table instead of
1708    -- being added from the matching LOV.
1709    -- So the whole section of the code involving preferred partner will be commented
1710    -- out.
1711    -- ================================================================================
1712    -- Get Preferred Partner Details
1713    -- ================================================================================
1714     OPEN lc_get_incumbent_pt (p_lead_id);
1715       FETCH lc_get_incumbent_pt INTO l_incumbent_pt_party_id;
1716     CLOSE lc_get_incumbent_pt;
1717 
1718     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1719         debug('Preferred partner for lead :'||p_lead_id||' is '||l_incumbent_pt_party_id);
1720     END IF;
1721 
1722     -- Checking to see if the preferred partner already exists in the matched partner tbl
1723     IF (x_matched_id.EXISTS(1) AND l_incumbent_pt_party_id IS NOT NULL) THEN
1724         FOR x IN (
1725          SELECT idx
1726          FROM   (SELECT rownum idx, column_value party_id
1727                  FROM  (SELECT column_value
1728                         FROM TABLE (CAST(x_matched_id AS JTF_NUMBER_TABLE)))) a
1729                         WHERE  a.party_id = l_incumbent_pt_party_id)
1730          LOOP
1731             l_incumbent_idx := x.idx;
1732 
1733             IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1734                 debug('Preferred partner already exists at matched partner list, position is '||l_incumbent_idx);
1735             END IF;
1736          END LOOP;
1737     END IF;
1738 
1739     -- Adding preferred partner to matched partner id tbl if there is an
1740     -- incumbent partner and that partner was not already there in the table.
1741     IF l_incumbent_idx = 0 and l_incumbent_pt_party_id IS NOT NULL THEN
1742         x_matched_id.extend;
1743         x_matched_id(x_matched_id.count) := l_incumbent_pt_party_id;
1744     END IF;
1745    ******************End of preferred partner Code comments ****************/
1746 
1747     -- ------------------------------------------------------------------------
1748     -- Retrieve customer-to-partner distance info...
1749     --
1750     -- Execute Geo Proximity API only when there is at least one partner
1751     -- returned from Partner Matching above.
1752     -- ------------------------------------------------------------------------
1753     IF (p_get_distance_flag = 'T' AND
1754         l_matched_id.EXISTS(1) AND l_matched_id.COUNT > 0)
1755     THEN
1756         -- -------------------------------------------------------------
1757         -- Retrieve location_id for this opportunity.
1758         -- -------------------------------------------------------------
1759         IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1760              Debug('before retrieving locator info');
1761         END IF;
1762 
1763         BEGIN
1764         SELECT b.location_id
1765         INTO   l_customer_address.location_id
1766         FROM   as_leads_all   a,
1767             hz_party_sites b,
1768             hz_locations   l
1769         WHERE  a.lead_id   = p_lead_id AND
1770             a.customer_id   = b.party_id AND
1771             b.party_site_id = a.address_id AND
1772             b.location_id   = l.location_id AND
1773             l.geometry IS NOT NULL;
1774 
1775         EXCEPTION
1776         WHEN NO_DATA_FOUND THEN
1777               l_locator_flag := 'N';
1778         END;
1779 
1780         Debug('Locator Flag :::' || l_locator_flag);
1781 
1782         IF l_locator_flag = 'Y' THEN
1783             IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1784                 Debug('Location ID: ' || l_customer_address.location_id);
1785                 Debug('..........................................................');
1786                 Debug('Calling pv_locator.Get_Partners..........................');
1787                 Debug('# of Partners Sent: ' || l_matched_id.COUNT);
1788 
1789                 FOR i IN 1 .. x_matched_id.COUNT
1790                 LOOP
1791                     Debug('Partner Id ' || l_matched_id(i));
1792                 END LOOP;
1793             END IF;
1794 
1795             -- -------------------------------------------------------------
1796             -- Execute geo proximity API.
1797             -- -------------------------------------------------------------
1798             -- Default to mile
1799             l_distance_uom := pv_locator.g_distance_unit_mile;
1800             pv_locator.Get_Partners (
1801                   p_api_version      => 1.0,
1802                   p_init_msg_list    => FND_API.g_false,
1803                   p_commit           => FND_API.g_false,
1804                   p_validation_level => FND_API.g_valid_level_full,
1805                   p_customer_address => l_customer_address,
1806                   p_partner_tbl      => l_matched_id,
1807                   p_max_no_partners  => null,
1808                   p_distance     => null,
1809                   p_distance_unit    => l_distance_uom,
1810                   p_sort_by_distance => 'T',
1811                   x_partner_tbl      => x_matched_id,
1812                   x_distance_tbl     => x_distance_tbl,
1813                   x_distance_unit    => x_distance_uom_returned,
1814                   x_return_status    => x_return_status,
1815                   x_msg_count        => x_msg_count,
1816                   x_msg_data     => x_msg_data
1817             );
1818 
1819             IF (x_return_status = FND_API.G_RET_STS_ERROR) THEN
1820               RAISE FND_API.G_EXC_ERROR;
1821             ELSIF (x_return_status = FND_API.g_ret_sts_unexp_error) THEN
1822               RAISE FND_API.g_exc_unexpected_error;
1823             END IF;
1824 
1825             IF (x_distance_uom_returned = pv_locator.g_distance_unit_km) THEN
1826               x_distance_uom_returned := 'KILOMETERS';
1827 
1828             ELSIF (x_distance_uom_returned = pv_locator.g_distance_unit_mile) THEN
1829               x_distance_uom_returned := 'MILES';
1830             END IF;
1831 
1832             IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1833                Debug('Distance UOM returned is: ' || x_distance_uom_returned);
1834                Debug('# of Partners Returned: ' || x_matched_id.COUNT);
1835             END IF;
1836 
1837      /****************Begin of preferred partner Code comments ****************
1838             -- ----------------------------------------------------------------
1839             -- Adding preferred partner on top
1840             -- ----------------------------------------------------------------
1841             IF  l_incumbent_pt_party_id IS NOT NULL THEN
1842 
1843                 FOR x IN (
1844                 SELECT idx
1845                 FROM   (SELECT rownum idx, column_value party_id
1846                      FROM  (SELECT column_value
1847                         FROM TABLE (CAST(x_matched_id AS JTF_NUMBER_TABLE)))) a
1848                 WHERE  a.party_id = l_incumbent_pt_party_id)
1849                 LOOP
1850                     l_incumbent_idx := x.idx;
1851                 END LOOP;
1852 
1853                 IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1854                    debug('location of Preferred partner in matched partner list '
1855                          ||l_incumbent_idx);
1856                 END IF;
1857 
1858                 l_prefered_partner_distance := x_distance_tbl(l_incumbent_idx);
1859 
1860                 IF (x_matched_id.COUNT > 1) THEN
1861                     FOR i IN REVERSE 1..(l_incumbent_idx - 1) LOOP
1862                         x_matched_id(i + 1) := x_matched_id(i);
1863                         x_distance_tbl(i+1) := x_distance_tbl(i);
1864                     END LOOP;
1865                     x_matched_id(1)   := l_incumbent_pt_party_id;
1866                     x_distance_tbl(1) := l_prefered_partner_distance;
1867                 END IF;
1868             END IF;
1869      ************************End of preferred partner Code comments **********/
1870 
1871             -- ------------------------------------------------------------------------
1872             -- Getting the partner details
1873             -- ------------------------------------------------------------------------
1874             FOR i IN 1 .. x_matched_id.COUNT LOOP
1875                 IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1876                     debug('Partner ID after prefered partner on top '||x_matched_id(i));
1877                     debug('Distance after prefered partner on top '||x_distance_tbl(i));
1878                 END IF;
1879             END LOOP;
1880 
1881         END IF; -- Locator flag is 'Y'
1882 
1883     END IF;
1884 
1885     IF x_matched_id.count > 0 THEN
1886 
1887         g_from_match_lov_flag := TRUE;
1888 
1889         Get_Matched_Partner_Details(
1890             p_api_version_number     => 1.0
1891             ,p_init_msg_list          => FND_API.G_FALSE
1892             ,p_commit                 => FND_API.G_FALSE
1893             ,p_validation_level       => FND_API.G_VALID_LEVEL_FULL
1894             ,p_lead_id                => p_lead_id
1895             ,p_matched_id             => x_matched_id
1896             ,p_distance_tbl           => x_distance_tbl
1897             ,x_return_status          => x_return_status
1898             ,x_msg_count              => x_msg_count
1899             ,x_msg_data               => x_msg_data
1900         );
1901 
1902         IF (x_return_status = fnd_api.g_ret_sts_error) THEN
1903             RAISE fnd_api.g_exc_error;
1904         ELSIF (x_return_status = fnd_api.g_ret_sts_unexp_error) THEN
1905             RAISE fnd_api.g_exc_unexpected_error;
1906         END IF;
1907 
1908         IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
1909             Debug('# of Partners Returned from matched_partner_details: ' || x_matched_id.COUNT);
1910         END IF;
1911 
1912    END IF;
1913 
1914    IF FND_API.To_Boolean ( p_commit )  THEN
1915       COMMIT WORK;
1916    END IF;
1917 
1918    -- Standard call to get message count and if count is 1, get message info.
1919    fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1920         p_count =>  x_msg_count,
1921         p_data  =>  x_msg_data);
1922 
1923 EXCEPTION
1924 
1925    WHEN FND_API.G_EXC_ERROR THEN
1926 
1927       x_return_status := FND_API.G_RET_STS_ERROR ;
1928 
1929       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1930                  p_count     =>  x_msg_count,
1931                  p_data      =>  x_msg_data);
1932 
1933    WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1934 
1935       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
1936 
1937       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1938                  p_count     =>  x_msg_count,
1939                  p_data      =>  x_msg_data);
1940 
1941 
1942    WHEN OTHERS THEN
1943 
1944       FND_MSG_PUB.Add_Exc_Msg(G_PKG_NAME, l_api_name);
1945 
1946       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1947 
1948 
1949       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
1950                  p_count     =>  x_msg_count,
1951                  p_data      =>  x_msg_data);
1952 
1953 END Manual_Match;
1954 -- ===========================Begin of Manual_match============================
1955 
1956 --=============================================================================+
1957 --|  Procedure                                                                 |
1958 --|                                                                            |
1959 --|    Get_Matched_Partner_Details                                             |
1960 --|    This procedure Gets the Matched Partner Details required in the UI      |
1961 --|                                                                            |
1962 --|                                                                            |
1963 --|                                                                            |
1964 --|  Parameters                                                                |
1965 --|  IN                                                                        |
1966 --|  OUT                                                                       |
1967 --|                                                                            |
1968 --|                                                                            |
1969 --| NOTES                                                                      |
1970 --|                                                                            |
1971 --| HISTORY                                                                    |
1972 --|                                                                            |
1973 --==============================================================================
1974 
1975 
1976  /*
1977      Following Assumptions are made for the following select statements.
1978      1. Flag values should each be a different power of 2 to ensure that
1979         each bit is used by only one flag.
1980         Also, these flag values should match with the flag constants defined
1981         in java API to resolve flags on the front end side.
1982 
1983         REJECTED CURRENT OPPORTUNITY  = 1
1984         PREFERRED OR INCUMBENT PARTNER FOR CURRENT OPPORTUNITY  = 2
1985 
1986      2. Most of the select statements assume that PT_APPROVED row for accepted
1987         partner exists in pv_lead_assignments until oppty is recycled by the partner
1988 
1989      3. ISSUE : RECYCLED from_status does not have partner_id populated in
1990         pv_assignment_logs. So, rejected partner query may not give the correct result
1991 
1992         PROPOSAL :  We need to identify an assignment status when partner is
1993             rejecting an oppty
1994 
1995         after accepting it . Then, we can populate  partner_id in logs table
1996         to identify rejected partner
1997 
1998  */
1999 
2000  Procedure Get_Matched_Partner_Details(
2001      p_api_version_number    IN  NUMBER,
2002      p_init_msg_list         IN  VARCHAR2 := FND_API.G_FALSE,
2003      p_commit                IN  VARCHAR2 := FND_API.G_FALSE,
2004      p_validation_level      IN  NUMBER   := FND_API.G_VALID_LEVEL_FULL,
2005      p_lead_id               IN  NUMBER,
2006      p_matched_id            IN  OUT NOCOPY JTF_NUMBER_TABLE,
2007      p_distance_tbl          IN  JTF_NUMBER_TABLE,
2008      x_return_status         OUT NOCOPY VARCHAR2,
2009      x_msg_count             OUT NOCOPY NUMBER,
2010      x_msg_data              OUT NOCOPY VARCHAR2)
2011   IS
2012 
2013 
2014    l_api_name            CONSTANT VARCHAR2(30) := 'Get_Matched_Partner_Details';
2015    l_api_version_number  CONSTANT NUMBER       := 1.0;
2016 
2017 
2018    -- In this API we get details for the partner and insert into
2019    -- an oracle temp table. any commit/rollback action will empty this
2020    -- table since this table maintains data for only the current transaction.
2021    -- so we are setting the l_commit flag to false so that the commit routine
2022    -- is never executed.
2023    l_commit                 VARCHAR2(1) := FND_API.G_FALSE;
2024 
2025    REJECTED_OPPTY_FLAG      CONSTANT NUMBER := 1;
2026    INCUMBENT_PARTNER_FLAG   CONSTANT NUMBER := 2;
2027    TOKEN                    CONSTANT VARCHAR2(3) := '~';
2028    NULLTOKEN                CONSTANT VARCHAR2(3) := '===';
2029    l_party_name             VARCHAR2(360);
2030    l_city                   VARCHAR2(60);
2031    l_state                  VARCHAR2(60);
2032    l_country                VARCHAR2(60);
2033    l_postal_code            VARCHAR2(60);
2034    l_address1               VARCHAR2(1000);
2035    l_address2               VARCHAR2(240);
2036    l_address3               VARCHAR2(240);
2037    l_attr_desc              VARCHAR2(60);
2038    l_partner_id             NUMBER;
2039    l_oppty_last_offer_dt    VARCHAR2(20);
2040    l_party_id               NUMBER;
2041    l_partner_count          NUMBER  := 0;
2042    l_recycled_flag          VARCHAR2(4);
2043    l_incumbent_pt_party_id  NUMBER;
2044    l_incumbent_exists_flag  boolean;
2045    l_relationship_id        NUMBER;
2046    l_partner_name           VARCHAR2(3600);
2047    l_internal_org_name      VARCHAR2(3600);
2048    l_internal_flag          VARCHAR2(1);
2049    l_party_flag             VARCHAR2(1);
2050    l_partner_names          VARCHAR2(3600);
2051    l_count                  NUMBER;
2052    l_wf_status              VARCHAR2(1000);
2053    l_active_flag            VARCHAR2(1);
2054 
2055    l_party_name_tbl         JTF_VARCHAR2_TABLE_1000 := JTF_VARCHAR2_TABLE_1000();
2056    l_party_id_tbl           JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
2057    l_partner_id_tbl         JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
2058    l_address1_tbl           JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
2059    l_attr_desc_tbl          JTF_VARCHAR2_TABLE_4000 := JTF_VARCHAR2_TABLE_4000();
2060    l_oppty_last_offer_dt_tbl  JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2061    l_active_flag_tbl        JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2062    l_order_table            JTF_NUMBER_TABLE := JTF_NUMBER_TABLE();
2063 
2064    l_membertype_table       JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2065    l_industry_table         JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2066    l_geography_table        JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2067    l_capacityrating_table   JTF_VARCHAR2_TABLE_100 := JTF_VARCHAR2_TABLE_100();
2068 
2069    l_incumbent_party_name   VARCHAR2(3600);
2070    l_pt_id                  NUMBER;
2071    l_pt_count               NUMBER;
2072 
2073    l_dist_exists            BOOLEAN;
2074 
2075    x_partner_details        JTF_VARCHAR2_TABLE_4000;
2076    x_recycled_flag_tbl      JTF_VARCHAR2_TABLE_100;
2077    x_incumbent_flag_tbl     JTF_VARCHAR2_TABLE_100;
2078 
2079    TYPE partner_det_rec is REF CURSOR;
2080    lc_partner_detail_cur partner_det_rec;
2081 
2082    /*
2083    TYPE l_tmp IS TABLE OF VARCHAR2(4000) INDEX BY binary_integer;
2084    l_tmp_ids_tbl            l_tmp;
2085    l_tmp_pt_details_tbl     l_tmp;
2086    */
2087 
2088    CURSOR lc_get_incumbent_pt (pc_lead_id NUMBER) IS
2089       SELECT asla.INCUMBENT_PARTNER_PARTY_ID
2090       FROM as_leads_all asla
2091       WHERE asla.lead_id = pc_lead_id;
2092 
2093    CURSOR lc_get_recycled_flag(pc_lead_id NUMBER , pc_partner_id NUMBER)
2094    IS
2095    SELECT  DECODE(status
2096                    ,'PT_REJECTED','Y'
2097                    ,'PT_ABANDONED','Y'
2098                    ,'PT_TIMEOUT','Y'
2099                    ,'N')
2100    FROM    pv_lead_assignments pval
2101    WHERE   pval.lead_id = pc_lead_id
2102    AND     pval.status in ('PT_REJECTED', 'PT_ABANDONED', 'PT_TIMEOUT')
2103    AND     pval.partner_id = pc_partner_id;
2104 
2105   /*
2106    CURSOR lc_duplicate_pt_count
2107    IS
2108    SELECT  pvpp.partner_id,
2109            hzp.party_name,
2110            hzop_pt.internal_flag pt_int_flag,
2111            vend.party_name,
2112            hzop_vend.internal_flag vend_int_flag
2113    FROM    hz_parties hzp , pv_partner_profiles pvpp , hz_parties vend,
2114            hz_relationships hzr,
2115            hz_organization_profiles HZOP_pt,
2116            hz_organization_profiles hzop_vend
2117    WHERE   hzr.party_id = pvpp.partner_id
2118    AND     pvpp.partner_party_id = hzr.subject_id
2119    AND     hzr.subject_id = hzp.party_id
2120    AND     hzr.subject_table_name = 'HZ_PARTIES'
2121    AND     hzr.object_table_name = 'HZ_PARTIES'
2122    AND     hzr.status = 'A' and hzr.start_date <= sysdate and nvl(hzr.end_date,sysdate) >= sysdate
2123    AND     hzr.subject_id = HZOP_pt.party_id and nvl(hzop_pt.effective_end_date,sysdate) >= sysdate
2124    AND     hzr.object_id = HZOP_vend.party_id and nvl(hzop_vend.effective_end_date,sysdate) >= sysdate
2125    AND     (HZOP_vend.internal_flag   = 'N' or hzop_pt.internal_flag = 'Y')
2126    AND     pvpp.partner_id in (
2127         SELECT * FROM TABLE (CAST(p_matched_id AS JTF_NUMBER_TABLE))
2128         )
2129    AND     hzr.object_id = vend.party_id
2130    AND     hzr.relationship_code in ('PARTNER_OF','VAD_OF');
2131   */
2132    -- =================================================================================
2133    -- When the Partner Status is Inactive OR Relationship status is inactive
2134    -- OR if the relationship is end dated OR if the Vendor ORG is end dated
2135    -- then the active_flag's value would be 'Inactive'
2136    -- Uncomment this when the local databases are upgraded to 9i
2137    -- =================================================================================
2138 /*
2139    -- 11.5.9
2140    CURSOR l_partner_detail_cur
2141    IS
2142       select  hzp.party_name, hzp.city,  hzp.state ,
2143           hzp.postal_code, hzp.country, hzp.address1,
2144           hzp.address2, hzp.address3, hzp.party_id,
2145           pvpp.partner_id,
2146           to_char(pvpp.OPPTY_LAST_OFFERED_DATE, 'YYYY-MM-DD HH:MM:SS'),
2147           pvac.description, hzr.relationship_id,
2148           (case when hzp.status = 'A'
2149            and  hzr.status = 'A'
2150            and nvl(hzop.effective_start_date, sysdate) <= sysdate
2151            and nvl(hzop.effective_end_date, sysdate) >= sysdate
2152            and hzr.start_date <= SYSDATE and NVL(hzr.end_date,SYSDATE) >= SYSDATE
2153            then 'A'
2154            else 'I'
2155            end ) active_flag
2156       from    hz_parties hzp , pv_partner_profiles pvpp ,
2157           pv_attribute_codes_vl  pvac, hz_relationships hzr ,
2158           hz_organization_profiles HZOP,
2159          (SELECT rownum idx, column_value
2160           FROM   (SELECT column_value FROM TABLE (CAST(p_matched_id AS JTF_NUMBER_TABLE)))) x_partner
2161       where   pvpp_partner_id in (SELECT * FROM THE(select CAST(p_matched_id AS JTF_NUMBER_TABLE) from dual))
2162       and     pvpp.partner_id = x_partner.column_value
2163       and     hzr.party_id = pvpp.partner_id
2164       and     hzr.subject_id = hzp.party_id
2165       and     hzr.object_id = HZOP.party_id
2166       and     HZOP.internal_flag   = 'Y'
2167       and     hzr.subject_table_name = 'HZ_PARTIES'
2168       and     hzr.object_table_name = 'HZ_PARTIES'
2169       and     pvpp.PARTNER_LEVEL = pvac.attr_code_id(+)
2170       order   by x_partner.idx;
2171 
2172    -- 11.5.10 -- pklin
2173    CURSOR l_partner_detail_cur
2174    IS
2175       select  hzp.party_name, hzp.city,  hzp.state ,
2176           hzp.postal_code, hzp.country, hzp.address1,
2177           hzp.address2, hzp.address3, hzp.party_id,
2178           pvpp.partner_id,
2179           to_char(pvpp.OPPTY_LAST_OFFERED_DATE, 'YYYY-MM-DD HH:MM:SS'),
2180           pvac.description,
2181               pvpp.status active_flag
2182       from    hz_parties hzp,
2183               pv_partner_profiles pvpp,
2184           pv_attribute_codes_vl pvac,
2185          (SELECT rownum idx, column_value
2186           FROM   (SELECT column_value FROM TABLE (CAST(p_matched_id AS JTF_NUMBER_TABLE)))) x_partner
2187       where   pvpp.partner_id = x_partner.column_value
2188       and     pvpp.partner_party_id = hzp.party_id
2189       and     pvpp.PARTNER_LEVEL = pvac.attr_code_id(+)
2190       order   by x_partner.idx;
2191 */
2192 
2193 
2194 
2195 /*   CURSOR lc_get_pt_org_name(lc_partner_id NUMBER)
2196    IS
2197    select distinct party_name
2198    from   hz_relationships hzr,
2199       hz_parties hzp,
2200       hz_organization_profiles HZOP
2201    where  hzr.subject_id = hzp.party_id
2202    and    hzr.object_id = HZOP.party_id
2203    and    HZOP.internal_flag   = 'Y'
2204    and    hzr.subject_table_name = 'HZ_PARTIES'
2205    and    hzr.object_table_name = 'HZ_PARTIES'
2206    and    hzr.party_id = lc_partner_id; */
2207 
2208 -- =================================================================================
2209 
2210 BEGIN
2211 
2212     IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2213       fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2214       fnd_message.Set_Token('TEXT', 'In ' || l_api_name);
2215       fnd_msg_pub.Add;
2216     END IF;
2217 
2218     -- Standard call to check for call compatibility.
2219 
2220     IF NOT FND_API.Compatible_API_Call (l_api_version_number,
2221                        p_api_version_number,
2222                        l_api_name,
2223                        G_PKG_NAME) THEN
2224       RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
2225 
2226     END IF;
2227 
2228     -- Initialize message list if p_init_msg_list is set to TRUE.
2229     IF FND_API.to_Boolean( p_init_msg_list )
2230     THEN
2231       fnd_msg_pub.initialize;
2232     END IF;
2233 
2234     x_incumbent_flag_tbl :=  JTF_VARCHAR2_TABLE_100();
2235     x_recycled_flag_tbl :=  JTF_VARCHAR2_TABLE_100();
2236     x_return_status   :=  FND_API.G_RET_STS_SUCCESS ;
2237 
2238     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2239        debug('Partner Id count before getting details '||p_matched_id.count);
2240     END IF;
2241 
2242     l_partner_id_tbl.EXTEND(p_matched_id.count);
2243     l_order_table.EXTEND(p_matched_id.count);
2244     x_incumbent_flag_tbl.EXTEND(p_matched_id.count);
2245     x_recycled_flag_tbl.EXTEND(p_matched_id.count);
2246     l_industry_table.EXTEND(p_matched_id.count);
2247     l_membertype_table.EXTEND(p_matched_id.count);
2248     l_geography_table.EXTEND(p_matched_id.count);
2249     l_capacityrating_table.EXTEND(p_matched_id.count);
2250 
2251     FOR i IN 1..p_matched_id.COUNT LOOP
2252         l_partner_id_tbl(i) := p_matched_id(i);
2253     END LOOP;
2254 
2255     FOR i IN 1..l_partner_id_tbl.COUNT LOOP
2256         debug('i '||i);
2257         debug('l_partner_id length '||l_partner_id_tbl(i));
2258     END LOOP;
2259 
2260 
2261     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2262        debug('l_partner_id length '||l_partner_id_tbl.count);
2263     END IF;
2264 
2265     OPEN lc_get_incumbent_pt (p_lead_id);
2266     FETCH lc_get_incumbent_pt INTO l_incumbent_pt_party_id;
2267         IF l_incumbent_pt_party_id IS NULL THEN
2268             IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2269                 fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2270                 fnd_message.Set_Token('TEXT', 'Incumbent Partner party ID is null. So, setting it to be zero');
2271                 fnd_msg_pub.Add;
2272             END IF;
2273             l_incumbent_pt_party_id := 0;
2274         END IF;
2275     CLOSE lc_get_incumbent_pt;
2276 
2277     IF l_partner_id_tbl.count > 0 THEN
2278 
2279         FOR j IN 1 .. l_partner_id_tbl.COUNT LOOP
2280 
2281             l_order_table(j)  := j;
2282 
2283             IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2284                debug('Value of index '||j);
2285             END IF;
2286 
2287             IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2288               fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2289               fnd_message.Set_Token('TEXT', 'Checking if preferred Partner: ' || l_incumbent_pt_party_id );
2290               fnd_msg_pub.Add;
2291             END IF;
2292 
2293             IF l_partner_id_tbl(j) = l_incumbent_pt_party_id THEN
2294                 x_incumbent_flag_tbl(j) := 'Y';
2295             ELSE
2296                 x_incumbent_flag_tbl(j) := 'N';
2297             END IF;
2298 
2299 
2300 
2301             -- This section gets the values for
2302             -- Membertype
2303             -- PartnerSince
2304             -- Phone
2305             -- Industry
2306             -- Geographic coverage
2307             -- capacity Rating
2308             -- Size of Company
2309             -- All these attributes have the same SQL_TEXT for the Partner entity
2310             -- So we are using it to query diff attr values and popluating it into
2311             -- the temp table.
2312             IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2313               fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2314               fnd_message.Set_Token('TEXT', 'Getting Personalized columns for : ' || l_partner_id_tbl(j));
2315               fnd_msg_pub.Add;
2316             END IF;
2317 
2318             l_industry_table(j)       := get_attribute_value(5, l_partner_id_tbl(j));
2319             l_membertype_table(j)     := get_attribute_value(6, l_partner_id_tbl(j));
2320             l_geography_table(j)      := get_attribute_value(8, l_partner_id_tbl(j));
2321             l_capacityrating_table(j) := get_attribute_value(18, l_partner_id_tbl(j));
2322 
2323             IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2324               fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2325               fnd_message.Set_Token('TEXT', 'Values for Attrs :5 ' ||l_industry_table(j)||
2326                                     'Values for Attrs :6 ' ||l_membertype_table(j)||
2327                                     'Values for Attrs :8 ' || l_geography_table(j)||
2328                                     'Values for Attrs :18 ' || l_capacityrating_table(j) );
2329               fnd_msg_pub.Add;
2330             END IF;
2331 
2332 
2333             IF fnd_msg_pub.Check_Msg_Level (fnd_msg_pub.G_MSG_LVL_DEBUG_LOW) THEN
2334               fnd_message.Set_Name('PV', 'PV_DEBUG_MESSAGE');
2335               fnd_message.Set_Token('TEXT', 'Looking for recycled flag for Partner Id : ' || l_partner_id_tbl(j));
2336               fnd_msg_pub.Add;
2337             END IF;
2338 
2339             -- Check if this lead has been recycled by this partner before.
2340             -- If it has then set the recycled column to 'Y'.
2341             OPEN lc_get_recycled_flag(p_lead_id, l_partner_id_tbl(j));
2342             FETCH lc_get_recycled_flag INTO l_recycled_flag;
2343 
2344                 x_recycled_flag_tbl.extend;
2345                 IF  lc_get_recycled_flag%FOUND AND  l_recycled_flag IS NOT NULL THEN
2346                     IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2347                         Debug( 'Recycled flag : ' ||  l_recycled_flag);
2348                     END IF;
2349                     x_recycled_flag_tbl(j) :=  l_recycled_flag;
2350                 ELSE
2351                     x_recycled_flag_tbl(j) := 'N';
2352                 END IF;
2353 
2354                 l_recycled_flag := 'N';
2355 
2356             CLOSE lc_get_recycled_flag;
2357         END LOOP;
2358     END IF;
2359 
2360     BEGIN
2361         IF p_distance_tbl.COUNT > 0 THEN
2362             FORALL i IN 1..p_matched_id.COUNT
2363                 INSERT INTO pv_matched_partners_gt
2364                 VALUES (
2365                 l_partner_id_tbl(i)
2366                 ,p_distance_tbl(i)
2367                 ,x_recycled_flag_tbl(i)
2368                 ,x_incumbent_flag_tbl(i)
2369                 ,l_order_table(i)
2370                 ,l_industry_table(i)
2371                 ,l_membertype_table(i)
2372                 ,l_geography_table(i)
2373                 ,l_capacityrating_table(i)
2374                 );
2375         ELSE
2376             FORALL i IN 1..p_matched_id.COUNT
2377                 INSERT INTO pv_matched_partners_gt
2378                 (
2379                 PARTNER_ID
2380                 ,RECYCLED_FLAG
2381                 ,INCUMBENT_FLAG
2382                 ,PARTNER_ORDER
2383                 ,INDUSTRY
2384                 ,MEMBER_TYPE
2385                 ,GEOGRAPHY
2386                 ,CAPACITY_RATING
2387                 )
2388                 VALUES (
2389                 l_partner_id_tbl(i)
2390                 ,x_recycled_flag_tbl(i)
2391                 ,x_incumbent_flag_tbl(i)
2392                 ,l_order_table(i)
2393                 ,l_industry_table(i)
2394                 ,l_membertype_table(i)
2395                 ,l_geography_table(i)
2396                 ,l_capacityrating_table(i)
2397                 );
2398         END IF;
2399         EXCEPTION
2400             WHEN others THEN
2401                 Debug('Bad row index = ' || (1 +sql%rowcount) ||' ' || sqlerrm);
2402     END;
2403 
2404     IF FND_API.To_Boolean ( l_commit ) THEN
2405         COMMIT WORK;
2406     END IF;
2407 
2408     -- Standard call to get message count and if count is 1, get message info.
2409     fnd_msg_pub.Count_And_Get( p_encoded     =>  FND_API.G_FALSE,
2410             p_count =>  x_msg_count,
2411             p_data  =>  x_msg_data);
2412 
2413 EXCEPTION
2414 
2415    WHEN FND_API.G_EXC_ERROR THEN
2416 
2417       x_return_status := FND_API.G_RET_STS_ERROR ;
2418       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
2419                  p_count     =>  x_msg_count,
2420                  p_data      =>  x_msg_data);
2421 
2422    WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
2423 
2424       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
2425 
2426       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
2427                  p_count     =>  x_msg_count,
2428                  p_data      =>  x_msg_data);
2429 
2430    WHEN OTHERS THEN
2431 
2432 
2433       x_return_status :=    FND_API.G_RET_STS_UNEXP_ERROR;
2434 
2435       FND_MSG_PUB.Add_Exc_Msg(G_PKG_NAME, l_api_name);
2436 
2437       fnd_msg_pub.Count_And_Get( p_encoded   =>  FND_API.G_FALSE,
2438                  p_count     =>  x_msg_count,
2439                  p_data      =>  x_msg_data);
2440 
2441 End get_matched_partner_details;
2442 --====================End of get_matched_partner_details ======================
2443 
2444 --=============================================================================+
2445 --|  Public Procedure                                                          |
2446 --|                                                                            |
2447 --|    Tie_Breaker                                                             |
2448 --|                                                                            |
2449 --|  Parameters                                                                |
2450 --|  IN                                                                        |
2451 --|  OUT                                                                       |
2452 --|                                                                            |
2453 --|                                                                            |
2454 --| NOTES:                                                                     |
2455 --|                                                                            |
2456 --| HISTORY                                                                    |
2457 --|                                                                            |
2458 --==============================================================================
2459    PROCEDURE Tie_Breaker(
2460       p_api_version            IN  NUMBER,
2461       p_init_msg_list          IN  VARCHAR2  := FND_API.g_false,
2462       p_commit                 IN  VARCHAR2  := FND_API.g_false,
2463       p_validation_level       IN  NUMBER    := FND_API.g_valid_level_full,
2464       p_process_rule_id        IN  NUMBER,
2465       x_partner_tbl            IN OUT NOCOPY JTF_NUMBER_TABLE,
2466       x_return_status          OUT NOCOPY VARCHAR2,
2467       x_msg_count              OUT NOCOPY NUMBER,
2468       x_msg_data               OUT NOCOPY VARCHAR2)
2469    IS
2470 
2471       l_api_version      NUMBER := 1.0;
2472       l_api_name         VARCHAR2(30) := 'Tie_Breaker';
2473       l_tie_breaking_tab PV_TIE_BREAKING_TBL := PV_TIE_BREAKING_TBL();
2474       l_sql_string       VARCHAR2(10000);
2475       l_index            NUMBER;
2476       l_last_index       NUMBER;
2477       l_comma            VARCHAR2(1) := ',';
2478       i                  NUMBER;
2479       l_max_left_length  NUMBER; -- Length to the left of the decimal point
2480       l_max_right_length NUMBER; -- Length to the right of the decimal point
2481       l_left_length      NUMBER;
2482       l_right_length     NUMBER;
2483       l_attribute_id     NUMBER;
2484       l_format_string    VARCHAR2(300);
2485       l_positive_format_string    VARCHAR2(300);
2486       --l_any_negative     BOOLEAN := FALSE;
2487       l_prev_party_id    NUMBER;
2488       l_party_id    NUMBER;
2489       l_attribute_value varchar2(2000);
2490 
2491       l_start            NUMBER;
2492       l_dup_count        NUMBER;
2493       l_stop_flag        BOOLEAN := FALSE;
2494 
2495       -- --------------------------------------------------------------------
2496       -- Fetch all the tie-breaking attributes for a matching rule.
2497       -- --------------------------------------------------------------------
2498       CURSOR c_tie_breaking_attr IS
2499          SELECT a.attribute_id, a.operator, b.return_type
2500          FROM   pv_enty_select_criteria a,
2501                 pv_attributes_vl b
2502          WHERE  a.process_rule_id            = p_process_rule_id AND
2503                 UPPER(a.selection_type_code) = 'TIE_BREAKING' AND
2504                 a.attribute_id               = b.attribute_id
2505          ORDER  BY a.rank;
2506 
2507       lc_cursor          c_tie_breaking_attr%ROWTYPE;
2508 
2509       -- --------------------------------------------------------------------
2510       -- For a specified attribute, fetch all the attribute values for all
2511       -- the partners in the list (x_partner_tbl).
2512       --
2513       -- The outer join to hz_parties is to trick the query so that NULL values
2514       -- are returned for partners that don't have a corresponding record in
2515       -- pv_search_attr_values.
2516       -- ---------------------------------------------------------------------
2517 /*
2518       CURSOR lc_attr_values IS
2519          SELECT b.party_id,
2520                 DECODE(a.attr_text, NULL, TO_CHAR(a.attr_value), a.attr_text) attribute_value
2521          FROM   pv_search_attr_values a,
2522                 hz_parties b
2523          WHERE  a.party_id     (+) = b.party_id AND
2524                 a.attribute_id (+) = l_attribute_id AND
2525                 b.party_id IN (
2526                   SELECT * FROM TABLE (CAST(x_partner_tbl AS JTF_NUMBER_TABLE))
2527                 )
2528          ORDER  BY b.party_id;
2529 */
2530 
2531       -- --------------------------------------------------------------------
2532       -- The use of "rownum idx" is to preserve the order of party_id's as
2533       -- they were passed in through x_partner_tbl.
2534       --
2535       -- The "leading" hint is to make sure that the optimizer will make
2536       -- c (CAST PLSQL table) as the driving table as it is most likely the
2537       -- smallest "table" in the join.  This, in most cases, speeds up the
2538       -- performance dramatically.
2539       -- ---------------------------------------------------------------------
2540      lc_attr_values_string  varchar2(1000) :=
2541       '		select  '  ||
2542       '		c.party_id, '||
2543       '		(select decode(a.attr_text, null, to_char(a.attr_value),  ' ||
2544       '		a.attr_text) from pv_search_attr_values a where a.party_id = c.party_id and ' ||
2545       '		a.attribute_id = :1) attribute_value, ' ||
2546       '		c.idx ' ||
2547       '		from ' ||
2548       '		(select * from (select rownum idx, ' ||
2549       '		column_value party_id from (select column_value from table (cast(:2 as ' ||
2550       '		jtf_number_table))))) c ' ||
2551       '		order by c.idx ' ;
2552 
2553 /*
2554      '          SELECT  ' ||
2555      '	        b.party_id, ' ||
2556      '           DECODE(a.attr_text, NULL, TO_CHAR(a.attr_value), a.attr_text) attribute_value, ' ||
2557      '           c.idx ' ||
2558      '    FROM   pv_search_attr_values a, ' ||
2559      '           hz_parties b, ' ||
2560      '          (SELECT * ' ||
2561      '           FROM   (SELECT rownum idx, column_value party_id ' ||
2562      '                   FROM  (SELECT column_value ' ||
2563      '                          FROM TABLE (CAST(:1 AS JTF_NUMBER_TABLE))))) c ' ||
2564      '    WHERE  a.party_id     (+) = b.party_id AND ' ||
2565      '           a.attribute_id (+) = :2 AND ' ||
2566      '           b.party_id     = c.party_id ' ||
2567      '    ORDER  BY c.idx ' ;
2568   */
2569 
2570      TYPE t_attr_values_cursor IS REF CURSOR;
2571      lc_attr_values t_attr_values_cursor;
2572      l_idx number;
2573 
2574   --    CURSOR lc_attr_values IS
2575 --         SELECT /*+ leading(c) */
2576 /*	        b.party_id,
2577                 DECODE(a.attr_text, NULL, TO_CHAR(a.attr_value), a.attr_text) attribute_value,
2578                 c.idx
2579          FROM   pv_search_attr_values a,
2580                 hz_parties b,
2581                (SELECT *
2582                 FROM   (SELECT rownum idx, column_value party_id
2583                         FROM  (SELECT column_value
2584                                FROM TABLE (CAST(x_partner_tbl AS JTF_NUMBER_TABLE))))) c
2585          WHERE  a.party_id     (+) = b.party_id AND
2586                 a.attribute_id (+) = l_attribute_id AND
2587                 b.party_id     = c.party_id
2588          ORDER  BY c.idx;
2589 */
2590 
2591 
2592    BEGIN
2593       -------------------- initialize -------------------------
2594       IF FND_API.to_boolean(p_init_msg_list) THEN
2595          FND_MSG_PUB.initialize;
2596       END IF;
2597 
2598       IF NOT FND_API.compatible_api_call(
2599             l_api_version,
2600             p_api_version,
2601             l_api_name,
2602             g_pkg_name
2603       ) THEN
2604          RAISE FND_API.g_exc_unexpected_error;
2605       END IF;
2606 
2607       x_return_status := FND_API.G_RET_STS_SUCCESS;
2608 
2609       -------------------------- Source code --------------------
2610 
2611       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2612          Debug('Inside Tie-Breaking................................');
2613       END IF;
2614 
2615       -- ----------------------------------------------------------
2616       -- Loop through tie-breaking attributes one at a time to
2617       -- break the tie.
2618       -- ----------------------------------------------------------
2619       OPEN  c_tie_breaking_attr;
2620       FETCH c_tie_breaking_attr INTO lc_cursor;
2621 
2622       WHILE (c_tie_breaking_attr%FOUND AND (NOT l_stop_flag)) LOOP
2623          i := 1;
2624          l_attribute_id := lc_cursor.attribute_id;
2625 
2626          l_max_left_length  := 0;
2627          l_max_right_length := 0;
2628          -- l_any_negative     := FALSE;
2629          l_prev_party_id    := NULL;
2630 
2631          --FOR lc_cursor_inner IN lc_attr_values LOOP
2632 
2633 	 OPEN lc_attr_values FOR lc_attr_values_string using l_attribute_id, x_partner_tbl  ;
2634          LOOP
2635 
2636 	 FETCH lc_attr_values INTO  l_party_id, l_attribute_value, l_idx;
2637 	 EXIT WHEN lc_attr_values%NOTFOUND;
2638 
2639             -- ----------------------------------------------------------------------------
2640             -- Raise an exception if there are more than 1 record with the same party_id.
2641             -- If this were the case, we won't be able to determine which attribute value
2642             -- to use for tie-breaking.
2643             -- ----------------------------------------------------------------------------
2644             IF (l_party_id = l_prev_party_id) THEN
2645                Set_Message(p_msg_level    => FND_MSG_PUB.G_MSG_LVL_ERROR,
2646                            p_msg_name     => 'PV_MULTIPLE_ATTR_VALUES',
2647                            p_token1       => 'TEXT',
2648                            p_token1_value => 'Party ID: ' || l_prev_party_id,
2649                            p_token2       => 'TEXT',
2650                            p_token2_value => 'Attribute ID: ' || l_attribute_id);
2651 
2652                g_failure_code := 'OTHER';
2653                RAISE FND_API.G_EXC_ERROR;
2654             END IF;
2655 
2656             l_prev_party_id := l_party_id;
2657 
2658             -- ----------------------------------------------------------------------------
2659             -- Note: indexing the table this way (using i, which is sequential) will not
2660             -- mess up the party_id order because the cursor is sorted by party_id.
2661             -- Consistent read will guarantee that the order won't be changed.
2662             -- However, may want to change this in the future!!!
2663             -- ----------------------------------------------------------------------------
2664             IF (NOT l_tie_breaking_tab.EXISTS(i)) THEN
2665                l_tie_breaking_tab.EXTEND;
2666                l_tie_breaking_tab(i) := system.PV_TIE_BREAKING_TYPE(
2667                                            l_party_id,
2668                                            l_attribute_value,
2669                                            null
2670                                            --,l_idx
2671                                            );
2672             ELSE
2673                l_tie_breaking_tab(i).attr_value := l_attribute_value;
2674             END IF;
2675 
2676            /* .....................................................................
2677             IF ((TO_NUMBER(l_tie_breaking_tab(i).attr_value) < 0) AND (NOT l_any_negative)) THEN
2678                l_any_negative := TRUE;
2679             END IF;
2680             * ..................................................................... */
2681 
2682             Get_Attr_Length(
2683                p_attr_value     => l_tie_breaking_tab(i).attr_value,
2684                p_left_length    => l_left_length,
2685                p_right_length   => l_right_length
2686             );
2687 
2688             --Debug('LEFT : ' || l_left_length);
2689             --Debug('RIGHT: ' || l_right_length);
2690 
2691             IF (l_left_length > l_max_left_length) THEN
2692                l_max_left_length := l_left_length;
2693             END IF;
2694 
2695             IF (l_right_length > l_max_right_length) THEN
2696                l_max_right_length := l_right_length;
2697             END IF;
2698 
2699             i := i + 1;
2700          END LOOP; -- lc_cursor_inner -- end of OPEN lc_attr_values FOR lc_attr_values_string
2701 
2702          --Debug('MAX RIGHT: ' || l_max_right_length);
2703          --Debug('MAX LEFT : ' || l_max_left_length);
2704 
2705          -- -------------------------------------------------------
2706          -- Build the format string for converting the attribute
2707          -- value to the format that we desire.
2708          -- -------------------------------------------------------
2709          l_format_string := Build_Format_String (
2710                                p_max_left_length  => l_max_left_length,
2711                                p_max_right_length => l_max_right_length
2712                             );
2713 
2714          -- -----------------------------------------------------------
2715          -- If there are any negative numbers in the list, make sure
2716          -- the format string for positive numbers is 1 digit more than
2717          -- the that of the negative numbers.
2718          -- -----------------------------------------------------------
2719 /*
2720          IF (l_any_negative) THEN
2721             l_positive_format_string :=
2722                SUBSTR(l_format_string, 1, 1) || '9' || SUBSTR(l_format_string, 2, LENGTH(l_format_string));
2723          ELSE
2724             l_positive_format_string := l_format_string;
2725          END IF;
2726 */
2727 
2728          -- -----------------------------------------------------------
2729          -- Instead of figuring out if there are any negative numbers
2730          -- (which is difficult to do since the operator could be MIN
2731          -- which would revert a positive number to a negative one),
2732          -- always add an additonal '9' to the right side of a positive
2733          -- format filter.
2734          -- -----------------------------------------------------------
2735          l_positive_format_string :=
2736             SUBSTR(l_format_string, 1, 1) || '9' || SUBSTR(l_format_string, 2, LENGTH(l_format_string));
2737 
2738          --Debug('Format String: ' || l_format_string);
2739 
2740          -- -------------------------------------------------------
2741          -- Now we have the attribute value for a specified
2742          -- attribute for all the partners, we will find the max
2743          -- length of the attribute values in the set, convert
2744          -- the numeric attribute_value into a string, padding
2745          -- 0's if necessary.  Depending on the operator for this
2746          -- attribute, we may need to do some special processing
2747          -- (see conver_to_string below) on the attribute value.
2748          -- -------------------------------------------------------
2749          l_index      := l_tie_breaking_tab.FIRST;
2750          l_last_index := l_tie_breaking_tab.LAST;
2751 
2752          WHILE (l_index <= l_last_index) LOOP
2753             l_tie_breaking_tab(l_index).concat_value_str :=
2754                l_tie_breaking_tab(l_index).concat_value_str ||
2755                Convert_To_String(p_attr_value       => TO_NUMBER(l_tie_breaking_tab(l_index).attr_value),
2756                                  p_max_left_length  => l_max_left_length,
2757                                  p_max_right_length => l_max_right_length,
2758                                  p_format_string    => l_format_string,
2759                                  p_positive_format_string => l_positive_format_string,
2760                                  p_min_max          => lc_cursor.operator) || '#';
2761 
2762             l_index := l_tie_breaking_tab.NEXT(l_index);
2763          END LOOP;
2764 
2765          -- -------------------------------------------------------
2766          -- Check for dupes. No need to continue if there are no
2767          -- dupes.
2768          -- -------------------------------------------------------
2769          l_start := dbms_utility.get_time;
2770 
2771          BEGIN
2772             SELECT *
2773             INTO   l_dup_count
2774             FROM (
2775                SELECT COUNT(*)
2776                FROM   THE (SELECT CAST(l_tie_breaking_tab AS PV_TIE_BREAKING_TBL)
2777                            FROM   dual) a
2778                WHERE  ROWNUM < 2
2779                GROUP  BY concat_value_str
2780                HAVING COUNT(*) > 1) b;
2781 
2782             EXCEPTION
2783              WHEN no_data_found THEN
2784                 --Debug('There are no dupes.');
2785                 l_stop_flag := TRUE;
2786 
2787          END;
2788 
2789 
2790          FETCH c_tie_breaking_attr INTO lc_cursor;
2791 
2792          IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2793             Debug('Finding Dups Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
2794          END IF;
2795       END LOOP;
2796 
2797       CLOSE c_tie_breaking_attr;
2798 
2799 
2800       -- DEBUGGING -------------------------------------------------------------
2801       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2802          Debug('Print out concatenated strings...');
2803          l_index      := l_tie_breaking_tab.FIRST;
2804          l_last_index := l_tie_breaking_tab.LAST;
2805 
2806          WHILE (l_index <= l_last_index) LOOP
2807             Debug(l_tie_breaking_tab(l_index).party_id || ':::' ||
2808                   l_tie_breaking_tab(l_index).concat_value_str);
2809             l_index := l_tie_breaking_tab.NEXT(l_index);
2810          END LOOP;
2811       END IF;
2812       -- DEBUGGING -------------------------------------------------------------
2813 
2814 
2815       -- ------------------------------------------------------------
2816       -- Sort the partners by their concatenated attribute values
2817       -- ------------------------------------------------------------
2818       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2819          Debug('Start sorting..............................');
2820       END IF;
2821 
2822       l_start := dbms_utility.get_time;
2823 
2824       l_index := 1;
2825 
2826       FOR x IN (
2827          SELECT *
2828          FROM   THE (SELECT CAST(l_tie_breaking_tab AS PV_TIE_BREAKING_TBL)
2829                      FROM   dual) a
2830          ORDER  BY concat_value_str DESC)
2831       LOOP
2832          x_partner_tbl(l_index) := x.party_id;
2833          --Debug(x.party_id || ':::' || x.concat_value_str);
2834          l_index := l_index + 1;
2835       END LOOP;
2836 
2837 
2838      /* =====================================================================
2839       -- ------------------------------------------------------------
2840       -- Sorting by concat_value_str and then by idx will preserve the
2841       -- party_ids order as they are passed in through x_partner_tbl
2842       -- should there be a tie in tie-breaking (e.g. all tie-breaking
2843       -- attributes come up with NULL values).
2844       -- ------------------------------------------------------------
2845       FOR x IN (
2846          SELECT *
2847          FROM   THE (SELECT CAST(l_tie_breaking_tab AS PV_TIE_BREAKING_TBL)
2848                      FROM   dual) a
2849          ORDER  BY concat_value_str DESC, idx ASC)
2850       LOOP
2851          x_partner_tbl(l_index) := x.party_id;
2852          --Debug(x.party_id || ':::' || x.concat_value_str);
2853          l_index := l_index + 1;
2854       END LOOP;
2855       * ===================================================================== */
2856 
2857 
2858       -- DEBUGGING -------------------------------------------------------------
2859       IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
2860          Debug('Sorting Elapsed Time: ' || (DBMS_UTILITY.get_time - l_start) || ' hsec');
2861 
2862          Debug('Printing out partner IDs after sorting...');
2863          FOR i IN 1..x_partner_tbl.COUNT LOOP
2864             Debug(x_partner_tbl(i));
2865          END LOOP;
2866       END IF;
2867       -- DEBUGGING -------------------------------------------------------------
2868    END Tie_Breaker;
2869 -- =========================End of Tie_Breaker==================================
2870 
2871 --=============================================================================+
2872 --|  Public Procedure                                                          |
2873 --|                                                                            |
2874 --|    Set_Message                                                             |
2875 --|                                                                            |
2876 --|  Parameters                                                                |
2877 --|  IN                                                                        |
2878 --|  OUT                                                                       |
2879 --|                                                                            |
2880 --|                                                                            |
2881 --| NOTES:                                                                     |
2882 --|                                                                            |
2883 --| HISTORY                                                                    |
2884 --|                                                                            |
2885 --==============================================================================
2886 PROCEDURE Set_Message(
2887     p_msg_level     IN      NUMBER,
2888     p_msg_name      IN      VARCHAR2,
2889     p_token1        IN      VARCHAR2,
2890     p_token1_value  IN      VARCHAR2,
2891     p_token2        IN      VARCHAR2 := NULL ,
2892     p_token2_value  IN      VARCHAR2 := NULL,
2893     p_token3        IN      VARCHAR2 := NULL,
2894     p_token3_value  IN      VARCHAR2 := NULL
2895 )
2896 IS
2897 BEGIN
2898     IF FND_MSG_PUB.Check_Msg_Level(p_msg_level) THEN
2899         FND_MESSAGE.Set_Name('PV', p_msg_name);
2900         FND_MESSAGE.Set_Token(p_token1, p_token1_value);
2901 
2902         IF (p_token2 IS NOT NULL) THEN
2903            FND_MESSAGE.Set_Token(p_token2, p_token2_value);
2904         END IF;
2905 
2906         IF (p_token3 IS NOT NULL) THEN
2907            FND_MESSAGE.Set_Token(p_token3, p_token3_value);
2908         END IF;
2909 
2910         FND_MSG_PUB.Add;
2911     END IF;
2912 END Set_Message;
2913 
2914 --=============================================================================+
2915 --|  Private Procedure                                                         |
2916 --|                                                                            |
2917 --|    Get_Attr_Length                                                         |
2918 --|        Given a "string of NUMBER", this procedure will return the length of|
2919 --|        the string to the left of the decimal point as well as that of the  |
2920 --|        string to the right of the decimal point.                           |
2921 --|                                                                            |
2922 --|  Parameters                                                                |
2923 --|  IN                                                                        |
2924 --|  OUT                                                                       |
2925 --|                                                                            |
2926 --|                                                                            |
2927 --| NOTES:                                                                     |
2928 --|                                                                            |
2929 --| HISTORY                                                                    |
2930 --|                                                                            |
2931 --==============================================================================
2932 PROCEDURE Get_Attr_Length(
2933    p_attr_value      IN  VARCHAR2,
2934    p_left_length     OUT NOCOPY NUMBER,
2935    p_right_length    OUT NOCOPY NUMBER)
2936 IS
2937    l_attr_value      VARCHAR2(2000);
2938 
2939 BEGIN
2940    -- --------------------------------------------------------------------------
2941    -- The negative sign should not be counted when counting string length.
2942    -- --------------------------------------------------------------------------
2943    l_attr_value := REPLACE(p_attr_value, '-', '');
2944 
2945    IF (INSTR(p_attr_value, '.') = 0) THEN
2946       p_left_length  := LENGTH(l_attr_value);
2947       p_right_length := 0;
2948 
2949    ELSE
2950       p_left_length  := LENGTH(SUBSTR(l_attr_value, 1, INSTR(l_attr_value, '.') - 1));
2951       p_right_length := LENGTH(SUBSTR(l_attr_value, INSTR(l_attr_value, '.') + 1, LENGTH(l_attr_value)));
2952    END IF;
2953 END Get_Attr_Length;
2954 -- ===========================End of Get_Attr_Length============================
2955 
2956 
2957 
2958 --=============================================================================+
2959 --|  Private Function                                                          |
2960 --|                                                                            |
2961 --|    Build_Format_String                                                     |
2962 --|                                                                            |
2963 --|  Parameters                                                                |
2964 --|  IN                                                                        |
2965 --|  OUT                                                                       |
2966 --|                                                                            |
2967 --|                                                                            |
2968 --| NOTES:                                                                     |
2969 --|  e.g. of value returned:                                                   |
2970 --|     '09999999.9990', '09999.990'                                           |
2971 --|                                                                            |
2972 --| HISTORY                                                                    |
2973 --|                                                                            |
2974 --==============================================================================
2975 FUNCTION Build_Format_String (
2976    p_max_left_length  NUMBER,
2977    p_max_right_length NUMBER)
2978 RETURN VARCHAR2 IS
2979    l_format_string VARCHAR2(100);
2980 
2981 BEGIN
2982    l_format_string := '0';
2983 
2984    FOR i IN 1..p_max_left_length - 1 LOOP
2985       l_format_string := l_format_string || '9';
2986    END LOOP;
2987 
2988    IF (p_max_right_length > 0) THEN
2989       l_format_string := l_format_string || '.';
2990 
2991       FOR i IN 1..p_max_right_length - 1 LOOP
2992          l_format_string := l_format_string || '9';
2993       END LOOP;
2994 
2995       l_format_string := l_format_string || '0';
2996    END IF;
2997 
2998    RETURN l_format_string;
2999 END;
3000 -- ====================End of Build_Format_String==========================
3001 
3002 
3003 
3004 --=============================================================================+
3005 --|  Private Function                                                          |
3006 --|                                                                            |
3007 --|    Convert_To_String                                                       |
3008 --|                                                                            |
3009 --|  Parameters                                                                |
3010 --|  IN                                                                        |
3011 --|  OUT                                                                       |
3012 --|                                                                            |
3013 --|                                                                            |
3014 --| NOTES:                                                                     |
3015 --|                                                                            |
3016 --| HISTORY                                                                    |
3017 --|                                                                            |
3018 --==============================================================================
3019 FUNCTION Convert_To_String(p_attr_value             NUMBER,
3020                            p_max_left_length        NUMBER,
3021                            p_max_right_length       NUMBER,
3022                            p_format_string          VARCHAR2,
3023                            p_positive_format_string VARCHAR2,
3024                            p_min_max                VARCHAR2)
3025 RETURN VARCHAR2 IS
3026    l_attr_value    NUMBER := p_attr_value;
3027    l_format_string VARCHAR2(300);
3028    l_null_string   VARCHAR2(300);
3029 
3030 BEGIN
3031    -- -----------------------------------------------------------------
3032    -- If the attribute value is NULL, we want to assign it the
3033    -- "smallest" possible VARCHAR2 value with a length of the format
3034    -- string.  The "smallest" value would be a string with all '-'s.
3035    -- e.g. '----------'
3036    -- -----------------------------------------------------------------
3037    IF (p_attr_value IS NULL) THEN
3038       FOR i IN 1..LENGTH(p_positive_format_string) LOOP
3039          IF (p_min_max = 'MIN') THEN
3040             l_null_string := l_null_string || '9';
3041         ELSE
3042             l_null_string := l_null_string || '-';
3043         END IF;
3044       END LOOP;
3045 
3046       RETURN l_null_string;
3047    END IF;
3048 
3049    -- -----------------------------------------------------------------
3050    -- If p_min_max is 'MIN', which means that 40 is
3051    -- ranked higher than 60, then we need to substract the attribute
3052    -- value from x where x is:
3053    -- POWER(10, p_max_attr_length)
3054    --
3055    -- e.g.
3056    --    If p_max_left_length is 3 (e.g. 100, 200, 250, etc.), then
3057    --    x = POWER(10, 3) = 1000
3058    --
3059    -- The attribute value in this case would be (1000 - p_attr_value).
3060    --
3061    -- Also if the attribute value is a negative number, we need to the
3062    -- similar thing described above for 'MIN'.  Of course, we want
3063    -- to leave the negative sign intact.
3064    --
3065    -- The reason for doing this is that we are doing string comparsion
3066    -- even though we are really comparing numbers.  When a number is
3067    -- negative, a normal string comparsion would yield the opposite
3068    -- result.
3069    -- e.g.
3070    --    '-1.7' > '-1.6'  ==> This is TRUE for string comparsion but
3071    --                         FALSE for number comparsion.
3072    --
3073    -- In the case of 'MIN' and negative number, nothing needs to be
3074    -- done since it would just be doing the above operation twice,
3075    -- reverting it to its original result.
3076    --
3077    -- Here's the algorithm:
3078    -- IF (negative AND MIN) THEN
3079    --    Turn it into a positive number
3080    -- ELSIF (negative AND MAX) THEN
3081    --    Substract from x (see above) and keep the negative sign
3082    -- ELSIF (positive AND MIN) THEN
3083    --    Substract from x and prefix it with a negative sign
3084    -- ELSIF (positive and MAX) THEN
3085    --    Just pad with 0's
3086    -- END IF;
3087    -- -----------------------------------------------------------------
3088    IF (p_min_max = 'MIN') THEN
3089       -- --------------------------------------------------------------
3090       -- If a positive number.
3091       -- --------------------------------------------------------------
3092       IF (TO_NUMBER(p_attr_value) > 0) THEN
3093          l_attr_value := POWER(10, p_max_left_length) - p_attr_value;
3094          l_attr_value := -l_attr_value;
3095 
3096       -- --------------------------------------------------------------
3097       -- If a negative number.
3098       -- --------------------------------------------------------------
3099       ELSIF (TO_NUMBER(p_attr_value) < 0) THEN
3100          l_attr_value := -l_attr_value;
3101       END IF;
3102 
3103    ELSIF (p_min_max = 'MAX') THEN
3104       -- --------------------------------------------------------------
3105       -- If a negative number.
3106       -- --------------------------------------------------------------
3107       IF (TO_NUMBER(p_attr_value) < 0) THEN
3108          -- -----------------------------------------------------------
3109          -- Only substract the positive portion of a negative number
3110          -- string from POWER(10, p_max_left_length). This is
3111          -- equivalent of adding it.
3112          -- -----------------------------------------------------------
3113          l_attr_value := POWER(10, p_max_left_length) + p_attr_value;
3114          l_attr_value := -l_attr_value;
3115       END IF;
3116    END IF;
3117 
3118    -- -----------------------------------------------------------------
3119    -- If the number is positive, apply the format string for positive
3120    -- numbers.  This is to ensure that positive and negative numbers
3121    -- end up with a string with equal length.
3122    --
3123    -- e.g. TO_CHAR(100, '0999')  ==> '0100'
3124    --      TO_CHAR(-100, '0999') ==> '-0100'
3125    --
3126    -- We want it to be like this for positive numbers:
3127    --      TO_CHAR(100, '09999') ==> '00100'
3128    --      TO_CHAR(-100, '0999') ==> '-0100'
3129    -- -----------------------------------------------------------------
3130    IF (l_attr_value >= 0) THEN
3131       l_format_string := p_positive_format_string;
3132    ELSE
3133       l_format_string := p_format_string;
3134    END IF;
3135 
3136    -- -----------------------------------------------------------------
3137    -- It is important to use LTRIM() here because ORACLE always adds
3138    -- a blank space in front of the converted string unless the number
3139    -- is negative.
3140    -- -----------------------------------------------------------------
3141    RETURN LTRIM(TO_CHAR(l_attr_value, l_format_string));
3142 END Convert_To_String;
3143 -- ====================End of Convert_To_String==========================
3144 
3145 -- ====================Start of get_attribute_value========================
3146 FUNCTION get_attribute_value (attribute_id NUMBER ,partner_id NUMBER)
3147 RETURN VARCHAR2
3148 as
3149     CURSOR lc_get_pt_type (pc_attribute_id NUMBER,pc_partner_id NUMBER) is
3150     SELECT pac.description
3151     FROM pv_attribute_codes_vl pac,
3152         pv_enty_attr_values peav
3153     WHERE peav.entity_id =  pc_partner_id
3154     AND peav.entity(+) = 'PARTNER'
3155     AND peav.attribute_id(+) = pc_attribute_id
3156     AND peav.attribute_id = pac.attribute_id(+)
3157     AND pac.attr_code(+) = peav.attr_value
3158     AND peav.latest_flag = 'Y'
3159     AND peav.enabled_flag = 'Y';
3160 
3161     l_partner_type_str VARCHAR2(500);
3162 BEGIN
3163 
3164     FOR c1 IN lc_get_pt_type(pc_attribute_id => attribute_id, pc_partner_id => partner_id)
3165     LOOP
3166         IF c1.description IS NOT NULL THEN
3167             l_partner_type_str := l_partner_type_str || ',' || c1.description;
3168         END IF;
3169 
3170     END LOOP;
3171 
3172     RETURN substr(l_partner_type_str,2);
3173 END get_attribute_value;
3174 -- ====================End of get_attribute_value==========================
3175 
3176 -- ====================Start of get_metric_value========================
3177 FUNCTION get_metric_value(attribute_id NUMBER ,partner_id NUMBER)
3178 RETURN NUMBER
3179 AS
3180     --CURSOR lc_get_metric_raw_value (pc_attribute_id NUMBER,pc_partner_id NUMBER) is
3181 
3182     l_get_metric_raw_value  varchar2(500) :=
3183 
3184     'SELECT pav.return_type, pav.display_style, psav.attr_value,psav.attr_text, pav.decimal_points ' ||
3185     'FROM pv_attributes_vl pav, ' ||
3186     '    pv_search_attr_values psav ' ||
3187     'WHERE psav.PARTY_ID =  :1 ' ||
3188     'AND psav.attribute_id = :2 ' ||
3189     'AND psav.attribute_id = pav.attribute_id ' ;
3190 
3191     TYPE t_metric_raw_value_cursor IS REF CURSOR;
3192     lc_get_metric_raw_value t_metric_raw_value_cursor;
3193 
3194 
3195     l_return_type VARCHAR2(100);
3196     l_display_style VARCHAR2(100);
3197     l_attr_value NUMBER;
3198     l_attr_text VARCHAR2(1000);
3199     l_metric_value NUMBER;
3200     l_decimals NUMBER;
3201 BEGIN
3202 
3203    --OPEN  lc_get_metric_raw_value(pc_attribute_id => attribute_id , pc_partner_id => partner_id);
3204 
3205     OPEN lc_get_metric_raw_value FOR l_get_metric_raw_value using partner_id, attribute_id ;
3206     LOOP
3207     FETCH lc_get_metric_raw_value INTO l_return_type,l_display_style,l_attr_value,l_attr_text,l_decimals;
3208     EXIT; -- WHEN lc_get_metric_raw_value%NOTFOUND;
3209     END LOOP;
3210 
3211     IF (lc_get_metric_raw_value%NOTFOUND) THEN
3212         l_metric_value := null;
3213     ELSE
3214         IF l_return_type = 'NUMBER'  THEN
3215 
3216             IF l_display_style = 'PERCENTAGE'  THEN
3217 
3218                 l_metric_value := l_attr_value * 100;
3219             ELSE
3220                 l_metric_value := l_attr_value;
3221             END IF;
3222             IF l_decimals IS NOT NULL THEN
3223                 l_metric_value := trunc(l_metric_value,l_decimals);
3224             ELSE
3225                 l_metric_value := trunc(l_metric_value,2);
3226             END IF;
3227 
3228 
3229         ELSIF  l_return_type = 'CURRENCY'  THEN
3230             l_metric_value := pv_check_match_pub.currency_conversion(l_attr_text);
3231 
3232         ELSE
3233            l_metric_value := 0;
3234         END IF;
3235 
3236 
3237     END IF;
3238 
3239     RETURN l_metric_value;
3240 
3241 END get_metric_value;
3242 -- ====================End of get_metric_value==========================
3243 
3244 -- ====================Start of get_currency_metric_value========================
3245 FUNCTION get_currency_metric_value(attribute_id NUMBER ,partner_id NUMBER)
3246 RETURN varchar2
3247 AS
3248     --CURSOR lc_get_metric_raw_value (pc_attribute_id NUMBER,pc_partner_id NUMBER) is
3249 
3250     l_get_metric_raw_value  varchar2(500) :=
3251 
3252     'SELECT pav.return_type, pav.display_style, psav.attr_value,psav.attr_text, pav.decimal_points ' ||
3253     'FROM pv_attributes_vl pav, ' ||
3254     '    pv_search_attr_values psav ' ||
3255     'WHERE psav.PARTY_ID =  :1 ' ||
3256     'AND psav.attribute_id = :2 ' ||
3257     'AND psav.attribute_id = pav.attribute_id ' ;
3258 
3259     TYPE t_metric_raw_value_cursor IS REF CURSOR;
3260     lc_get_metric_raw_value t_metric_raw_value_cursor;
3261 
3262 
3263     l_return_type VARCHAR2(100);
3264     l_display_style VARCHAR2(100);
3265     l_attr_value NUMBER;
3266     l_attr_text VARCHAR2(1000);
3267     l_metric_value VARCHAR2(100);
3268     l_decimals NUMBER;
3269     l_user_currency_code VARCHAR(30)	:=nvl(fnd_profile.value('ICX_PREFERRED_CURRENCY'), 'USD');
3270     --l_curr_value VARCHAR2(80);
3271 BEGIN
3272 
3273    --OPEN  lc_get_metric_raw_value(pc_attribute_id => attribute_id , pc_partner_id => partner_id);
3274 
3275     OPEN lc_get_metric_raw_value FOR l_get_metric_raw_value using partner_id, attribute_id ;
3276     LOOP
3277     FETCH lc_get_metric_raw_value INTO l_return_type,l_display_style,l_attr_value,l_attr_text,l_decimals;
3278     EXIT; -- WHEN lc_get_metric_raw_value%NOTFOUND;
3279     END LOOP;
3280 
3281     IF (lc_get_metric_raw_value%NOTFOUND) THEN
3282         l_metric_value := null;
3283     ELSE
3284         IF  l_return_type = 'CURRENCY'  THEN
3285             begin
3286                 --select name into l_curr_value from fnd_currencies_vl
3287 				--where currency_code=l_user_currency_code;
3288 
3289                 l_metric_value := pv_check_match_pub.Currency_Conversion(
3290 							l_attr_text,
3291 							l_user_currency_code
3292 							) || ' ' || l_user_currency_code;
3293 
3294                 exception
3295 			when others then
3296 			--dbms_output.put_line('error:' || SQLERRM);
3297 			l_metric_value:= '';
3298 			end;
3299 
3300 
3301         ELSE
3302            l_metric_value := '';
3303         END IF;
3304 
3305 
3306     END IF;
3307 
3308     RETURN l_metric_value;
3309 
3310 END get_currency_metric_value;
3311 
3312 -- ====================End of get_currency_metric_value===============
3313 
3314 
3315 -- ====================Start of get_assign_status_meaning===============
3316 FUNCTION get_assign_status_meaning (p_lead_id NUMBER, p_partner_id NUMBER)
3317 RETURN VARCHAR2
3318 AS
3319     CURSOR lc_assign_status (pc_lead_id NUMBER, pc_partner_id NUMBER) is
3320     SELECT DECODE(pla.status,'MATCH_WITHDRAWN','UNASSIGNED'
3321                             ,'MATCH_WITHDRAWN','UNASSIGNED'
3322                             ,'OFFER_WITHDRAWN','UNASSIGNED'
3323                             ,'PT_TIMEOUT','UNASSIGNED'
3324                             ,'ACTIVE_WITHDRAWN','UNASSIGNED'
3325                             ,'LOST_CHANCE','UNASSIGNED'
3326                             ,'CM_ADDED','ASSIGNED'
3327                             ,'PT_REJECTED','CM_REJECTED'
3328                             ,'CM_BYPASSED','CM_APPROVED'
3329                             ,'CM_TIMEOUT','CM_APPROVED'
3330                             ,'CM_APP_FOR_PT','PT_APPROVED'
3331                             ,'CM_ADD_APP_FOR_PT','PT_APPROVED'
3332                             ,'PT_CREATED','PT_APPROVED'
3333                             ,pla.status) assign_status
3334            , plw.wf_status
3335            , plw.routing_status
3336            , pla.status
3337            , plw.routing_type
3338            , pla.wf_item_key
3339            , pla.assign_sequence
3340     FROM   pv_lead_assignments pla,
3341            pv_lead_workflows plw
3342     WHERE  plw.lead_id = pc_lead_id
3343     AND    plw.wf_item_key = pla.wf_item_key
3344     AND    plw.wf_item_type = pla.wf_item_type
3345     AND    pla.partner_id = pc_partner_id
3346     AND    plw.latest_routing_flag = 'Y';
3347 
3348     CURSOR lc_status_meaning (pc_status VARCHAR2) IS
3349     SELECT MEANING
3350     FROM   PV_LOOKUPS
3351     WHERE  LOOKUP_TYPE = 'PV_ASN_ASSIGNMENT_STATUS'
3352     AND    LOOKUP_CODE = pc_status;
3353 
3354     CURSOR lc_curr_rank (p_wf_item_key NUMBER) IS
3355     SELECT wf_engine.GetItemAttrNumber( 'PVASGNMT',p_wf_item_key,'PV_SERIAL_RANK_ATTR')
3356     FROM   dual;
3357 
3358     l_assign_status VARCHAR2(500) := 'UNASSIGNED';
3359     l_wf_status VARCHAR2(500);
3360     l_routing_status VARCHAR2(500);
3361     l_routing_type VARCHAR2(50);
3362     l_wf_item_key VARCHAR2(10);
3363     l_curr_offered_rank NUMBER;
3364     l_curr_partner_in_serial VARCHAR2(10);
3365     l_assign_seq NUMBER;
3366 
3367     l_assign_status_mean VARCHAR2(500);
3368 BEGIN
3369 
3370     FOR c1 IN lc_assign_status(pc_lead_id => p_lead_id
3371                              , pc_partner_id => p_partner_id)
3372     LOOP
3373         l_wf_status := c1.wf_status;
3374         l_routing_status := c1.routing_status;
3375         l_routing_type := c1.routing_type;
3376         l_wf_item_key := c1.wf_item_key;
3377         l_assign_seq := c1.assign_sequence;
3378         l_assign_status := c1.assign_status;
3379 
3380         -- Cases like recycled, abandonded, partner timeout will come
3381         -- under this case. the wf is closed and not active.
3382         IF l_wf_status = 'CLOSED' AND l_routing_status <> 'ACTIVE' THEN
3383             l_assign_status := 'UNASSIGNED';
3384         -- If wf_status is null that means it is unassigned
3385         ELSIF l_wf_status IS NULL  THEN
3386             l_assign_status := 'UNASSIGNED';
3387         -- This works only in serial case. If the routing is serial and
3388         -- the current partner is the one to whom it is offered then it
3389         -- must say offered not active
3390         ELSIF l_routing_type = 'SERIAL' THEN
3391             BEGIN
3392                 OPEN lc_curr_rank(l_wf_item_key);
3393                 FETCH lc_curr_rank into l_curr_offered_rank;
3394                 CLOSE lc_curr_rank;
3395 
3396                 IF l_assign_seq = l_curr_offered_rank THEN
3397                     l_curr_partner_in_serial := 'Y';
3398                 END IF;
3399 
3400             EXCEPTION
3401             WHEN OTHERS THEN
3402                     l_curr_partner_in_serial := 'N';
3403             END;
3404 
3405 	    /*
3406             IF l_curr_partner_in_serial = 'Y' THEN
3407                 l_assign_status := 'OFFERED';
3408             END IF;
3409 	    */
3410 	    --for bug# 4217950
3411 	    IF(l_wf_status = 'OPEN' and l_curr_partner_in_serial = 'Y') THEN
3412                 l_assign_status := 'OFFERED';
3413 	    END IF;
3414 	    -- end of change fir bug# 4217950
3415 
3416         -- If the routing status is Offered then all rows that are Approved
3417         -- should say Offered.
3418         ELSIF l_routing_status = 'OFFERED'
3419               AND c1.assign_status = 'CM_APPROVED'
3420               AND l_routing_type <> 'SERIAL' THEN
3421             l_assign_status := 'OFFERED';
3422         ELSE
3423             l_assign_status := c1.assign_status;
3424         END IF;
3425     END LOOP;
3426 
3427     OPEN  lc_status_meaning(pc_status => l_assign_status);
3428     FETCH lc_status_meaning INTO l_assign_status_mean;
3429 
3430     IF (lc_status_meaning%NOTFOUND) THEN
3431         l_assign_status_mean := null;
3432     END IF;
3433 
3434     RETURN l_assign_status_mean;
3435 END get_assign_status_meaning;
3436 -- ====================End of get_assign_status_meaning==================
3437 -- ====================Start of get_partner_types========================
3438 FUNCTION get_partner_types (partner_id NUMBER)
3439 RETURN VARCHAR2
3440 as
3441     CURSOR lc_get_pt_type (pc_partner_id NUMBER) is
3442     SELECT pac.description
3443     FROM pv_attribute_codes_vl pac,
3444         pv_enty_attr_values peav
3445     WHERE peav.entity_id =  pc_partner_id
3446     AND peav.entity(+) = 'PARTNER'
3447     AND peav.attribute_id(+) = 3
3448     AND peav.attribute_id = pac.attribute_id(+)
3449     AND pac.attr_code(+) = peav.attr_value
3450     AND peav.latest_flag = 'Y'
3451     AND peav.enabled_flag = 'Y'
3452     AND peav.attr_value_extn = 'Y' ;
3453 
3454     l_partner_type_str VARCHAR2(500);
3455 BEGIN
3456 
3457     FOR c1 IN lc_get_pt_type(pc_partner_id => partner_id)
3458     LOOP
3459         l_partner_type_str := l_partner_type_str || ',' || c1.description;
3460     END LOOP;
3461 
3462     RETURN substr(l_partner_type_str,2);
3463 END get_partner_types;
3464 -- ====================End of get_partner_types==========================
3465 
3466 -- ====================Start of pref_partner_flag========================
3467 FUNCTION pref_partner_flag (p_lead_id NUMBER, p_partner_id NUMBER)
3468 RETURN VARCHAR2
3469 AS
3470     CURSOR lc_incumbent_part (pc_lead_id NUMBER, pc_partner_id NUMBER) is
3471     SELECT 'Y'
3472     FROM  as_leads_all
3473     WHERE lead_id = pc_lead_id
3474     AND   incumbent_partner_party_id = pc_partner_id;
3475 
3476     l_pref_part_str VARCHAR2(1);
3477 BEGIN
3478 
3479     l_pref_part_str := 'N';
3480 
3481     OPEN  lc_incumbent_part(p_lead_id , p_partner_id);
3482     FETCH lc_incumbent_part INTO l_pref_part_str;
3483 
3484     IF (lc_incumbent_part%NOTFOUND) THEN
3485         l_pref_part_str := 'N';
3486     END IF;
3487 
3488    CLOSE lc_incumbent_part;
3489 
3490     RETURN l_pref_part_str;
3491 END pref_partner_flag;
3492 -- ====================End of pref_partner_flag==========================
3493 -- ====================Begin of is_cm_flag==========================
3494 FUNCTION lock_flag (p_lead_assign_id NUMBER, p_wf_item_key VARCHAR2)
3495 RETURN VARCHAR2
3496 AS
3497     CURSOR lc_cm_for_partner (pc_lead_assign_id NUMBER, pc_wf_item_key VARCHAR2)
3498     IS
3499     SELECT 'N'
3500     FROM pv_party_notifications
3501     WHERE lead_assignment_id = pc_lead_assign_id
3502     AND wf_item_type = 'PVASGNMT'
3503     AND wf_item_key = pc_wf_item_key
3504     --AND notification_type = 'MATCHED_TO'
3505     AND user_id = FND_GLOBAL.user_id;
3506 
3507     CURSOR lc_routing_status (pc_wf_item_key VARCHAR2)
3508     IS
3509     SELECT routing_status
3510     FROM   pv_lead_workflows
3511     WHERE  wf_item_key = pc_wf_item_key
3512     AND    wf_item_type = 'PVASGNMT'
3513     AND    latest_routing_flag = 'Y';
3514 
3515     CURSOR lc_user_type
3516     IS
3517     SELECT jtfre.category
3518     FROM jtf_rs_resource_extns jtfre
3519     WHERE jtfre.user_id = FND_GLOBAL.user_id
3520     AND start_date_active <= sysdate
3521     AND (end_date_active IS NULL OR end_date_active > sysdate);
3522 
3523 
3524     l_lock_flag VARCHAR2(1);
3525     l_routing_status VARCHAR2(50);
3526     l_user_type VARCHAR2(50);
3527 BEGIN
3528     -- In the UI we are using an API which locks the
3529     -- row for value 'Y' and leaves it enabled for value 'N'
3530 
3531     -- Added fix to make sure checking for the vendor and statuses
3532     -- before showing lock flag. This was found when testing fix for
3533     -- Bug 4115728
3534     l_lock_flag := 'Y';
3535 
3536     OPEN  lc_routing_status(p_wf_item_key);
3537     FETCH lc_routing_status INTO l_routing_status;
3538 
3539     IF (lc_routing_status%NOTFOUND
3540         OR l_routing_status = 'UNASSIGNED'
3541         OR l_routing_status = 'WITHDRAWN'
3542         OR l_routing_status = 'RECYCLED'
3543         OR l_routing_status = 'ABANDONED'
3544         OR l_routing_status = 'ACTIVE') THEN
3545 
3546         OPEN  lc_user_type;
3547         FETCH lc_user_type INTO l_user_type;
3548 
3549         IF l_user_type = 'EMPLOYEE' THEN
3550             l_lock_flag := 'N';
3551         ELSE
3552             OPEN  lc_cm_for_partner(p_lead_assign_id , p_wf_item_key);
3553             FETCH lc_cm_for_partner INTO l_lock_flag;
3554 
3555             IF (lc_cm_for_partner%NOTFOUND) THEN
3556                 l_lock_flag := 'Y';
3557             END IF;
3558             CLOSE lc_cm_for_partner;
3559         END IF;
3560 
3561         CLOSE lc_user_type;
3562 
3563     ELSE
3564         OPEN  lc_cm_for_partner(p_lead_assign_id , p_wf_item_key);
3565         FETCH lc_cm_for_partner INTO l_lock_flag;
3566 
3567         IF (lc_cm_for_partner%NOTFOUND) THEN
3568             l_lock_flag := 'Y';
3569         END IF;
3570         CLOSE lc_cm_for_partner;
3571 
3572     END IF;
3573 
3574     CLOSE lc_routing_status;
3575 
3576 
3577     RETURN l_lock_flag;
3578 END lock_flag;
3579 -- ====================End of is_cm_flag==========================
3580 --=============================================================================+
3581 --|  Public Procedure                                                          |
3582 --|                                                                            |
3583 --|    PROCEDURE Clear_Rules_Cache                                             |
3584 --|                                                                            |
3585 --|                                                                            |
3586 --|  Parameters                                                                |
3587 --|  IN                                                                        |
3588 --|  OUT                                                                       |
3589 --|                                                                            |
3590 --|                                                                            |
3591 --| NOTES                                                                      |
3592 --|                                                                            |
3593 --| HISTORY                                                                    |
3594 --|                                                                            |
3595 --==============================================================================
3596 PROCEDURE Clear_Rules_Cache IS
3597 BEGIN
3598    g_opp_selection_tab.DELETE;
3599 END;
3600 -- ==========================End of Clear_Rules_Cache===========================
3601 
3602 FUNCTION Get_Next_Rule_Index(
3603    p_current_index     NUMBER,
3604    p_opp_selection_tab t_opp_selection_tab
3605 )
3606 RETURN NUMBER
3607 IS
3608    i                 NUMBER := p_current_index;
3609    l_current_rule_id NUMBER := p_opp_selection_tab(p_current_index).process_rule_id;
3610    l_last_index      NUMBER := p_opp_selection_tab.LAST;
3611 
3612 BEGIN
3613    -- ---------------------------------------------------------------------------
3614    -- We're already at the end of the array. No more rules to evaluate.
3615    -- ---------------------------------------------------------------------------
3616    IF (i = l_last_index) THEN
3617       RETURN g_no_more_Rules;
3618    END IF;
3619 
3620    -- ---------------------------------------------------------------------------
3621    -- Starting from the next item in the array, if the process_rule_id changes,
3622    -- this indicates the start of a new record.  Return the index of this record.
3623    -- ---------------------------------------------------------------------------
3624    i := i + 1;
3625 
3626    WHILE ((p_opp_selection_tab(i).process_rule_id = l_current_rule_id) AND
3627          (i < l_last_index))
3628    LOOP
3629       i := i + 1;
3630    END LOOP;
3631 
3632    -- ---------------------------------------------------------------------------
3633    -- We've reached the end of the index, no more rules to evaluate.
3634    -- ---------------------------------------------------------------------------
3635    IF ((i = l_last_index) AND
3636       (p_opp_selection_tab(i).process_rule_id = l_current_rule_id))
3637    THEN
3638       i := g_no_more_rules;
3639    END IF;
3640 
3641    RETURN i;
3642 
3643    -- -------------------------------------------------------
3644    -- May want to capture INDEX OUT OF BOUND here by trapping
3645    -- ORA-01403: no data found
3646    -- -------------------------------------------------------
3647 END Get_Next_Rule_Index;
3648 -- ===========================End of Get_Next_Rule_Index===========================
3649 
3650 PROCEDURE Cache_Rules IS
3651    -- --------------------------------------------------------------------
3652    -- Note that we need an outer join from pv_enty_select_criteria to
3653    -- pv_selected_attr_value
3654    -- since certain attributes (e.g. <condition> is not null) will not
3655    -- have attribute values.
3656    -- --------------------------------------------------------------------
3657 
3658    CURSOR lc_opp_selection IS
3659       SELECT prr.process_rule_id,
3660              prr.rank,
3661              pesc.attribute_id,
3662              prr.currency_code,
3663              pesc.operator,
3664              pesc.selection_criteria_id,
3665              psav.attribute_value,
3666              psav.attribute_to_value
3667       FROM   pv_process_rules_vl prr,
3668              pv_enty_select_criteria pesc,
3669              pv_selected_attr_values psav
3670       WHERE  prr.process_rule_id = pesc.process_rule_id AND
3671              pesc.selection_criteria_id = psav.selection_criteria_id (+) AND
3672              prr.status_code = 'ACTIVE' AND
3673              TRUNC(SYSDATE) BETWEEN prr.start_date AND
3674                 NVL(prr.end_date, to_DATE('31-12-4000', 'DD-MM-YYYY')) AND
3675              pesc.selection_type_code = 'OPPORTUNITY_SELECTION'
3676       ORDER  BY prr.rank DESC, prr.process_rule_id, pesc.attribute_id,
3677              pesc.selection_criteria_id;
3678 
3679    i                   NUMBER := 1;
3680    l_count             NUMBER;
3681    l_or_count          NUMBER;
3682    l_next_index        NUMBER;
3683    l_next_rule_id      NUMBER;
3684    l_next_attribute_id NUMBER;
3685    l_next_sc_id        NUMBER;
3686    l_lower_index       NUMBER;
3687 
3688 BEGIN
3689    -- --------------------------------------------------------------------------
3690    -- Cache rules only if they are not already cached.
3691    -- --------------------------------------------------------------------------
3692    IF (g_opp_selection_tab.COUNT = 0) THEN
3693       FOR l_opp_selection IN lc_opp_selection LOOP
3694          g_opp_selection_tab(i).rank                  := l_opp_selection.rank;
3695          g_opp_selection_tab(i).process_rule_id       := l_opp_selection.process_rule_id;
3696          g_opp_selection_tab(i).attribute_id          := l_opp_selection.attribute_id;
3697          g_opp_selection_tab(i).currency_code         := l_opp_selection.currency_code;
3698          g_opp_selection_tab(i).operator              := l_opp_selection.operator;
3699          g_opp_selection_tab(i).selection_criteria_id := l_opp_selection.selection_criteria_id;
3700          g_opp_selection_tab(i).attribute_value       := l_opp_selection.attribute_value;
3701          g_opp_selection_tab(i).attribute_to_value    := l_opp_selection.attribute_to_value;
3702 
3703          i := i + 1;
3704       END LOOP;
3705 
3706       -- --------------------------------------------------------------------------------
3707       -- Set last_attr_flag and count in g_opp_selection_tab.
3708       -- --------------------------------------------------------------------------------
3709       l_count    := g_opp_selection_tab.COUNT;
3710       l_or_count := 1;
3711 
3712       FOR i IN 1..l_count LOOP
3713          IF (i = l_count) THEN
3714             g_opp_selection_tab(i).last_attr_flag := 'Y';
3715 
3716             l_lower_index := i - l_or_count + 1;
3717 
3718             FOR j IN l_lower_index..i LOOP
3719                g_opp_selection_tab(j).count := l_or_count;
3720             END LOOP;
3721 
3722          ELSE
3723             l_next_index        := g_opp_selection_tab.NEXT(i);
3724             l_next_rule_id      := g_opp_selection_tab(l_next_index).process_rule_id;
3725             l_next_attribute_id := g_opp_selection_tab(l_next_index).attribute_id;
3726             l_next_sc_id        := g_opp_selection_tab(l_next_index).selection_criteria_id;
3727 
3728             -- ---------------------------------------------------------------------------
3729             -- If the current process_rule_id is not the same as the next
3730             -- process_rule_id, then this is the last attribute in the rule.
3731             -- ---------------------------------------------------------------------------
3732             IF (l_next_rule_id <> g_opp_selection_tab(i).process_rule_id) THEN
3733                g_opp_selection_tab(i).last_attr_flag := 'Y';
3734             ELSE
3735                g_opp_selection_tab(i).last_attr_flag := 'N';
3736             END IF;
3737 
3738             -- ---------------------------------------------------------------------------
3739             -- Set g_opp_selection_tab.count.  This field is used to indicate the number
3740             -- of records involved in an AND/OR logic. If the count is 1, then the logic
3741             -- is AND. If the count is greater than 1, the logic is OR.
3742             -- ---------------------------------------------------------------------------
3743             IF (l_next_rule_id      = g_opp_selection_tab(i).process_rule_id) AND
3744                (l_next_attribute_id = g_opp_selection_tab(i).attribute_id) AND
3745                (l_next_sc_id        = g_opp_selection_tab(i).selection_criteria_id)
3746             THEN
3747                l_or_count := l_or_count + 1;
3748 
3749             ELSE
3750                l_lower_index := i - l_or_count + 1;
3751 
3752                FOR j IN l_lower_index..i LOOP
3753                   g_opp_selection_tab(j).count := l_or_count;
3754                END LOOP;
3755 
3756                l_or_count := 1;
3757             END IF;
3758          END IF;
3759       END LOOP;
3760    END IF;
3761 
3762    -- -------------------------------------------------------------------
3763    -- Debugging code
3764    -- -------------------------------------------------------------------
3765 
3766    IF (g_rule_engine_trace_flag = 'Y') OR FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_DEBUG_LOW) THEN
3767       l_count    := g_opp_selection_tab.COUNT;
3768 
3769       FOR i IN 1..l_count LOOP
3770          Debug('===== ' || i || ' ===========================================');
3771          Debug(g_opp_selection_tab(i).rank || '::' ||
3772                g_opp_selection_tab(i).process_rule_id || '::' ||
3773                g_opp_selection_tab(i).attribute_id || '::' ||
3774                g_opp_selection_tab(i).currency_code || '::' ||
3775                g_opp_selection_tab(i).operator || '::' ||
3776                g_opp_selection_tab(i).selection_criteria_id || '::' ||
3777                g_opp_selection_tab(i).attribute_value || '::' ||
3778                g_opp_selection_tab(i).attribute_to_value || '::' ||
3779                g_opp_selection_tab(i).last_attr_flag || '::' ||
3780                g_opp_selection_tab(i).count
3781          );
3782       END LOOP;
3783    END IF;
3784 
3785 END Cache_Rules;
3786 -- =============================End of Cache_Rules==============================
3787 
3788 END PV_MATCH_V3_PUB;