Emre Göçmen Blog

SAP GUI'de Sıfır Bağımlılıkla Dashboard: ST22, SM37, SM12 ve TADIR'ı Tek Ekranda Toplamak

5 dk. okuma
343 görüntülenme
0 yorum

Emre Göçmen

Yazar

SAP GUI'de Sıfır Bağımlılıkla Dashboard: ST22, SM37, SM12 ve TADIR'ı Tek Ekranda Toplamak

Her SAP danışmanının, geliştiricinin ve Basis uzmanının bir sabah rutini var: ST22'yi aç, dün gece ne patlamış diye bak. SM37'yi aç, hangi job kesilmiş. SM12'ye göz at. Ayın sonuysa SE16'da TADIR'ı sorgula, bu sistemde kaç Z objesi olduğunu hatırlamaya çalış.

Altı transaction, altı ayrı ekran, hiçbirinde trend yok. Dün 3 dump vardı, bugün 19 — bunu ancak fark ederseniz fark ediyorsunuz.

Bu yazıda o altı ekranı tek bir ABAP raporunda birleştiriyoruz. Ama asıl konu dashboard değil; SAP GUI içinde HTML/JavaScript'in gerçekten nasıl çalıştığı ve kimsenin yazmadığı dört sessiz tuzak. O tuzaklara düşenler “SAP'ta grafik olmuyor” deyip vazgeçiyor.

Kod tek dosya, kopyala-çalıştır. İnternet erişimi, CDN, SMW0, MIME repository, harici kütüphane — hiçbiri gerekmiyor.

Neyi çözüyoruz

01-sistem-sagligi.png

Tek program, iki sekme.

Sistem Sağlığı: son 24 saatteki dump sayısı ve eşik durumu, günlük dump trendi (ortalama çizgisiyle, sıçrayan günler kırmızı), kullanıcı bazında dump dağılımı, program bazında kesilen job'lar, en uzun süren job'lar, anlık kilit girişi sayısı ve en son kesilen job'ların listesi.

Custom Code Envanteri: toplam Z/Y objesi, obje türü ve paket dağılımı, son 12 ayın custom kod değişim trendi, $TMP'de kalmış (transport edilemez) objeler, sahibi sistemde artık tanımlı olmayan “sahipsiz” objeler ve en son değiştirilen Z programlar.

Grafik çubuklarına ve tablo satırlarına tıklayınca tıklanan kritere göre filtrelenmiş bir ALV detay listesi açılıyor: kullanıcı çubuğu → o kullanıcının dump'ları, program çubuğu → o programın kesilen job'ları, paket çubuğu → o paketteki Z objeleri. Program satırında doğrudan SE38 açılıyor.

İki sekmenin birlikte durması tesadüf değil. Sistem sağlığı tarafında “kesilen job'ların kaçı Z* kaynaklı” diye bir not var — ve cevap genelde beklediğinizden yüksek çıkıyor. Custom code envanteri o sorunun nereden geldiğini gösteren taraf.

Neden Chart.js değil

İlk refleks Chart.js ya da ECharts'ı CDN'den çekmek:

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

SAP GUI'nin HTML kontrolünde bu satır çoğu kurumda sessizce başarısız olur. Şirket ağı CDN'e çıkmaz, proxy araya girer, ya da sunucu hiç internete bakmaz. Sonuç: tablo ve kartlar görünür, grafiklerin yerinde bomboş <canvas> durur. Konsolu göremediğiniz için de sebebini anlamazsınız.

CDN'e erişseniz bile ikinci bir duvar var: HTML kontrolünün hangi tarayıcı motorunu kullandığı, sunucu değil kullanıcının makinesi tarafından belirlenir. SAP GUI for Windows, HTML kontrolünü ya eski IE tabanlı (MSHTML) ya da Edge/Chromium (WebView2) motoruyla çalıştırır. Edge seçeneği bazı kurulumlarda yönetici tarafından kilitlenmiş gelir ve WebView2 sürüm güncellemeleri geçmişte SAP GUI'de sorun çıkarmıştır (SAP KBA 3191784, KBA 3704912).

Yani modern Chart.js sürümlerinin beklediği ES6 sizin makinenizde çalışır, kullanıcının makinesinde çalışmaz. Bu, tek makinede test edip yayına aldığınızda öğrenilen bir ders.

Bu yüzden karar: grafikleri saf SVG olarak, ES5 JavaScript ile kendimiz çiziyoruz. Yaklaşık 60 satırlık iki fonksiyon (yatay bar, dikey bar) tüm panoyu besliyor. Dış bağımlılık sıfır, IE ve Edge'de aynı görünüyor, dosya 17 KB.

Dört sessiz tuzak

02-custom-code.png

Bu kısım yazının asıl sebebi. Bu dört şey internette pek yazmıyor ve dördü de hata mesajı vermeden sizi yanlış yola sokuyor. Dördüncüsünü canlı sistemde ilk denemede yedim.

1. HTML'i 1000 karakterlik parçalara bölmek JavaScript'i bozar

Neredeyse her örnekte gördüğünüz kalıp bu:

" YANLIS
DATA: lv_chunk TYPE c LENGTH 1000.
WHILE lv_offset < lv_len.
  lv_chunk = gv_html+lv_offset(1000).
  APPEND lv_chunk TO gt_html_table.
  lv_offset = lv_offset + 1000.
ENDWHILE.

İki ayrı şekilde bozuyor. Birincisi, kesme noktası bir JS token'ının ortasına düşebilir — dataMtart değişkeni satır sonunda dataM, satır başında tart olarak ikiye ayrılır. HTML bunu affeder, JavaScript affetmez. İkincisi, TYPE c sabit uzunluklu olduğu için son parça boşluklarla doldurulur ve o boşluklar dosyaya yazılır.

Sonuç: HTML açılır, CSS çalışır, tablo görünür, JavaScript sessizce ölür. Hata mesajı yok.

Doğrusu string'i hiç parçalamamak — UTF-8 xstring'e çevirip binary tablo olarak yüklemek:

" DOGRU
DATA: lo_conv TYPE REF TO cl_abap_conv_out_ce,
      lv_x    TYPE xstring,
      lt_bin  TYPE solix_tab,
      lv_len  TYPE i.

lo_conv = cl_abap_conv_out_ce=>create( encoding = 'UTF-8' ).
CALL METHOD lo_conv->convert
  EXPORTING data   = gv_html
  IMPORTING buffer = lv_x.

" BOM: eski IE tabanli kontrolun kod sayfasini dogru secmesi icin
CONCATENATE cl_abap_char_utilities=>byte_order_mark_utf8 lv_x
       INTO lv_x IN BYTE MODE.

lv_len = xstrlen( lv_x ).
lt_bin = cl_bcs_convert=>xstring_to_solix( lv_x ).

CALL METHOD go_html->load_data
  EXPORTING url = 'panel.html' type = 'text' subtype = 'html' size = lv_len
  IMPORTING assigned_url = lv_url
  CHANGING  data_table   = lt_bin.

BOM detayı ayrıca Türkçe karakter sorununu da çözüyor. Butonlarda ?? görüyorsanız sebep buydu: <meta charset="utf-8"> tek başına yeterli değil, veriyi gerçekten UTF-8 olarak göndermeniz gerekiyor.

2. cl_gui_cfw=>dispatch olmadan sapevent hiç çalışmaz

Grafiğe tıklamayı ABAP'a döndürmek için sapevent protokolü kullanılıyor. JavaScript tarafı basit:

function go(action,key){
  window.location.href = 'sapevent:' + action + '?key=' + key;
}

ABAP tarafında olayı kaydediyorsunuz:

ls_ev-eventid    = go_html->m_id_sapevent.
ls_ev-appl_event = 'X'.
APPEND ls_ev TO lt_ev.
go_html->set_registered_events( events = lt_ev ).
SET HANDLER lcl_evt=>on_sapevent FOR go_html.

Ve hiçbir şey olmuyor. Sebep: appl_event = 'X' ile kaydedilen olaylar application event'tir; bunların handler'a ulaşması için PAI içinde açıkça dispatch edilmeleri gerekir.

MODULE user_command_0100 INPUT.
  DATA lv_rc TYPE i.
* Bu satir olmadan handler hic calismaz
  CALL METHOD cl_gui_cfw=>dispatch IMPORTING return_code = lv_rc.
  ...
ENDMODULE.

Bir ayrıntı daha: handler'ın kendisi iş yapmıyor, sadece isteği global değişkenlere yazıyor. CALL TRANSACTION ya da ALV popup gibi ekran akışını değiştiren işler PAI modülünde yapılmalı — handler'ın içinde yapılırsa ekran akışıyla kavga eder.

Bir de küçük ama sinir bozucu bir ayrıntı: JavaScript tarafında encodeURIComponent kullanmayın. $TMP gibi bir anahtar %24TMP olarak gider ve ABAP tarafındaki filtreyle eşleşmez. Teknik adlar zaten sorgu dizesinde güvenli karakterlerden oluşuyor.

3. COLLECT string alanla çalışmaz, LOOP AT ... WHERE içinde offset yasaktır

Gruplama için akla gelen ilk şey:

" YANLIS -- COLLECT flat yapi ister, STRING yapiyi derin yapar
TYPES: BEGIN OF ty_kv, k TYPE string, v TYPE i, END OF ty_kv.
COLLECT ls_kv INTO lt_agg.

COLLECT yalnızca düz (flat) yapılarla çalışır ve STRING bir yapıyı derin hale getirir. JSON'a string olarak yazacağınız için tipi string yapmak istiyorsunuz, ama gruplamayı düz bir tiple yapmanız gerekiyor:

" Gruplama icin duz tip; grafige giderken string tipe cevir
TYPES: BEGIN OF ty_agg, k TYPE c LENGTH 60, v TYPE i, END OF ty_agg.

İkinci tuzak aynı ailede: aylık trendi hesaplarken udat'ın ilk 6 karakterini karşılaştırmak istiyorsunuz. Ama LOOP AT ... WHERE koşulunda offset kullanılamaz.

" YANLIS: LOOP AT lt_trdir ASSIGNING <r> WHERE udat+0(6) = lv_ym.
" DOGRU:
LOOP AT lt_trdir ASSIGNING <r>.
  IF <r>-udat+0(6) = lv_ym.
    ls_kv-v = ls_kv-v + 1.
  ENDIF.
ENDLOOP.

Bunlar sözdizimi hatası verir, yani en azından sizi uyarırlar — ama neden olduğunu bilmeden yarım saat harcanır.

4. Eski IE motorunda CSS değişkenleri, flexbox gap ve SVG height:auto çalışmaz

Bu maddeyi tahmin ederek değil, canlı sistemde yiyerek yazıyorum. Panoyu ilk kez gerçek bir sistemde açtığımda üst bar düzgün görünüyordu, ama kartların arka planı, çerçevesi ve durum noktaları yoktu. Sistem bilgileri Sistem KEDMandant 100Kullanıcı EGOCMEN diye bitişik yazıyordu. Grafikler ise saçma ölçeklerde çiziliyordu.

Üç ayrı belirti, tek bir teşhis: HTML kontrolü eski IE motorunda çalışıyordu. Kanıt, neyin çalıştığında — üst barın rengi sabit hex ile verilmişti ve göründü, kartların rengi CSS değişkeniyle verilmişti ve görünmedi.

Somut olarak, eski IE motorunda çalışmayan şeyler:

/* 1) CSS custom properties -> hic uygulanmaz, renk kaybolur */
:root { --surface:#fff; }
.card { background:var(--surface); }     /* YANLIS */
.card { background:#ffffff; }            /* DOGRU  */

/* 2) flexbox gap -> yok sayilir, ogeler bitisir */
.row { display:flex; gap:12px; }         /* YANLIS */
.row { margin:0 -6px; overflow:hidden; } /* DOGRU: float + padding */
.col { float:left; padding:0 6px 12px; }
.c4  { width:25%; }

Aynı listeye calc() (eski sürümlerde kısmi) ve position:sticky (hiç yok) da giriyor. Tablo başlığını sabitlemek istiyorsanız sticky yerine kaydırılabilir bir kapsayıcı kullanın.

Üçüncüsü daha sinsi: SVG'yi width:100%; height:auto ile ölçeklendirmek. Modern tarayıcılar viewBox'tan en-boy oranını hesaplar, eski IE hesaplamaz — grafik ya 150px yükseklikte ezilir ya da absürt oranda uzar. Çözüm, ölçeklendirmeyi tarayıcıya hiç bırakmamak: çizim anında kapsayıcının genişliğini okuyup SVG'ye width ve heightattribute olarak piksel değerinde yazmak.

var W = host.clientWidth || 440;          /* gercek piksel genislik */
var H = TP + slots*(RH+GP);
var svg = E('svg',{width:W, height:H, viewBox:'0 0 '+W+' '+H});

Bunun bir yan faydası da var: tüm ölçüler piksel uzayında hesaplandığı için etiket sütununun genişliğini en uzun etikete göre ayarlayabiliyorsunuz. ESH_IX_CRT_INDEX_OBJECT_TYPE gibi bir program adı artık kırpılmıyor. Bir de window.onresize bağlayıp yeniden çizerseniz pano SAP GUI penceresiyle birlikte akıyor.

Kısacası: bu ekranı yazarken hedefiniz “modern tarayıcıda çalışan HTML” değil, 2013'ten kalma bir motorda da aynı görünen HTML. Bunu baştan kabul ederseniz CSS'iniz kısıtlı ama sonuç her makinede aynı olur.

Mimari: ABAP hiç HTML yazmaz

30 rapora ölçeklenmeyen yaklaşım, HTML'i ABAP kodunun içine serpiştirmektir. Bu programda HTML iskeleti tek bir yerde duruyor ve içinde sadece iki placeholder var:

{{DATA}}   ->  var D = {trend:{l:[..],v:[..]}, user:{...}, tJob:[[..],[..]], ...}
{{META}}   ->  var M = {sys:{...}, kpi1:[{...}], kpi2:[{...}], notes:{...}}

ABAP'ın tek işi bu iki JSON'u üretmek. KPI kartlarını, sistem satırını, grafik altındaki yorumları HTML değil JavaScript çiziyor — verisi M'den geliyor.

Pratik faydası şu: yeni bir KPI kartı eklemek için HTML'e dokunmuyorsunuz, ABAP'ta gt_kpi1'e bir satır ekliyorsunuz. Yeni grafik istiyorsanız iskelette bir <div id="..."> ile bir hbar(...) çağrısı, ABAP'ta bir PERFORM f_kv. Renk paletini, Excel butonunu, IE uyumluluk düzeltmesini tek yerde değiştirip bütün raporlarınızı birden düzeltebiliyorsunuz.

Sondaki virgül problemini de zararsız bir kapanış anahtarıyla çözüyorum, böylece JSON üretirken “son eleman mı” kontrolü yapmak gerekmiyor:

CONCATENATE lv_data `x:0};` INTO lv_data.

Drill-down: transaction'ı boş açmak yerine filtrelenmiş liste

İlk sürümde tıklama CALL TRANSACTION 'SM37' yapıyordu. Çalışıyor ama işe yaramıyor: kullanıcı kendi tıkladığı programı SM37'nin seçim ekranına elle yazmak zorunda kalıyor. Tıklamanın anlamı kayboluyor.

Standart raporların seçim ekranı parametrelerini SUBMIT ... WITH ... ile doldurmak da cazip ama kırılgan: parametre adları sürümler arasında değişebiliyor ve derlenmeyen bir kod paylaşmak istemedim. Bu yüzden detay listesini kendim kuruyorum — CL_SALV_TABLE ile popup ALV:

FORM f_alv USING iv_title TYPE string it_hdr TYPE tt_hdr
           CHANGING ct TYPE STANDARD TABLE.
  DATA: lo_alv TYPE REF TO cl_salv_table.

  IF ct IS INITIAL.
    MESSAGE 'Secime uyan kayit bulunamadi' TYPE 'S' DISPLAY LIKE 'W'.
    RETURN.
  ENDIF.

  TRY.
      CALL METHOD cl_salv_table=>factory
        IMPORTING r_salv_table = lo_alv
        CHANGING  t_table      = ct.
    CATCH cx_salv_msg.
      RETURN.
  ENDTRY.

  lo_alv->set_screen_popup( start_column = 5  end_column = 145
                            start_line   = 3  end_line   = 25 ).
  " ... baslik, kolon metinleri, fonksiyonlar
  lo_alv->display( ).
ENDFORM.

Bunun üç avantajı var. Pano açık kalıyor — popup kapanınca kullanıcı bıraktığı yere dönüyor. Filtre tam olarak tıklanan kriter: “EERTE kullanıcısının dump'ları”, “ZMM paketindeki Z objeleri”, “03.26'da değişen Z programlar”. Ve kolon başlıklarını kendiniz veriyorsunuz, yani DAKIKA değil “Süre (dk)” yazıyor.

Bunun bedeli, ham veriyi bellekte tutmak. Pano açılırken okunan SNAP, TBTCO, TADIR ve TRDIR kayıtları global tablolarda kalıyor ve drill-down anında oradan filtreleniyor — ikinci bir veritabanı okuması yok.

Bir de buradan çıkan gerçek bir performans dersi: ilk sürümde TBTCP'yi FOR ALL ENTRIES ile tüm job'lar için okuyordum. Test sisteminde sorun çıkmadı. 14 günde 90.733 job'u olan bir sistemde ise bu, 90 bin girişli bir FOR ALL ENTRIES demek. Program adına yalnızca kesilen job'lar için ihtiyaç var:

" Kesilen joblar ayri bir tabloya alinir ve FAE SADECE onlar icin yapilir
IF lt_abo IS NOT INITIAL.
  SELECT jobname jobcount stepcount progname
    FROM tbtcp INTO TABLE gt_step
    FOR ALL ENTRIES IN lt_abo
    WHERE jobname = lt_abo-jobname AND jobcount = lt_abo-jobcount.
ENDIF.

90.733 giriş yerine 1.640. Aynı sonuç, kıyaslanamayacak kadar hafif.

Veri kaynakları ve dikkat edilmesi gerekenler

NeKaynakNotDump'larSNAPHer dump için çok satır tutar. SEQNO alan tipi sürümler arasında değiştiği için filtre yerine dump anahtarında SELECT DISTINCT kullandım. Tabloya erişim yetkisi gerekir.Kesilen job'larTBTCO (STATUS = 'A')Süre = (enddate-strtdate)*86400 + (endtime-strttime) saniye. Başlamadan iptal edilen job'da STRTDATE boş kalır; kontrol etmezseniz süre ~740.000 gün çıkar ve grafiği ezer.Job'un programıTBTCPFOR ALL ENTRIES'i sadece kesilen job'lar için yapın. Tablonun boş olmadığını da mutlaka kontrol edin — boş tabloyla tüm tabloyu çeker.KilitlerENQUEUE_READSadece sayı için NUMBER parametresi yeterli. SEQG3 alan adlarına bilerek dokunmadım ki sürüm farkı derlemeyi bozmasın.Z objeleriTADIRPGMID = 'R3TR' ve DELFLAG = space filtresi şart. Paket, obje türü ve sahibi buradan geliyor.Z programlarTRDIRUDAT/UNAM son değişiklik, CNAM oluşturan, SUBC program türü.Sahipsiz objelerTADIR-AUTHOR vs USR02-BNAMESahibi sistemde artık tanımlı olmayan objeler. Devir-teslimde en çok işe yarayan metrik.

SM13 (update terminations) ve SM21 (sistem logu) bilerek dışarıda. VBHDR alan adları ve sistem log API'si sürüme göre değişiyor; sizin sisteminizde derlenmeyecek bir kod paylaşmak istemedim. İkisini de aynı desenle eklemek yaklaşık 20 satır.

Kurulum

Screen Painter'da hiçbir şey çizmiyoruz — docking container ekranın tamamını kaplıyor. Dört adım:

  1. SE38 — programı oluştur, kodu yapıştır, aktive et.

  2. SE51 — Dynpro 0100 oluştur (boş ekran, tip “Normal”). Element listesindeki OK code alanına OK_CODE yaz.

  3. SE41MAIN status'ü oluştur; BACK / EXIT / CANCEL fonksiyon kodlarını F3 / Shift+F3 / F12'ye bağla.

  4. SE38 > Goto > Text Elements — metin sembollerini ve seçim metinlerini gir.

İkinci adımdaki dynpro'nun flow logic'i tam olarak şu olmalı:

PROCESS BEFORE OUTPUT.
  MODULE status_0100.

PROCESS AFTER INPUT.
  MODULE user_command_0100.

Kod klasik ABAP söz dizimiyle yazıldı; ECC 6.0'dan S/4HANA'ya kadar aynı şekilde derleniyor. Parantezli metot çağrısı yerine CALL METHOD kullandım ki NetWeaver 7.00 seviyesindeki eski sistemlerde de sorun çıkmasın. Sisteminiz Unicode değilse HTML'deki Türkçe etiketleri ASCII'ye çevirmeniz gerekir.

Nereye kadar gider, nereye gitmez

Dürüst olmak gerekirse bu yaklaşım bir BI platformu değil ve olmaya çalışmamalı.

İyi olduğu yer: SAP GUI'den çıkmayan teknik kullanıcılar, canlı SAP verisi, ek lisans yok, ek altyapı yok, yetkilendirme zaten SAP'ta, transportla taşınıyor. Birkaç bin satırlık kümeler için mükemmel.

Sınırları: HTML'i ABAP string'inde kurup gönderiyorsunuz — 100 bin satırlık bir veri seti için uygun değil, agregasyonu veritabanına yıkmanız gerekir. Zamanlanmış yenileme, abonelik, paylaşım, mobil, satır seviyesi güvenlik, self-service analiz — hiçbiri yok. Bunları HTML template ile yeniden yazmaya çalışmak Power BI'ı taklit etmeye çalışmaktır ve iyi bitmez.

Yatırım nereye yapılmalı: sunum katmanı (HTML/JS) en ucuz ve en kolay değiştirilebilen parça. Kalıcı değer CDS view'da. Agregasyonu CDS'e taşırsanız aynı veri modelini ABAP raporu, Fiori Elements, SAC ve Power BI aynı anda kullanabilir. Yarın “biz Power BI'a geçiyoruz” dendiğinde ABAP raporunu çöpe atarsınız, veri modeliniz kalır.

Sonraki adım isteyene

  • ECharts'ı SMW0'a koymak. Saf SVG basit grafikler için yeterli; treemap, sankey, gauge, zoom istiyorsanız echarts.min.js'i SMW0'a MIME objesi olarak yükleyip load_mime_object( ) ile URL alın. Hâlâ internet gerekmez, hâlâ transportla gider.

  • SM13 ve SM21'i eklemek — aynı desen, f_health içinde yaklaşık 20 satır.

  • Günlük e-posta özeti. f_build_html zaten tam bir HTML üretiyor; CL_BCS ile her sabah 07:00'de Basis ekibine göndermek bir background job meselesi.

  • Eşikleri tabloya taşımak. Şu an selection screen'de; Z tablosuna alınca sistem başına farklı eşik tanımlayabilirsiniz.

Ekler(1)

Yorumlar

0

Yorum yapmak için giriş yapmalısınız.

Henüz yorum bulunmamaktadır.

İlk yorumu yapan siz olun.

Emre Göçmen

Yazar & Geliştirici

SAP ABAP & Full Stack geliştirici olarak deneyimlerim, becerilerim ve kariyer yolculuğum hakkında blog yazılarım.

Kategori

SAP

SAP

Yazılardan Haberdar Olun

Yeni yazılardan ilk siz haberdar olmak için e-posta bültenime abone olun.