1 package body BOM_DIAGUNITTEST_BILLHLCHK as
2 /* $Header: BOMDGBIB.pls 120.1 2007/12/26 09:41:58 vggarg noship $ */
3 PROCEDURE init is
4 BEGIN
5 null;
6 END init;
7
8 PROCEDURE cleanup IS
9 BEGIN
10 -- test writer could insert special cleanup code here
11 NULL;
12 END cleanup;
13
14 PROCEDURE runtest(inputs IN JTF_DIAG_INPUTTBL,
15 report OUT NOCOPY JTF_DIAG_REPORT,
16 reportClob OUT NOCOPY CLOB) IS
17 reportStr LONG; -- REPORT
18 sqltxt VARCHAR2(9999); -- SQL select statement
19 c_username VARCHAR2(50); -- accept input for username
20 statusStr VARCHAR2(50); -- SUCCESS or FAILURE
21 errStr VARCHAR2(4000); -- error message
22 fixInfo VARCHAR2(4000); -- fix tip
23 isFatal VARCHAR2(50); -- TRUE or FALSE
24 num_rows NUMBER;
25 row_limit NUMBER;
26 l_item_id NUMBER;
27 l_org_id NUMBER;
28 l_org_exists NUMBER;
29 l_script VARCHAR2(20);
30
31 BEGIN
32 JTF_DIAGNOSTIC_ADAPTUTIL.setUpVars;
33 JTF_DIAGNOSTIC_ADAPTUTIL.addStringToReport('@html');
34 JTF_DIAGNOSTIC_COREAPI.insert_style_sheet;
35
36 /* Set Row Limit to 1000 (i.e.) Max Number of records to be fetched by each sql*/
37 row_limit :=1000;
38 l_org_exists :=0; /* Initialize to zero */
39
40 -- accept input
41 l_org_id := JTF_DIAGNOSTIC_ADAPTUTIL.getInputValue('OrgId',inputs);
42 l_script := nvl(upper(JTF_DIAGNOSTIC_ADAPTUTIL.getInputValue('Script',inputs)),'ALL');
43
44 /*JTF_DIAGNOSTIC_ADAPTUTIL.addStringToReport('OrgID input :'||l_org_id||' Script: '||l_script);
45 JTF_DIAGNOSTIC_COREAPI.BRPrint;
46 */
47
48 -- JTF_DIAGNOSTIC_COREAPI.Line_Out('script: '||l_script);
49
50 /* l_script is NOT a mandatory input. If it is not entered, then run all the scripts.
51 However if a script name is entered, then validate it for existence. */
52
53 If l_script not in ('UNIT_EFF','IMPLDT_NULL','ALL') Then
54 JTF_DIAGNOSTIC_COREAPI.errorprint('Invalid Script Name');
55 JTF_DIAGNOSTIC_COREAPI.ActionErrorPrint('Please choose a Script Name from the Lov or leave the field blank.');
56 statusStr := 'FAILURE';
57 isFatal := 'TRUE';
58 fixInfo := ' Please review the error message below and take corrective action.';
59 errStr := ' Invalid value for input field Script ';
60
61 report := JTF_DIAGNOSTIC_ADAPTUTIL.constructReport(statusStr,errStr,fixInfo,isFatal);
62 reportClob := JTF_DIAGNOSTIC_ADAPTUTIL.getReportClob;
63 Return;
64 End If;
65 /* End of script name validation*/
66
67
68 /* l_org_id is NOT a mandatory input. If it is not entered, then run the scripts for all orgs.
69 However if a value is entered for org_id, then validate it for existence. */
70
71 If l_org_id is not null Then /* validate if input org_id exists*/
72 Begin
73 select 1 into l_org_exists
74 from mtl_parameters
75 where organization_id=l_org_id;
76 Exception
77 When others Then
78 l_org_exists :=0;
79 JTF_DIAGNOSTIC_COREAPI.errorprint('Invalid Organization Id');
80 JTF_DIAGNOSTIC_COREAPI.ActionErrorPrint(' Please either provide a valid value for the Organization Id or leave it blank.');
81 statusStr := 'FAILURE';
82 isFatal := 'TRUE';
83 fixInfo := ' Please review the error message below and take corrective action.';
84 errStr := ' Invalid value for input field Organization Id ';
85
86 report := JTF_DIAGNOSTIC_ADAPTUTIL.constructReport(statusStr,errStr,fixInfo,isFatal);
87 reportClob := JTF_DIAGNOSTIC_ADAPTUTIL.getReportClob;
88 End;
89 End If; /* End of l_org_id is not null */
90
91 If (l_org_id is null) or (l_org_exists = 1) Then
92
93 /* Script 1 to identify invalid/missing Unit effective component records
94 Records of the below three types are fetched.
95 (a) Missing from_end_item_unit_number (it is a mandatory column)
96 (b) Invalid from_end_item_unit_number
97 (c) Invalid To_end_item_unit_number
98 Note: Unit numbers are termed invalid if they do not exist in pjm_unit_numbers table.
99 To_end_item_unit_number is not a mandatory column and hence can be null.
100
101 Logic of the Query below:
102 Query 1 (fetches records with missing/invalid from_end_item_unit_number AND invalid to_end_item_unit_number)
103 Union
104 Query 2 (fetches records with missing/invalid from_end_item_unit_number AND Valid to_end_item_unit_number)
105 Union
106 Query 3 (fetches records with Valid from_end_item_unit_number AND invalid to_end_item_unit_number)
107
108 output rows are limited to row_limt/3 since the accumulated output
109 of all the three queries should atmost be row_limit.
110
111 */
112
113 If l_script in ('ALL','UNIT_EFF') Then
114 sqltxt := ' select mif1.padded_item_number "Assembly Item Number", '||
115 ' mp.organization_code "Organization Code", '||
116 ' bsb.alternate_bom_designator "Alternate Bom Designator", '||
117 ' bcb.operation_seq_num "Operation Seq Num", '||
118 ' bcb.item_num "Item Seq Num", '||
119 ' mif2.padded_item_number "Component Item", '||
120 ' decode(bcb.from_end_item_unit_number,null,''*MISSING'', '||
121 ' bcb.from_end_item_unit_number||'' (Invalid)'') "From End Item Unit Number", '||
122 ' bcb.to_end_item_unit_number||'' (Invalid)'' "To End Item Unit Number", '||
123 ' bcb.component_quantity "Component Quantity", '||
124 ' to_char(bcb.effectivity_date,''DD-MON-YYYY HH24:MI:SS'') "Effectivity Date", '||
125 ' to_char(bcb.disable_date,''DD-MON-YYYY HH24:MI:SS'') "Disable Date", '||
126 ' bcb.change_notice "Change Notice", '||
127 ' bsb.assembly_item_id "Assembly Item Id", '||
128 ' bsb.organization_id "Organization Id", '||
129 ' bsb.bill_sequence_id "Bill Sequence Id", '||
130 ' bcb.component_sequence_id "Component Sequence Id" '||
131 ' from bom_components_b bcb, bom_structures_b bsb, '||
132 ' mtl_item_flexfields mif1, mtl_item_flexfields mif2, '||
133 ' mtl_parameters mp '||
134 ' where bsb.bill_sequence_id = bcb.bill_sequence_id '||
135 ' and bsb.assembly_item_id = mif1.inventory_item_id '||
136 ' and bsb.organization_id = mif1.organization_id '||
137 ' and bcb.component_item_id = mif2.inventory_item_id '||
138 ' and bsb.organization_id = mif2.organization_id '||
139 ' and mif1.organization_id = mp.organization_id '||
140 ' and mif1.effectivity_control = 2 '||
141 ' and ( ( bcb.from_end_item_unit_number is null '||
142 ' or '||
143 ' ( bcb.from_end_item_unit_number is not null '||
144 ' and not exists '||
145 ' (select 1 from pjm_unit_numbers '||
146 ' where unit_number = bcb.from_end_item_unit_number) '||
147 ' ) '||
148 ' ) '||
149 ' and ( bcb.to_end_item_unit_number is not null '||
150 ' and not exists '||
151 ' (select 1 from pjm_unit_numbers '||
152 ' where unit_number = bcb.to_end_item_unit_number) '||
153 ' ) '||
154 ' ) ';
155
156 if l_org_id is not null then
157 sqltxt :=sqltxt||' and bsb.organization_id = '||l_org_id;
158 end if;
159 sqltxt :=sqltxt||' and rownum< '||round(row_limit/3);
160
161 sqltxt :=sqltxt||' UNION '||
162 ' select mif1.padded_item_number "Assembly Item Number", '||
163 ' mp.organization_code "Organization Code", '||
164 ' bsb.alternate_bom_designator "Alternate Bom Designator", '||
165 ' bcb.operation_seq_num "Operation Seq Num", '||
166 ' bcb.item_num "Item Seq Num", '||
167 ' mif2.padded_item_number "Component Item", '||
168 ' decode(bcb.from_end_item_unit_number,null,''*MISSING'', '||
169 ' bcb.from_end_item_unit_number||'' (Invalid)'') "From End Item Unit Number", '||
170 ' bcb.to_end_item_unit_number "To End Item Unit Number", '||
171 ' bcb.component_quantity "Component Quantity", '||
172 ' to_char(bcb.effectivity_date,''DD-MON-YYYY HH24:MI:SS'') "Effectivity Date", '||
173 ' to_char(bcb.disable_date,''DD-MON-YYYY HH24:MI:SS'') "Disable Date", '||
174 ' bcb.change_notice "Change Notice", '||
175 ' bsb.assembly_item_id "Assembly Item Id", '||
176 ' bsb.organization_id "Organization Id", '||
177 ' bsb.bill_sequence_id "Bill Sequence Id", '||
178 ' bcb.component_sequence_id "Component Sequence Id" '||
179 ' from bom_components_b bcb, bom_structures_b bsb, '||
180 ' mtl_item_flexfields mif1, mtl_item_flexfields mif2, '||
181 ' mtl_parameters mp '||
182 ' where bsb.bill_sequence_id = bcb.bill_sequence_id '||
183 ' and bsb.assembly_item_id = mif1.inventory_item_id '||
184 ' and bsb.organization_id = mif1.organization_id '||
185 ' and bcb.component_item_id = mif2.inventory_item_id '||
186 ' and bsb.organization_id = mif2.organization_id '||
187 ' and mif1.organization_id = mp.organization_id '||
188 ' and mif1.effectivity_control = 2 '||
189 ' and ( ( bcb.from_end_item_unit_number is null '||
190 ' or ( bcb.from_end_item_unit_number is not null '||
191 ' and not exists '||
192 ' (select 1 from pjm_unit_numbers '||
193 ' where unit_number = bcb.from_end_item_unit_number) '||
194 ' ) '||
195 ' ) '||
196 ' and ( bcb.to_end_item_unit_number is null '||
197 ' or '||
198 ' ( bcb.to_end_item_unit_number is not null '||
199 ' and exists '||
200 ' (select 1 from pjm_unit_numbers '||
201 ' where unit_number = bcb.to_end_item_unit_number) '||
202 ' ) '||
203 ' ) '||
204 ' ) ';
205
206 if l_org_id is not null then
207 sqltxt :=sqltxt||' and bsb.organization_id = '||l_org_id;
208 end if;
209 sqltxt :=sqltxt||' and rownum< '||round(row_limit/3);
210
211 sqltxt :=sqltxt||' UNION '||
212 ' select mif1.padded_item_number "Assembly Item Number", '||
213 ' mp.organization_code "Organization Code", '||
214 ' bsb.alternate_bom_designator "Alternate Bom Designator", '||
215 ' bcb.operation_seq_num "Operation Seq Num", '||
216 ' bcb.item_num "Item Seq Num", '||
217 ' mif2.padded_item_number "Component Item", '||
218 ' bcb.from_end_item_unit_number "From End Item Unit Number", '||
219 ' bcb.to_end_item_unit_number||'' (Invalid)'' "To End Item Unit Number", '||
220 ' bcb.component_quantity "Component Quantity", '||
221 ' to_char(bcb.effectivity_date,''DD-MON-YYYY HH24:MI:SS'')"Effectivity Date", '||
222 ' to_char(bcb.disable_date,''DD-MON-YYYY HH24:MI:SS'') "Disable Date", '||
223 ' bcb.change_notice "Change Notice", '||
224 ' bsb.assembly_item_id "Assembly Item Id", '||
225 ' bsb.organization_id "Organization Id", '||
226 ' bsb.bill_sequence_id "Bill Sequence Id", '||
227 ' bcb.component_sequence_id "Component Sequence Id" '||
228 ' from bom_components_b bcb, bom_structures_b bsb, '||
229 ' mtl_item_flexfields mif1, mtl_item_flexfields mif2, '||
230 ' mtl_parameters mp '||
231 ' where bsb.bill_sequence_id = bcb.bill_sequence_id '||
232 ' and bsb.assembly_item_id = mif1.inventory_item_id '||
233 ' and bsb.organization_id = mif1.organization_id '||
234 ' and bcb.component_item_id = mif2.inventory_item_id '||
235 ' and bsb.organization_id = mif2.organization_id '||
236 ' and mif1.organization_id = mp.organization_id '||
237 ' and mif1.effectivity_control = 2 '||
238 ' and ( ( bcb.to_end_item_unit_number is not null '||
239 ' and not exists '||
240 ' (select 1 from pjm_unit_numbers '||
241 ' where unit_number = bcb.to_end_item_unit_number) '||
242 ' ) '||
243 ' and ( bcb.from_end_item_unit_number is not null '||
244 ' and exists '||
245 ' (select 1 from pjm_unit_numbers '||
246 ' where unit_number = bcb.from_end_item_unit_number) '||
247 ' ) '||
248 ' ) ';
249
250 if l_org_id is not null then
251 sqltxt :=sqltxt||' and bsb.organization_id = '||l_org_id;
252 end if;
253
254 sqltxt :=sqltxt||' and rownum< '||round(row_limit/3);
255
256 num_rows:= JTF_DIAGNOSTIC_COREAPI.display_sql(sqltxt, ' Unit Effective Components with invalid ''From End Item Unit Number'' or ''To End Item Unit Number'' ');
257
258 If (num_rows = 0) Then /* Corrupt Data Not Found for this case*/
259 JTF_DIAGNOSTIC_COREAPI.Line_Out('No corrupt data found for this case. <BR/><BR/>');
260 ElsIf (num_rows > 0) Then /* Show Impact and Action only if rows are returned */
261 If (num_rows = row_limit -1 ) Then
262 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/> Output of the above table is limited to the first '||(row_limit-1)||' rows
263 <BR/> to prevent an excessively big output file. <BR/>');
264 End If;
265 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/>Records of the below three types are fetched.
266 <BR/> (a) Missing from_end_item_unit_number (it is a mandatory column).
267 <BR/> Indicated by word '' *MISSING''.
268 <BR/> (b) Invalid from_end_item_unit_number. Indicated by word ''Invalid''.
269 <BR/> (c) Invalid To_end_item_unit_number. Indicated by word ''Invalid''.
270 <BR/> Note: Unit numbers are termed invalid if they do not exist
271 <BR/> in pjm_unit_numbers table.
272 <BR/> To_end_item_unit_number is not a mandatory column
273 <BR/> and hence can be null. ');
274
275 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/><BR/><u>IMPACT:</u>
276 <BR/>Component records get created with corrupt data which
277 <BR/>generate error messages while querying the Bills.<BR/><BR/> ');
278
279 JTF_DIAGNOSTIC_COREAPI.ActionErrorLink('<BR/> For fixing the rootcause of this data corruption,
280 <BR/> please apply appropriate patches suggested in metalink note : ' , '393085.1', '' );
281
282 reportStr := '<BR/> If Rows are returned with missing/invalid ''From End Item Unit Number''
283 <BR/> or ''To End Item Unit Number'' ,
284 <BR/> then please follow the below steps for correcting them.
285 <BR/> 1) Open (N) Bills of Material > Bills form.
286 <BR/> 2) Query for the Assembly Items fetched above.
287 <BR/> 3) Query for the particular Component record as identified by
288 <BR/> ''Operation Seq Num'', ''Item Num'', ''Component Item'' etc.
289 <BR/> 4) Go to ''Unit Effectivity'' tab in Components block.
290 <BR/> 4) Go to the ''From'' field or the ''To'' field that has to be corrected.
291 <BR/> 5) Correct these values by choosing an appropriate unit number
292 <BR/> from the associated Lov.
293 <BR/> 6) Save the changes to the bill.
294 <BR/> <u>Note</u>: If the number of invalid unit numbers are huge,
295 <BR/> then use the Bills Open Interface functionality to correct them.
296 <BR/>';
297 JTF_DIAGNOSTIC_ADAPTUTIL.addStringToReport(reportClob,reportStr);
298 End If; /* End of Impact and Action */
299
300 statusStr := 'SUCCESS';
301 isFatal := 'FALSE';
302
303 JTF_DIAGNOSTIC_COREAPI.BRPrint;
304 End If; /* End of l_script */
305 /* End of script identify components with invalid Unit numbers*/
306
307 /* Script 2 - Fetch bills with Null Implementation Date */
311 ' bsb.alternate_bom_designator "Alternate Designator", '||
308 If l_script in ('ALL','IMPLDT_NULL') Then
309 sqltxt:= ' select mif.padded_item_number "Assembly Item", '||
310 ' mp.organization_code "Organization Code", '||
312 ' decode(bsb.assembly_type,1,''Manufacturing Bill'',2,''Engineering Bill'') "Assembly Type",'||
313 ' to_char(bsb.implementation_date,''DD-MON-YYYY HH24:MI:SS'') "Implementation Date", '||
314 ' bsb.pending_from_ecn "Pending From ECN", '||
315 ' bsb.assembly_item_id "Assembly Item Id" , '||
316 ' bsb.organization_id "Organization Id", '||
317 ' bsb.bill_sequence_id "Bill Sequence Id", '||
318 ' bsb.common_bill_sequence_id "Common Bill Sequence Id" '||
319 ' from bom_structures_b bsb, mtl_item_flexfields mif, mtl_parameters mp '||
320 ' where mif.inventory_item_id = bsb.assembly_item_id '||
321 ' and mif.organization_id = bsb.organization_id '||
322 ' and bsb.organization_id = mp.organization_id '||
323 ' and bsb.implementation_date is null ';
324
325 if l_org_id is not null then
326 sqltxt :=sqltxt||' and bsb.organization_id = '||l_org_id;
327 end if;
328
329 sqltxt :=sqltxt||' and rownum< '||row_limit;
330 /* sqltxt := sqltxt || ' and rownum< 5'; -- temporarily limiting the records to 5 */
331 sqltxt :=sqltxt||' order by mp.organization_code, mif.padded_item_number,bsb.alternate_bom_designator';
332
333 num_rows:= JTF_DIAGNOSTIC_COREAPI.display_sql(sqltxt, ' Bills with Null Implementation Date ');
334
335 If (num_rows = 0) Then /* Corrupt Data Not Found for this case*/
336 JTF_DIAGNOSTIC_COREAPI.Line_Out('No corrupt data found for this case. <BR/><BR/>');
337 ElsIf (num_rows > 0) Then /* Show Impact and Action only if rows are returned */
338 If (num_rows = row_limit -1 ) Then
339 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/> Output of the above table is limited to the first '||(row_limit-1)||' rows
340 <BR/> to prevent an excessively big output file. <BR/>');
341 End If;
342
343 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/><u>IMPACT:</u>
344 <BR/> Components added to these bills will appear
345 <BR/> to be unimplemented when querying the bill.');
346
347 reportStr := '<BR/><BR/><u>ACTION</u>:
348 <BR/> If bills are returned with Null Implementation Date,
349 <BR/>then please follow the below steps for correcting them.
350 <BR/><I><u>Important:</u> Try this action plan on a TEST INSTANCE first.</I>
351 <BR/>(1) Take a backup of entire bom_structures_b table.
352 <BR/>(2) Use the below update statement to correct these bills.
353 <pre> update bom_structures_b
354 set implementation_date = creation_date
355 where implementation_date is null;
356 </pre>
357 (3) Make sure that the total number of records updated
358 <BR/>are same as the number of records fetched above.
359 <BR/>(4) Commit the transaction.
360 <BR/>';
361 JTF_DIAGNOSTIC_ADAPTUTIL.addStringToReport(reportClob,reportStr);
362
363 End If; /* End of Impact and Action */
364
365 statusStr := 'SUCCESS';
366 isFatal := 'FALSE';
367
368 JTF_DIAGNOSTIC_COREAPI.BRPrint;
369 End If; /* End of l_script */
370 /* End of script 2- Bills with NULL Implementation Date */
371
372 <<l_test_end>>
373 JTF_DIAGNOSTIC_COREAPI.Line_Out('<BR/><BR/>This Health Check test completed as expected <BR/>');
374 report := JTF_DIAGNOSTIC_ADAPTUTIL.constructReport(statusStr,errStr,fixInfo,isFatal);
375 reportClob := JTF_DIAGNOSTIC_ADAPTUTIL.getReportClob;
376 End If; /* End of l_org_id is null or l_org_exists=1 */
377
378 EXCEPTION
379 when others then
380 JTF_DIAGNOSTIC_COREAPI.errorprint('Error: '||sqlerrm);
381 JTF_DIAGNOSTIC_COREAPI.ActionErrorPrint('If this error repeats, please contact Oracle Support Services');
382 statusStr := 'FAILURE';
383 errStr := sqlerrm ||' occurred in script. ';
384 fixInfo := 'Unexpected Exception in BOMDGBIB.pls';
385 isFatal := 'FALSE';
386 report := JTF_DIAGNOSTIC_ADAPTUTIL.constructReport(statusStr,errStr,fixInfo,isFatal);
387 reportClob := JTF_DIAGNOSTIC_ADAPTUTIL.getReportClob;
388 END runTest;
389
390 PROCEDURE getComponentName(name OUT NOCOPY VARCHAR2) IS
391 BEGIN
392 name := 'Bills Data Health Check Details';
393 END getComponentName;
394
395 PROCEDURE getTestDesc(descStr OUT NOCOPY VARCHAR2) IS
396 BEGIN
397 descStr := ' This diagnostic test performs a variety of health checks against Bills <BR/>
398 and provides suggestions on how to solve possible issues.<BR/>
399 It is recommended to run this health check periodically. ';
400 END getTestDesc;
401
402 PROCEDURE getTestName(name OUT NOCOPY VARCHAR2) IS
403 BEGIN
404 name := 'Bills Data Health Check';
405 END getTestName;
406
407 PROCEDURE getDependencies (package_names OUT NOCOPY JTF_DIAG_DEPENDTBL) IS
408 tempDependencies JTF_DIAG_DEPENDTBL;
409
410 BEGIN
411 package_names := JTF_DIAGNOSTIC_ADAPTUTIL.initDependencyTable;
412 END getDependencies;
413
414 PROCEDURE isDependencyPipelined (str OUT NOCOPY VARCHAR2) IS
415 BEGIN
416 str := 'FALSE';
417 END isDependencyPipelined;
418
419
420 PROCEDURE getOutputValues(outputValues OUT NOCOPY JTF_DIAG_OUTPUTTBL) IS
421 tempOutput JTF_DIAG_OUTPUTTBL;
422 BEGIN
423 tempOutput := JTF_DIAGNOSTIC_ADAPTUTIL.initOutputTable;
424 outputValues := tempOutput;
425 EXCEPTION
426 when others then
427 outputValues := JTF_DIAGNOSTIC_ADAPTUTIL.initOutputTable;
428 END getOutputValues;
429
430
431 PROCEDURE getDefaultTestParams(defaultInputValues OUT NOCOPY JTF_DIAG_INPUTTBL) IS
432 tempInput JTF_DIAG_INPUTTBL;
433 BEGIN
434 tempInput := JTF_DIAGNOSTIC_ADAPTUTIL.initinputtable;
435 tempInput := JTF_DIAGNOSTIC_ADAPTUTIL.addInput(tempInput,'OrgId','LOV-oracle.apps.bom.diag.lov.OrganizationLov');-- Lov name modified to OrgId for bug 6412260
436 tempInput := JTF_DIAGNOSTIC_ADAPTUTIL.addInput(tempInput,'Script','LOV-oracle.apps.bom.diag.lov.BomHealthLov');
437 defaultInputValues := tempInput;
438 EXCEPTION
439 when others then
440 defaultInputValues := JTF_DIAGNOSTIC_ADAPTUTIL.initinputtable;
441 END getDefaultTestParams;
442
443 Function getTestMode return INTEGER IS
444 BEGIN
445 return JTF_DIAGNOSTIC_ADAPTUTIL.ADVANCED_MODE;
446
447 END getTestMode;
448
449 END BOM_DIAGUNITTEST_BILLHLCHK;