Repository navigation
Expand file tree
/
Copy pathvalio_source_code.abap
More file actions
2852 lines (2192 loc) · 109 KB
/
Copy pathvalio_source_code.abap
File metadata and controls
2852 lines (2192 loc) · 109 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
*&---------------------------------------------------------------------*
*& Report Z_VALIO_CODE_REVIEW
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT z_valio_code_review LINE-SIZE 132.
CONSTANTS:
gc_object_def_type_class TYPE string VALUE 'CLASS',
gc_object_def_type_report TYPE string VALUE 'REPORT',
gc_object_def_type_fm TYPE string VALUE 'FM'.
TYPES:
BEGIN OF ts_suggestion,
object_type TYPE string,
object_name TYPE string,
source_code_section_name TYPE string,
suggestion TYPE string,
priority TYPE string,
user TYPE string,
END OF ts_suggestion,
BEGIN OF ts_object_definition,
object_name TYPE string,
object_type TYPE string,
END OF ts_object_definition,
tt_suggestion TYPE STANDARD TABLE OF ts_suggestion WITH DEFAULT KEY,
tt_object_definition TYPE STANDARD TABLE OF ts_object_definition WITH DEFAULT KEY,
tt_class_name TYPE STANDARD TABLE OF seoclsname WITH DEFAULT KEY,
tt_prog_name TYPE STANDARD TABLE OF progname WITH DEFAULT KEY,
tt_fm_name TYPE STANDARD TABLE OF rs38l_fnam WITH DEFAULT KEY,
BEGIN OF ts_object_source,
object_name TYPE string,
local_section_name TYPE string,
source_code TYPE string,
END OF ts_object_source,
BEGIN OF ts_object_sections_source,
object_name TYPE string,
sections TYPE string_table,
END OF ts_object_sections_source,
BEGIN OF ts_contact,
object TYPE seoclsname,
component TYPE seocmpname,
contact TYPE sy-uname,
END OF ts_contact,
tt_contact TYPE STANDARD TABLE OF ts_contact WITH DEFAULT KEY,
tt_object_source TYPE STANDARD TABLE OF ts_object_source WITH DEFAULT KEY,
tt_object_sections_source TYPE STANDARD TABLE OF ts_object_sections_source WITH DEFAULT KEY.
CLASS lcx_utility_base DEFINITION INHERITING FROM cx_static_check ABSTRACT.
PUBLIC SECTION.
METHODS:
constructor IMPORTING !iv_error_text TYPE string
!io_previous TYPE REF TO cx_root OPTIONAL
!iv_subrc TYPE syst_subrc OPTIONAL,
get_text REDEFINITION.
PRIVATE SECTION.
DATA:
mv_error_text TYPE string,
mv_subrc TYPE syst_subrc.
ENDCLASS.
CLASS lcx_utility_base IMPLEMENTATION.
METHOD constructor.
super->constructor( previous = io_previous ).
mv_error_text = iv_error_text.
mv_subrc = iv_subrc.
ENDMETHOD.
METHOD get_text.
result = mv_error_text.
IF mv_subrc IS NOT INITIAL.
result = |{ result }:SUBRC { mv_subrc }|.
ENDIF.
IF previous IS BOUND.
result = |{ result }:( { previous->get_text( ) } )|.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS lcx_ai_helper_error DEFINITION INHERITING FROM lcx_utility_base FINAL.
ENDCLASS.
CLASS lcx_object_extractor_error DEFINITION INHERITING FROM lcx_utility_base FINAL.
ENDCLASS.
CLASS lcx_suggestions_exporter_error DEFINITION INHERITING FROM lcx_utility_base FINAL.
ENDCLASS.
CLASS lcx_source_code_getter_error DEFINITION INHERITING FROM lcx_utility_base FINAL.
ENDCLASS.
CLASS lcx_code_reviewer_error DEFINITION INHERITING FROM lcx_utility_base FINAL.
ENDCLASS.
CLASS lcl_logger DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS:
warn IMPORTING !iv_message TYPE string.
ENDCLASS.
CLASS lcl_logger IMPLEMENTATION.
METHOD warn.
IF sy-batch = abap_true.
MESSAGE iv_message TYPE 'S' DISPLAY LIKE 'W'.
ENDIF.
ENDMETHOD.
ENDCLASS.
CLASS lcl_ai_helper DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS:
get_master_prompt RETURNING VALUE(rv_master_prompt) TYPE stringval,
get_default_prompt RETURNING VALUE(rv_default_prompt) TYPE stringval,
get_final_prompt IMPORTING iv_user_prompt TYPE stringval
RETURNING VALUE(rv_target_prompt) TYPE stringval,
deserialize_suggestions IMPORTING !iv_object_type TYPE string
!iv_object_name TYPE string
!iv_json TYPE string
!iv_user TYPE string
RETURNING VALUE(rt_suggestion) TYPE tt_suggestion
RAISING lcx_ai_helper_error,
execute_prompt IMPORTING !iv_prompt TYPE string
RETURNING VALUE(rv_response) TYPE string
RAISING lcx_ai_helper_error.
PRIVATE SECTION.
CONSTANTS:
gc_prompt_begin_of_input TYPE string VALUE 'Input for the review:',
gc_msg_inaccessible_llm TYPE string VALUE 'LLM Agent cannot be accessed',
gc_msg_agent_not_provided TYPE string VALUE 'LLM agent is not provided',
gc_msg_corrupted_json TYPE string VALUE 'Corrupted JSON',
gc_msg_no_object_name TYPE string VALUE 'No object name was provided',
gc_msg_no_json_string TYPE string VALUE 'No JSON string was provided',
gc_msg_unnormalizable_string TYPE string VALUE 'String cannot be normalized',
gc_fallback_object_type TYPE string VALUE 'OBJ',
gc_fallback_user_name TYPE string VALUE 'UNKNOWN'.
CLASS-METHODS:
normalize_format IMPORTING !iv_string TYPE string
RETURNING VALUE(rv_normalized_string) TYPE string
RAISING lcx_ai_helper_error.
ENDCLASS.
CLASS lcl_ai_helper IMPLEMENTATION.
METHOD execute_prompt.
**********************************************************************
* Here you should provide a call to LLM.
**********************************************************************
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_agent_not_provided.
**********************************************************************
* Here you should provide a call to LLM.
**********************************************************************
ENDMETHOD.
METHOD get_master_prompt.
rv_master_prompt = |Goal: Perform a detailed code review of an ABAP class and return structured findings.|
&& |{ cl_abap_char_utilities=>newline }Context: You are an expert ABAP developer with deep knowledge of SAP best practices, performance optimization, maintainability.|
&& |{ cl_abap_char_utilities=>newline }Output Format:|
&& |{ cl_abap_char_utilities=>newline } - Return ONLY a valid JSON array.|
&& |{ cl_abap_char_utilities=>newline } - Each element must follow this structure:|
&& |{ cl_abap_char_utilities=>newline } \{|
&& |{ cl_abap_char_utilities=>newline } "source_code_section_name": "<source_code_section_name_or_global_if_not_applicable>",|
&& |{ cl_abap_char_utilities=>newline } "suggestion": "<short, precise recommendation>",|
&& |{ cl_abap_char_utilities=>newline } "priority": "<HIGH\|MEDIUM\|LOW>"|
&& |{ cl_abap_char_utilities=>newline } \}|
&& |{ cl_abap_char_utilities=>newline } - JSON must always start with [ symbol and end with ] symbol|
&& |{ cl_abap_char_utilities=>newline } - Ensure the JSON is valid and properly formatted.|
&& |{ cl_abap_char_utilities=>newline } - If no issues are found, return an empty JSON array: [].|
&& |{ cl_abap_char_utilities=>newline } - Do not explain suggestions outside the JSON.|
&& |{ cl_abap_char_utilities=>newline } - Avoid duplicate or overlapping suggestions.|
&& |{ cl_abap_char_utilities=>newline } - Points max length 50 words.|
&& |{ cl_abap_char_utilities=>newline }Instructions:|.
ENDMETHOD.
METHOD get_default_prompt.
" Default prompt
rv_default_prompt = | - Analyze the provided ABAP class code thoroughly.|
&& |{ cl_abap_char_utilities=>newline } - Identify concrete issues, bugs, risks, and improvements.|
&& |{ cl_abap_char_utilities=>newline } - Do not stop at surface-level issues;|
&& |{ cl_abap_char_utilities=>newline } analyze underlying risks and edge cases.|
&& |{ cl_abap_char_utilities=>newline } - The output should not be huge|
&& |{ cl_abap_char_utilities=>newline } - Focus on:|
&& |{ cl_abap_char_utilities=>newline } - Syntax and logical errors|
&& |{ cl_abap_char_utilities=>newline } - Performance issues like needless database access, inefficient loops|
&& |{ cl_abap_char_utilities=>newline } - Clean code violations (readability, naming, modularization)|
&& |{ cl_abap_char_utilities=>newline } - SAP best practices and conventions|
&& |{ cl_abap_char_utilities=>newline } - Generate as many potential issues as possible,|
&& |{ cl_abap_char_utilities=>newline } but avoid trivial or redundant points.|
&& |{ cl_abap_char_utilities=>newline } - Each point must be concise, actionable, and specific.|
&& |{ cl_abap_char_utilities=>newline } - Do not include any text outside the JSON output.|
&& |{ cl_abap_char_utilities=>newline } - Use "GLOBAL" as source_code_section_name |
&& |{ cl_abap_char_utilities=>newline } if the issue is not tied to a specific method.|
&& |{ cl_abap_char_utilities=>newline } - For GLOBAL be ultra precise|
&& |{ cl_abap_char_utilities=>newline } - Do not use complex words for explanations|
&& |{ cl_abap_char_utilities=>newline } - Be precise and specific. Point exactly to the weak places|
&& |{ cl_abap_char_utilities=>newline } - Generic points are prohibited|
&& |{ cl_abap_char_utilities=>newline } - You must add clear examples to the output|.
ENDMETHOD.
METHOD get_final_prompt.
DATA(lv_master_prompt) = lcl_ai_helper=>get_master_prompt( ).
rv_target_prompt = COND #( WHEN iv_user_prompt IS NOT INITIAL
THEN |{ lv_master_prompt }{ iv_user_prompt }{ cl_abap_char_utilities=>newline }{ gc_prompt_begin_of_input }{ cl_abap_char_utilities=>newline } |
ELSE |{ lv_master_prompt }{ cl_abap_char_utilities=>newline }{ gc_prompt_begin_of_input }{ cl_abap_char_utilities=>newline } | ).
ENDMETHOD.
METHOD deserialize_suggestions.
IF iv_object_name IS INITIAL.
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_no_object_name.
ENDIF.
IF iv_json IS INITIAL.
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_no_json_string.
ENDIF.
DATA(lv_json) = normalize_format( iv_json ).
IF /ui5/cl_json_util=>is_wellformed( lv_json ) = abap_false.
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_corrupted_json.
ENDIF.
/ui2/cl_json=>deserialize( EXPORTING json = lv_json
CHANGING data = rt_suggestion ).
IF rt_suggestion IS INITIAL.
RETURN.
ENDIF.
DATA(lv_object_type) = COND #( WHEN iv_object_type IS NOT INITIAL THEN iv_object_type ELSE gc_fallback_object_type ).
DATA(lv_user) = COND #( WHEN iv_user IS NOT INITIAL THEN iv_user ELSE gc_fallback_user_name ).
LOOP AT rt_suggestion ASSIGNING FIELD-SYMBOL(<ls_suggestion>).
<ls_suggestion>-object_type = lv_object_type.
<ls_suggestion>-object_name = to_upper( iv_object_name ).
<ls_suggestion>-source_code_section_name = to_upper( <ls_suggestion>-source_code_section_name ).
<ls_suggestion>-user = lv_user.
ENDLOOP.
ENDMETHOD.
METHOD normalize_format.
CONSTANTS:
lc_occurrence_last TYPE i VALUE -1,
lc_inclusive_length_adjustment TYPE i VALUE 1,
lc_json_array_begin VALUE '[',
lc_json_array_end VALUE ']'.
IF iv_string IS INITIAL.
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_unnormalizable_string.
ENDIF.
DATA(lv_truncate_from) = find_any_of( val = iv_string sub = lc_json_array_begin ).
DATA(lv_truncate_to) = find_any_of( val = iv_string sub = lc_json_array_end occ = lc_occurrence_last ).
IF lv_truncate_from < 0
OR lv_truncate_to < 0
OR lv_truncate_to - lv_truncate_from < 0.
RAISE EXCEPTION TYPE lcx_ai_helper_error
EXPORTING
iv_error_text = gc_msg_unnormalizable_string.
ENDIF.
rv_normalized_string = substring( val = iv_string
off = lv_truncate_from
len = lv_truncate_to - lv_truncate_from + lc_inclusive_length_adjustment ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_object_extractor DEFINITION FINAL.
PUBLIC SECTION.
TYPES:
tt_user TYPE STANDARD TABLE OF syuname WITH DEFAULT KEY.
METHODS:
get_objects_by_packages IMPORTING !it_package_name TYPE string_table
RETURNING VALUE(rt_object) TYPE tt_object_definition
RAISING lcx_object_extractor_error,
get_objects_by_names IMPORTING !it_object_name TYPE string_table
RETURNING VALUE(rt_object) TYPE tt_object_definition
RAISING lcx_object_extractor_error,
get_objects_by_tr_requests IMPORTING !iv_fl_current_objects_only TYPE abap_bool
!iv_fl_current_user_only TYPE abap_bool
!it_tr_request_header TYPE trwbo_request_headers
!it_user TYPE tt_user
RETURNING VALUE(rt_object) TYPE tt_object_definition
RAISING lcx_object_extractor_error.
PRIVATE SECTION.
CONSTANTS:
gc_request_functions_all TYPE string VALUE 'CDEFGKMOPQRSTWX',
gc_status_modifiable_released TYPE string VALUE 'DLP ',
gc_objects_type_class_include TYPE string VALUE 'CINC',
gc_objects_type_class TYPE string VALUE 'CLAS',
gc_objects_type_func TYPE string VALUE 'FUNC',
gc_objects_type_program TYPE string VALUE 'PROG',
gc_objects_type_fm TYPE string VALUE 'FUGR',
gc_function_group_prefix TYPE string VALUE 'SAPL',
gc_pgmid_complete_object TYPE pgmid VALUE 'R3TR',
gc_program_type_include TYPE string VALUE 'I',
gc_trfunction_workbench TYPE string VALUE 'K',
gc_msg_search_objects_error TYPE string VALUE 'Search objects error',
gc_msg_no_packages TYPE string VALUE 'No packages were provided',
gc_msg_no_objects TYPE string VALUE 'No objects were provided',
gc_msg_no_user_request TYPE string VALUE 'No user or request was provided',
gc_msg_tr_request_read_error TYPE string VALUE 'Cannot read transport request headers',
gc_msg_invalid_format TYPE string VALUE 'Invalid object name format'.
METHODS:
get_tr_request_headers IMPORTING !is_selection TYPE trwbo_selection OPTIONAL
!iv_username_pattern TYPE syst_uname OPTIONAL
RETURNING VALUE(rt_tr_request) TYPE trwbo_request_headers,
get_objects_by_tr_request_hdrs IMPORTING !it_tr_request_header TYPE trwbo_request_headers
!iv_fl_current_user_only TYPE abap_bool OPTIONAL
RETURNING VALUE(rt_object) TYPE tt_object_definition,
get_modules_in_function_group IMPORTING !it_function_group_name TYPE string_table
RETURNING VALUE(rt_function_module) TYPE tt_object_definition,
delete_includes IMPORTING !it_prog_name TYPE tt_prog_name
CHANGING !ct_object TYPE tt_object_definition,
adjust_objects_table IMPORTING !it_object TYPE tt_object_definition
RETURNING VALUE(rt_object) TYPE tt_object_definition.
ENDCLASS.
CLASS lcl_object_extractor IMPLEMENTATION.
METHOD get_objects_by_packages.
DATA: lt_package_name TYPE STANDARD TABLE OF devclass,
lt_search_object_type TYPE RANGE OF trobjtype.
lt_package_name = VALUE #( FOR <lv_package_name> IN it_package_name WHERE ( table_line IS NOT INITIAL )
( CONV #( <lv_package_name> ) ) ).
IF lt_package_name IS INITIAL.
RAISE EXCEPTION TYPE lcx_object_extractor_error
EXPORTING
iv_error_text = gc_msg_no_packages.
ENDIF.
lt_search_object_type = VALUE #( ( option = 'EQ' sign = 'I' low = gc_objects_type_class )
( option = 'EQ' sign = 'I' low = gc_objects_type_program )
( option = 'EQ' sign = 'I' low = gc_objects_type_fm ) ) .
SELECT obj_name,
object
FROM tadir "#EC CI_GENBUFF.
FOR ALL ENTRIES IN @lt_package_name
WHERE devclass = @lt_package_name-table_line
AND pgmid = @gc_pgmid_complete_object
AND object IN @lt_search_object_type
INTO TABLE @DATA(lt_object).
IF sy-subrc <> 0.
RETURN.
ENDIF.
RETURN adjust_objects_table( it_object = VALUE #( FOR <ls_obj> IN lt_object ( object_name = <ls_obj>-obj_name
object_type = <ls_obj>-object ) ) ).
ENDMETHOD.
METHOD get_objects_by_names.
DATA: lt_wb_request TYPE if_ris_quick_search=>ty_t_workbench_requests,
lo_ris_quick_search TYPE REF TO if_ris_quick_search,
lt_search_result TYPE cl_wb_browser_util=>tt_sewb_quicksearch_value_help,
lt_prog_name TYPE STANDARD TABLE OF progname.
DATA(lt_object_name) = VALUE string_table( FOR <ls_object_name> IN it_object_name WHERE ( table_line IS NOT INITIAL )
( <ls_object_name> ) ).
IF lt_object_name IS INITIAL.
RAISE EXCEPTION TYPE lcx_object_extractor_error
EXPORTING
iv_error_text = gc_msg_no_objects.
ENDIF.
lo_ris_quick_search = NEW cl_ris_quick_search( ).
LOOP AT lt_object_name ASSIGNING FIELD-SYMBOL(<ls_obj_name>).
CLEAR: lt_wb_request,
lt_search_result.
TRY.
lo_ris_quick_search->execute( EXPORTING i_query = <ls_obj_name>
i_object_types = VALUE #( ( CONV #( gc_objects_type_class ) )
( CONV #( gc_objects_type_class_include ) )
( CONV #( gc_objects_type_fm ) )
( CONV #( gc_objects_type_func ) )
( CONV #( gc_objects_type_program ) ) )
IMPORTING e_wb_requests = lt_wb_request ).
cl_wb_browser_util=>map_wb_requests_to_value_help( EXPORTING i_wb_requests = lt_wb_request
IMPORTING e_value_helps = lt_search_result ).
CATCH cx_ris_exception INTO DATA(lx_ris).
RAISE EXCEPTION TYPE lcx_object_extractor_error
EXPORTING
iv_error_text = |{ gc_msg_search_objects_error }: { <ls_obj_name> }|
io_previous = lx_ris.
ENDTRY.
LOOP AT lt_search_result ASSIGNING FIELD-SYMBOL(<ls_res>).
APPEND CONV #( <ls_res>-obj_name ) TO lt_prog_name.
APPEND VALUE #( object_name = <ls_res>-obj_name
object_type = SWITCH #( <ls_res>-object WHEN gc_objects_type_class OR gc_objects_type_class_include
THEN gc_object_def_type_class
WHEN gc_objects_type_fm OR gc_objects_type_func
THEN gc_object_def_type_fm
WHEN gc_objects_type_program
THEN gc_object_def_type_report ) ) TO rt_object.
ENDLOOP.
ENDLOOP.
delete_includes( EXPORTING it_prog_name = lt_prog_name
CHANGING ct_object = rt_object ).
ENDMETHOD.
METHOD get_objects_by_tr_requests.
DATA lt_tr_request TYPE trwbo_request_headers.
IF it_user IS INITIAL
AND it_tr_request_header IS INITIAL.
RAISE EXCEPTION TYPE lcx_object_extractor_error
EXPORTING
iv_error_text = gc_msg_no_user_request.
ENDIF.
IF iv_fl_current_objects_only = abap_true.
lt_tr_request = get_tr_request_headers( iv_username_pattern = sy-uname ).
ELSE.
lt_tr_request = it_tr_request_header.
LOOP AT it_user ASSIGNING FIELD-SYMBOL(<ls_user>).
APPEND LINES OF get_tr_request_headers( iv_username_pattern = <ls_user> ) TO lt_tr_request.
ENDLOOP.
ENDIF.
SORT lt_tr_request BY trkorr.
DELETE ADJACENT DUPLICATES FROM lt_tr_request COMPARING trkorr.
RETURN get_objects_by_tr_request_hdrs( it_tr_request_header = lt_tr_request
iv_fl_current_user_only = iv_fl_current_user_only ).
ENDMETHOD.
METHOD get_objects_by_tr_request_hdrs.
DATA: lt_request TYPE trwbo_requests,
lt_all_request TYPE trwbo_requests,
lt_object_definition TYPE tt_object_definition.
IF it_tr_request_header IS INITIAL.
RETURN.
ENDIF.
LOOP AT it_tr_request_header ASSIGNING FIELD-SYMBOL(<ls_tr_req_header>) .
CALL FUNCTION 'TR_READ_REQUEST_WITH_TASKS'
EXPORTING
iv_trkorr = <ls_tr_req_header>-trkorr
IMPORTING
et_requests = lt_request
EXCEPTIONS
invalid_input = 1
OTHERS = 2.
IF sy-subrc <> 0.
lcl_logger=>warn( |{ gc_msg_tr_request_read_error }: { <ls_tr_req_header>-trkorr }| ).
CONTINUE.
ENDIF.
APPEND LINES OF lt_request TO lt_all_request.
ENDLOOP.
IF iv_fl_current_user_only = abap_true.
DELETE lt_all_request WHERE h-as4user <> sy-uname.
ENDIF.
LOOP AT lt_all_request ASSIGNING FIELD-SYMBOL(<ls_request_detail>).
LOOP AT <ls_request_detail>-objects ASSIGNING FIELD-SYMBOL(<ls_object>).
SPLIT <ls_object>-obj_name AT '=' INTO TABLE DATA(lt_split).
IF lt_split IS INITIAL.
lcl_logger=>warn( |{ gc_msg_invalid_format }: { <ls_object>-obj_name }| ).
CONTINUE.
ENDIF.
APPEND VALUE #( object_name = VALUE #( lt_split[ 1 ] OPTIONAL )
object_type = <ls_object>-object ) TO lt_object_definition.
ENDLOOP.
ENDLOOP.
RETURN adjust_objects_table( lt_object_definition ).
ENDMETHOD.
METHOD adjust_objects_table.
DATA:
ls_object_definition TYPE ts_object_definition,
lt_function_group_name TYPE string_table,
lt_prog_name TYPE STANDARD TABLE OF progname.
IF it_object IS INITIAL.
RETURN.
ENDIF.
LOOP AT it_object ASSIGNING FIELD-SYMBOL(<ls_object>).
ls_object_definition-object_name = <ls_object>-object_name.
CASE <ls_object>-object_type.
WHEN gc_objects_type_class_include OR gc_objects_type_class.
ls_object_definition-object_type = gc_object_def_type_class.
WHEN gc_objects_type_func.
ls_object_definition-object_type = gc_object_def_type_fm.
WHEN gc_objects_type_program.
ls_object_definition-object_type = gc_object_def_type_report.
" Add to lt_prog_name to check if it is include and delete in that case
APPEND ls_object_definition-object_name TO lt_prog_name.
WHEN gc_objects_type_fm.
"Add to lt_function_group_name to find function modules in groups
APPEND |{ gc_function_group_prefix }{ ls_object_definition-object_name }| TO lt_function_group_name.
"Skip to not add function group
CONTINUE.
WHEN OTHERS.
CONTINUE.
ENDCASE.
APPEND ls_object_definition TO rt_object.
ENDLOOP.
APPEND LINES OF get_modules_in_function_group( lt_function_group_name ) TO rt_object.
SORT rt_object BY object_name.
DELETE ADJACENT DUPLICATES FROM rt_object COMPARING ALL FIELDS.
delete_includes( EXPORTING it_prog_name = lt_prog_name
CHANGING ct_object = rt_object ).
ENDMETHOD.
METHOD get_modules_in_function_group.
DATA lt_function_group_name TYPE STANDARD TABLE OF pname.
lt_function_group_name = VALUE #( FOR <ls_fg> IN it_function_group_name WHERE ( table_line IS NOT INITIAL )
( CONV #( to_upper( <ls_fg> ) ) ) ).
IF lt_function_group_name IS INITIAL.
RETURN.
ENDIF.
" select function modules names that belong to function group
SELECT funcname
FROM tfdir "#EC CI_GENBUFF.
FOR ALL ENTRIES IN @lt_function_group_name
WHERE pname = @lt_function_group_name-table_line
INTO TABLE @DATA(lt_function_module_name).
IF sy-subrc <> 0.
RETURN.
ENDIF.
APPEND LINES OF VALUE tt_object_definition( FOR <ls_fm> IN lt_function_module_name ( object_name = <ls_fm>-funcname
object_type = gc_object_def_type_fm ) ) TO rt_function_module.
ENDMETHOD.
METHOD delete_includes.
DATA(lt_prog_name) = VALUE tt_prog_name( FOR <ls_prog_name> IN it_prog_name WHERE ( table_line IS NOT INITIAL )
( <ls_prog_name> ) ).
IF lt_prog_name IS INITIAL.
RETURN.
ENDIF.
SELECT name
FROM progdir
FOR ALL ENTRIES IN @lt_prog_name
WHERE name = @lt_prog_name-table_line
AND subc = @gc_program_type_include
INTO TABLE @DATA(lt_inc_name).
IF sy-subrc <> 0.
RETURN.
ENDIF.
LOOP AT lt_inc_name ASSIGNING FIELD-SYMBOL(<ls_inc_name>).
DELETE ct_object WHERE object_name = <ls_inc_name>-name.
ENDLOOP.
ENDMETHOD.
METHOD get_tr_request_headers.
DATA(lv_username_pattern) = sy-uname.
" All types of requests
DATA(ls_selection) = VALUE trwbo_selection( reqfunctions = gc_request_functions_all
reqstatus = gc_status_modifiable_released ).
IF is_selection IS SUPPLIED.
ls_selection = is_selection.
ENDIF.
IF iv_username_pattern IS SUPPLIED.
lv_username_pattern = iv_username_pattern.
ENDIF.
CALL FUNCTION 'TRINT_SELECT_REQUESTS'
EXPORTING
is_selection = ls_selection
iv_username_pattern = lv_username_pattern
IMPORTING
et_requests = rt_tr_request.
DELETE rt_tr_request WHERE trfunction <> gc_trfunction_workbench.
ENDMETHOD.
ENDCLASS.
CLASS lcl_suggestions_exporter DEFINITION FINAL.
PUBLIC SECTION.
METHODS:
export_in_excel IMPORTING !it_suggestion TYPE tt_suggestion
RAISING lcx_suggestions_exporter_error,
export_to_server IMPORTING !iv_file_path TYPE string
!it_suggestion TYPE tt_suggestion
RAISING lcx_suggestions_exporter_error,
display_in_demo_output IMPORTING !it_suggestion TYPE tt_suggestion,
display_in_alv IMPORTING !it_suggestion TYPE tt_suggestion
RAISING lcx_suggestions_exporter_error.
PRIVATE SECTION.
CONSTANTS:
gc_msg_xlsx_creation_error TYPE string VALUE 'XLSX creation error',
gc_msg_export_err_gui_download TYPE string VALUE 'Exporting with gui download error',
gc_msg_export_err_open_dataset TYPE string VALUE 'Exporting with open dataset error',
gc_msg_invalid_path TYPE string VALUE 'Invalid path was provided for current platform',
gc_msg_table_not_bound TYPE string VALUE 'ALV table not bound',
gc_msg_alv_format_error TYPE string VALUE 'ALV table format error',
gc_msg_alv_display_error TYPE string VALUE 'Error while generating SALV Grid Display',
gc_msg_save_dialog_error TYPE string VALUE 'Error occurred in save file dialog',
gc_msg_empty_file_path TYPE string VALUE 'Empty file path',
gc_priority_high TYPE string VALUE 'HIGH',
gc_priority_medium TYPE string VALUE 'MEDIUM',
gc_priority_low TYPE string VALUE 'LOW',
" constants for calculating sorting key according to priority
gc_sort_priority_high TYPE string VALUE '1',
gc_sort_priority_medium TYPE string VALUE '2',
gc_sort_priority_low TYPE string VALUE '3',
gc_sort_priority_default TYPE string VALUE '4',
gc_column_name_color TYPE lvc_fname VALUE 'COLOR',
gc_column_name_sorting_key TYPE lvc_fname VALUE 'SORTING_KEY',
gc_column_name_object_type TYPE lvc_fname VALUE 'OBJECT_TYPE',
gc_column_name_object_name TYPE lvc_fname VALUE 'OBJECT_NAME',
gc_column_name_code_section TYPE lvc_fname VALUE 'SOURCE_CODE_SECTION_NAME',
gc_column_name_suggestion TYPE lvc_fname VALUE 'SUGGESTION',
gc_column_name_priority TYPE lvc_fname VALUE 'PRIORITY',
gc_column_name_user TYPE lvc_fname VALUE 'USER',
gc_column_text_object_type TYPE string VALUE 'Type',
gc_column_text_object_name TYPE string VALUE 'Object',
gc_column_text_code_section TYPE string VALUE 'Code section name',
gc_column_text_suggestion TYPE string VALUE 'Comment',
gc_column_text_priority TYPE string VALUE 'Priority',
gc_column_text_user TYPE string VALUE 'User',
gc_method_name_global TYPE string VALUE 'GLOBAL',
gc_file_extension_xlsx TYPE string VALUE 'XLSX',
gc_file_type_bin TYPE char10 VALUE 'BIN',
gc_default_file_name TYPE string VALUE 'Code review',
gc_default_intense_value TYPE i VALUE 1,
gc_color_code_red TYPE i VALUE 6,
gc_color_code_orange TYPE i VALUE 7,
gc_color_code_yellow TYPE i VALUE 3.
TYPES:
BEGIN OF ts_suggestion_with_tech_info,
object_type TYPE string,
object_name TYPE string,
source_code_section_name TYPE string,
suggestion TYPE string,
priority TYPE string,
user TYPE string,
sorting_key TYPE string,
color TYPE lvc_t_scol,
END OF ts_suggestion_with_tech_info,
tt_suggestion_with_tech_info TYPE STANDARD TABLE OF ts_suggestion_with_tech_info WITH DEFAULT KEY.
METHODS:
create_xlsx_from_itab IMPORTING !it_fieldcat TYPE lvc_t_fcat OPTIONAL
!it_sort TYPE lvc_t_sort OPTIONAL
!it_filt TYPE lvc_t_filt OPTIONAL
!is_layout TYPE lvc_s_layo OPTIONAL
!it_hyperlink TYPE lvc_t_hype OPTIONAL
CHANGING !it_data TYPE STANDARD TABLE
RETURNING VALUE(rv_xstring) TYPE xstring
RAISING lcx_suggestions_exporter_error,
export_with_gui_download IMPORTING !iv_file_path TYPE string
!iv_file_data TYPE xstring
RAISING lcx_suggestions_exporter_error,
export_with_open_dataset IMPORTING !iv_file_path TYPE string
!iv_file_data TYPE xstring
RAISING lcx_suggestions_exporter_error,
populate_technical_info IMPORTING !it_suggestion TYPE tt_suggestion
RETURNING VALUE(rt_suggestion_with_tech_info) TYPE tt_suggestion_with_tech_info,
calculate_sorting_key IMPORTING !is_suggestion TYPE ts_suggestion
RETURNING VALUE(rv_key) TYPE string,
calculate_color IMPORTING !is_suggestion TYPE ts_suggestion
RETURNING VALUE(rv_code) TYPE lvc_s_scol,
beautify_salv_table IMPORTING !io_salv_table TYPE REF TO cl_salv_table
RAISING lcx_suggestions_exporter_error,
get_default_file_name RETURNING VALUE(rv_file_name) TYPE string.
ENDCLASS.
CLASS lcl_suggestions_exporter IMPLEMENTATION.
METHOD create_xlsx_from_itab.
FIELD-SYMBOLS: <ls_tab> TYPE STANDARD TABLE.
DATA(lt_data) = REF #( it_data ).
IF it_fieldcat IS INITIAL.
ASSIGN lt_data->* TO <ls_tab>.
TRY.
cl_salv_table=>factory( EXPORTING list_display = abap_false
IMPORTING r_salv_table = DATA(salv_table)
CHANGING t_table = <ls_tab> ).
beautify_salv_table( salv_table ).
DATA(lt_fcat) = cl_salv_controller_metadata=>get_lvc_fieldcatalog( r_columns = salv_table->get_columns( )
r_aggregations = salv_table->get_aggregations( ) ).
CATCH cx_salv_msg INTO DATA(lx_salv).
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_xlsx_creation_error
io_previous = lx_salv.
ENDTRY.
ELSE.
lt_fcat = it_fieldcat.
ENDIF.
TRY.
cl_salv_bs_lex=>export_from_result_data_table( EXPORTING is_format = if_salv_bs_lex_format=>mc_format_xlsx
ir_result_data_table = cl_salv_ex_util=>factory_result_data_table(
r_data = lt_data
s_layout = is_layout
t_fieldcatalog = lt_fcat
t_sort = it_sort
t_filter = it_filt
t_hyperlinks = it_hyperlink )
IMPORTING er_result_file = rv_xstring ).
CATCH cx_salv_unexpected_param_value INTO DATA(lx_salv_param).
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_xlsx_creation_error
io_previous = lx_salv_param.
ENDTRY.
ENDMETHOD.
METHOD export_with_gui_download.
IF iv_file_path IS INITIAL.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_empty_file_path.
ENDIF.
DATA(it_raw_string) = cl_bcs_convert=>xstring_to_solix( iv_file_data ).
cl_gui_frontend_services=>gui_download( EXPORTING filename = iv_file_path
filetype = gc_file_type_bin
bin_filesize = xstrlen( iv_file_data )
CHANGING data_tab = it_raw_string
EXCEPTIONS access_denied = 1
file_write_error = 2
no_batch = 3
gui_refuse_filetransfer = 4
OTHERS = 5 ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = | { gc_msg_export_err_gui_download }: { iv_file_path }|
iv_subrc = sy-subrc.
ENDIF.
ENDMETHOD.
METHOD export_with_open_dataset.
DATA lv_msg TYPE string.
IF iv_file_path IS INITIAL.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_empty_file_path.
ENDIF.
TRY.
cl_fs_path=>create( iv_file_path ).
CATCH cx_fs_path_error INTO DATA(lx_path_error).
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_invalid_path
io_previous = lx_path_error.
ENDTRY.
OPEN DATASET iv_file_path FOR OUTPUT IN BINARY MODE MESSAGE lv_msg.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = |{ gc_msg_export_err_open_dataset }: { iv_file_path }: { lv_msg }|
iv_subrc = sy-subrc.
ENDIF.
TRANSFER iv_file_data TO iv_file_path.
IF sy-subrc <> 0.
CLOSE DATASET iv_file_path.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = |{ gc_msg_export_err_open_dataset }: { iv_file_path }|
iv_subrc = sy-subrc.
ENDIF.
CLOSE DATASET iv_file_path.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = |{ gc_msg_export_err_open_dataset }: { iv_file_path }|
iv_subrc = sy-subrc.
ENDIF.
ENDMETHOD.
METHOD calculate_color.
IF is_suggestion IS INITIAL.
RETURN.
ENDIF.
rv_code = SWITCH lvc_s_scol( is_suggestion-priority
WHEN gc_priority_high THEN VALUE #( fname = gc_column_name_priority color = VALUE #( col = gc_color_code_red int = gc_default_intense_value ) )
WHEN gc_priority_medium THEN VALUE #( fname = gc_column_name_priority color = VALUE #( col = gc_color_code_orange int = gc_default_intense_value ) )
WHEN gc_priority_low THEN VALUE #( fname = gc_column_name_priority color = VALUE #( col = gc_color_code_yellow int = gc_default_intense_value ) )
ELSE VALUE #( ) ).
ENDMETHOD.
METHOD calculate_sorting_key.
IF is_suggestion IS INITIAL.
RETURN.
ENDIF.
DATA(lv_suggestion) = is_suggestion.
CONDENSE: lv_suggestion-object_name NO-GAPS, lv_suggestion-source_code_section_name NO-GAPS.
rv_key = |{ lv_suggestion-object_name }|
&& |{ SWITCH stringval( is_suggestion-priority WHEN gc_priority_high THEN gc_sort_priority_high
WHEN gc_priority_medium THEN gc_sort_priority_medium
WHEN gc_priority_low THEN gc_sort_priority_low
ELSE gc_sort_priority_default ) }|
&& |{ SWITCH stringval( is_suggestion-source_code_section_name WHEN gc_method_name_global THEN gc_sort_priority_high
ELSE lv_suggestion-source_code_section_name ) }|.
ENDMETHOD.
METHOD populate_technical_info.
IF it_suggestion IS INITIAL.
RETURN.
ENDIF.
rt_suggestion_with_tech_info = VALUE #( FOR <ls_suggestion> IN it_suggestion
WHERE ( table_line IS NOT INITIAL )
( object_type = <ls_suggestion>-object_type
object_name = <ls_suggestion>-object_name
source_code_section_name = <ls_suggestion>-source_code_section_name
suggestion = <ls_suggestion>-suggestion
priority = <ls_suggestion>-priority
user = <ls_suggestion>-user
sorting_key = calculate_sorting_key( <ls_suggestion> )
color = VALUE #( ( calculate_color( <ls_suggestion> ) ) ) ) ).
ENDMETHOD.
METHOD beautify_salv_table.
TYPES: BEGIN OF ts_column_config,
column_name TYPE lvc_fname,
text TYPE string,
END OF ts_column_config.
DATA: lt_column_config TYPE STANDARD TABLE OF ts_column_config,
lo_column TYPE REF TO cl_salv_column.
IF io_salv_table IS NOT BOUND.
RAISE EXCEPTION TYPE lcx_suggestions_exporter_error
EXPORTING
iv_error_text = gc_msg_table_not_bound.
ENDIF.