SAP ABAP'den Claude AI Entegrasyonu: Akıllı Üretim Raporu Oluşturma
Emre Göçmen
Yazar

SAP üretim verilerini analiz edip yöneticilere otomatik rapor göndermek yaygın bir ihtiyaçtır. Bu yazıda, üretim verilerini Claude API ile analiz eden ve sonuçları mail olarak ileten tam bir ABAP uygulaması geliştireceğiz.
Uygulamamız dört ana sınıftan oluşacak:
lcl_production_data: Üretim verilerini toplar ve özetler
lcl_claude_api: Claude API ile iletişim kurar
lcl_mail_sender: Mail gönderimini yönetir
lcl_application: Tüm süreci koordine eder
Şimdi adım adım ilerleyelim.
Adım 1: Program Tanımı ve Tip Bildirimleri
İlk olarak programımızı tanımlıyor ve ihtiyaç duyacağımız veri tiplerini oluşturuyoruz. Üretim verileri, özet bilgileri ve API yanıtı için ayrı yapılar tanımlıyoruz.
*&---------------------------------------------------------------------*
*& Report ZPP_PRODUCTION_AI_REPORT
*&---------------------------------------------------------------------*
*& Üretim verilerini Claude API ile analiz eder ve mail gönderir
*&---------------------------------------------------------------------*
REPORT zpp_production_ai_report.
*----------------------------------------------------------------------*
* Tip Tanımlamaları
*----------------------------------------------------------------------*
TYPES:
BEGIN OF gty_production,
aufnr TYPE aufnr,
matnr TYPE matnr,
maktx TYPE maktx,
werks TYPE werks_d,
gamng TYPE gamng,
gmein TYPE meins,
budat TYPE budat,
lmnga TYPE lmnga,
xmnga TYPE xmnga,
rmnga TYPE rmnga,
END OF gty_production,
gty_t_production TYPE STANDARD TABLE OF gty_production WITH EMPTY KEY,
BEGIN OF gty_summary,
budat TYPE budat,
plan_qty TYPE gamng,
actual_qty TYPE lmnga,
scrap_qty TYPE xmnga,
rework_qty TYPE rmnga,
efficiency TYPE decfloat16,
scrap_rate TYPE decfloat16,
END OF gty_summary,
gty_t_summary TYPE STANDARD TABLE OF gty_summary WITH EMPTY KEY,
BEGIN OF gty_content,
type TYPE string,
text TYPE string,
END OF gty_content,
gty_t_content TYPE STANDARD TABLE OF gty_content WITH EMPTY KEY,
BEGIN OF gty_api_response,
id TYPE string,
type TYPE string,
model TYPE string,
role TYPE string,
content TYPE gty_t_content,
stop_reason TYPE string,
END OF gty_api_response.gty_production: AFKO, AFPO ve AFRU tablolarından çekeceğimiz ham üretim verileri için kullanılır. Üretim emri numarası, malzeme, planlanan miktar, gerçekleşen miktar, fire ve yeniden işleme miktarlarını içerir.
gty_summary: Günlük bazda hesaplanacak özet verileri tutar. Verimlilik ve fire oranı bu yapıda hesaplanır.
gty_api_response: Claude API'den dönen JSON yanıtını parse etmek için kullanılır. API yanıtındaki content dizisi içinde text alanını okuyacağız.
Adım 2: Üretim Veri Sınıfı
Bu sınıf, SAP'den üretim verilerini çeker ve günlük bazda özet hesaplar. Constructor'da tarih aralığı alır ve hemen veri çekme ile özet hesaplama işlemlerini başlatır.
*----------------------------------------------------------------------*
* Üretim Veri Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_production_data DEFINITION FINAL.
PUBLIC SECTION.
METHODS constructor
IMPORTING
iv_date_from TYPE datum
iv_date_to TYPE datum.
METHODS get_data
RETURNING VALUE(rt_data) TYPE gty_t_production.
METHODS get_summary
RETURNING VALUE(rt_summary) TYPE gty_t_summary.
PRIVATE SECTION.
DATA mv_date_from TYPE datum.
DATA mv_date_to TYPE datum.
DATA mt_data TYPE gty_t_production.
DATA mt_summary TYPE gty_t_summary.
METHODS select_data.
METHODS calculate_summary.
ENDCLASS.
CLASS lcl_production_data IMPLEMENTATION.
METHOD constructor.
mv_date_from = iv_date_from.
mv_date_to = iv_date_to.
select_data( ).
calculate_summary( ).
ENDMETHOD.
METHOD select_data.
SELECT afko~aufnr,
afpo~matnr,
makt~maktx,
afpo~pwerk AS werks,
afko~gamng,
afko~gmein,
afru~budat,
afru~lmnga,
afru~xmnga,
afru~rmnga
FROM afko
INNER JOIN afpo
ON afpo~aufnr = afko~aufnr
INNER JOIN afru
ON afru~aufnr = afko~aufnr
LEFT OUTER JOIN makt
ON makt~matnr = afpo~matnr
AND makt~spras = @sy-langu
WHERE afru~budat BETWEEN @mv_date_from AND @mv_date_to
AND afru~stokz = @abap_false
INTO CORRESPONDING FIELDS OF TABLE @mt_data.
ENDMETHOD.
METHOD calculate_summary.
DATA ls_summary TYPE gty_summary.
CLEAR mt_summary.
LOOP AT mt_data ASSIGNING FIELD-SYMBOL(<ls_data>)
GROUP BY <ls_data>-budat
ASSIGNING FIELD-SYMBOL(<lo_group>).
CLEAR ls_summary.
ls_summary-budat = <lo_group>.
LOOP AT GROUP <lo_group> ASSIGNING FIELD-SYMBOL(<ls_item>).
ADD <ls_item>-gamng TO ls_summary-plan_qty.
ADD <ls_item>-lmnga TO ls_summary-actual_qty.
ADD <ls_item>-xmnga TO ls_summary-scrap_qty.
ADD <ls_item>-rmnga TO ls_summary-rework_qty.
ENDLOOP.
IF ls_summary-plan_qty > 0.
ls_summary-efficiency = ls_summary-actual_qty / ls_summary-plan_qty * 100.
ENDIF.
IF ls_summary-actual_qty > 0.
ls_summary-scrap_rate = ls_summary-scrap_qty / ls_summary-actual_qty * 100.
ENDIF.
APPEND ls_summary TO mt_summary.
ENDLOOP.
SORT mt_summary BY budat.
ENDMETHOD.
METHOD get_data.
rt_data = mt_data.
ENDMETHOD.
METHOD get_summary.
rt_summary = mt_summary.
ENDMETHOD.
ENDCLASS.select_data metodu: AFKO (üretim emri başlığı), AFPO (üretim emri kalemi), AFRU (üretim teyidi) ve MAKT (malzeme tanımı) tablolarını birleştirerek verileri çeker. stokz = false filtresi ile iptal edilmemiş teyitleri alırız.
calculate_summary metodu: GROUP BY sözdizimi ile verileri tarihe göre gruplar. Her gün için planlanan, gerçekleşen, fire ve yeniden işleme miktarlarını toplar. Ardından verimlilik ve fire oranını hesaplar.
Adım 3: Claude API İstemci Sınıfı
Bu sınıf, Claude API ile HTTP üzerinden iletişim kurar. API anahtarı, endpoint ve model bilgileri sabit olarak tanımlanır.
*----------------------------------------------------------------------*
* Claude API İstemci Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_claude_api DEFINITION FINAL.
PUBLIC SECTION.
CONSTANTS gc_api_key TYPE string VALUE 'sk-ant-api03-XXXXXXXXXXXXXXXXXXXXXXXX'.
CONSTANTS gc_api_url TYPE string VALUE 'https://api.anthropic.com/v1/messages'.
CONSTANTS gc_api_version TYPE string VALUE '2023-06-01'.
CONSTANTS gc_model TYPE string VALUE 'claude-sonnet-4-5-20250929'.
CLASS-METHODS analyze
IMPORTING
it_summary TYPE gty_t_summary
RETURNING
VALUE(rv_result) TYPE string.
PRIVATE SECTION.
CLASS-METHODS create_request_body
IMPORTING
it_summary TYPE gty_t_summary
RETURNING
VALUE(rv_body) TYPE string.
CLASS-METHODS parse_response
IMPORTING
iv_json TYPE string
RETURNING
VALUE(rv_text) TYPE string.
ENDCLASS.
CLASS lcl_claude_api IMPLEMENTATION.
METHOD analyze.
DATA lo_http_client TYPE REF TO if_http_client.
DATA lv_response TYPE string.
DATA lv_status TYPE i.
cl_http_client=>create_by_url(
EXPORTING
url = gc_api_url
ssl_id = 'ANONYM'
IMPORTING
client = lo_http_client
EXCEPTIONS
OTHERS = 1 ).
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_sy_create_object_error.
ENDIF.
lo_http_client->propertytype_logon_popup = if_http_client=>co_disabled.
lo_http_client->request->set_method( if_http_request=>co_request_method_post ).
lo_http_client->request->set_header_field(
name = 'Content-Type'
value = 'application/json' ).
lo_http_client->request->set_header_field(
name = 'x-api-key'
value = gc_api_key ).
lo_http_client->request->set_header_field(
name = 'anthropic-version'
value = gc_api_version ).
lo_http_client->request->set_cdata( create_request_body( it_summary ) ).
lo_http_client->send(
EXCEPTIONS
OTHERS = 1 ).
IF sy-subrc <> 0.
lo_http_client->close( ).
RAISE EXCEPTION TYPE cx_sy_create_object_error.
ENDIF.
lo_http_client->receive(
EXCEPTIONS
OTHERS = 1 ).
IF sy-subrc <> 0.
lo_http_client->close( ).
RAISE EXCEPTION TYPE cx_sy_create_object_error.
ENDIF.
lv_status = lo_http_client->response->get_header_field( '~status_code' ).
lv_response = lo_http_client->response->get_cdata( ).
lo_http_client->close( ).
IF lv_status = 200.
rv_result = parse_response( lv_response ).
ELSE.
rv_result = |HTTP Hata: { lv_status }|.
ENDIF.
ENDMETHOD.
METHOD create_request_body.
DATA lv_json TYPE string.
lv_json = /ui2/cl_json=>serialize(
data = it_summary
pretty_name = /ui2/cl_json=>pretty_mode-low_case ).
REPLACE ALL OCCURRENCES OF '\' IN lv_json WITH '\\'.
REPLACE ALL OCCURRENCES OF '"' IN lv_json WITH '\"'.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN lv_json WITH '\n'.
REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN lv_json WITH '\n'.
rv_body =
`{` &&
`"model":"` && gc_model && `",` &&
`"max_tokens":4096,` &&
`"messages":[{` &&
`"role":"user",` &&
`"content":"Asagidaki uretim verilerini analiz et. ` &&
`Verimlilik, fire orani ve dikkat edilmesi gereken noktalari belirle. ` &&
`Sonuclari Turkce yonetici ozeti formatinda sun:\n\n` && lv_json && `"` &&
`}]` &&
`}`.
ENDMETHOD.
METHOD parse_response.
DATA ls_response TYPE gty_api_response.
/ui2/cl_json=>deserialize(
EXPORTING
json = iv_json
CHANGING
data = ls_response ).
READ TABLE ls_response-content INDEX 1 INTO DATA(ls_content).
IF sy-subrc = 0.
rv_text = ls_content-text.
ENDIF.
ENDMETHOD.
ENDCLASS.analyze metodu: HTTP client oluşturur, gerekli header'ları ayarlar ve POST isteği gönderir. Yanıt başarılı ise parse_response ile içeriği çıkarır.
create_request_body metodu: Özet verilerini JSON'a dönüştürür ve Claude API formatına uygun request body oluşturur. Özel karakterler escape edilir.
parse_response metodu: API yanıtındaki content dizisinden text alanını okur ve döndürür.
Adım 4: Mail Gönderim Sınıfı
Bu sınıf, CL_BCS sınıfını kullanarak mail gönderimini gerçekleştirir.
*----------------------------------------------------------------------*
* Mail Gönderim Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_mail_sender DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS send
IMPORTING
iv_subject TYPE clike
iv_body TYPE string
it_emails TYPE string_table
RAISING
cx_send_req_bcs.
ENDCLASS.
CLASS lcl_mail_sender IMPLEMENTATION.
METHOD send.
DATA lt_body TYPE soli_tab.
DATA lo_document TYPE REF TO cl_document_bcs.
DATA lo_request TYPE REF TO cl_bcs.
DATA lo_sender TYPE REF TO cl_sapuser_bcs.
DATA lo_recipient TYPE REF TO if_recipient_bcs.
DATA lv_email TYPE adr6-smtp_addr.
SPLIT iv_body AT cl_abap_char_utilities=>newline INTO TABLE lt_body.
lo_document = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = lt_body
i_subject = CONV so_obj_des( iv_subject ) ).
lo_request = cl_bcs=>create_persistent( ).
lo_request->set_document( lo_document ).
lo_sender = cl_sapuser_bcs=>create( sy-uname ).
lo_request->set_sender( lo_sender ).
LOOP AT it_emails INTO DATA(ls_email).
lv_email = ls_email.
lo_recipient = cl_cam_address_bcs=>create_internet_address( lv_email ).
lo_request->add_recipient( lo_recipient ).
ENDLOOP.
lo_request->set_send_immediately( abap_true ).
lo_request->send( ).
COMMIT WORK AND WAIT.
ENDMETHOD.
ENDCLASS.send metodu: Mail içeriğini satırlara böler, doküman oluşturur, alıcıları ekler ve hemen gönderim yapar. COMMIT WORK AND WAIT ile işlemin tamamlanması beklenir.
Adım 5: Ana Uygulama Sınıfı
Bu sınıf, tüm süreci koordine eder. Veri toplama, analiz ve mail gönderimi adımlarını sırayla çalıştırır.
*----------------------------------------------------------------------*
* Ana Uygulama Sınıfı
*----------------------------------------------------------------------*
CLASS lcl_application DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS run
IMPORTING
iv_date_from TYPE datum
iv_date_to TYPE datum
it_emails TYPE string_table.
ENDCLASS.
CLASS lcl_application IMPLEMENTATION.
METHOD run.
DATA lo_production TYPE REF TO lcl_production_data.
DATA lt_summary TYPE gty_t_summary.
DATA lv_analysis TYPE string.
DATA lv_subject TYPE string.
" Üretim verilerini topla
lo_production = NEW lcl_production_data(
iv_date_from = iv_date_from
iv_date_to = iv_date_to ).
lt_summary = lo_production->get_summary( ).
IF lt_summary IS INITIAL.
MESSAGE 'Seçilen tarih aralığında veri bulunamadı' TYPE 'S' DISPLAY LIKE 'W'.
RETURN.
ENDIF.
" Claude API ile analiz et
TRY.
lv_analysis = lcl_claude_api=>analyze( lt_summary ).
CATCH cx_root INTO DATA(lx_error).
MESSAGE lx_error->get_text( ) TYPE 'E'.
RETURN.
ENDTRY.
" Mail gönder
lv_subject = |Üretim Raporu: { iv_date_from DATE = USER } - { iv_date_to DATE = USER }|.
TRY.
lcl_mail_sender=>send(
iv_subject = lv_subject
iv_body = lv_analysis
it_emails = it_emails ).
MESSAGE 'Rapor başarıyla gönderildi' TYPE 'S'.
CATCH cx_send_req_bcs INTO DATA(lx_mail).
MESSAGE lx_mail->get_text( ) TYPE 'E'.
ENDTRY.
ENDMETHOD.
ENDCLASS.
run metodu: Üç ana adımı sırayla yürütür. Her adımda hata kontrolü yapılır ve kullanıcıya bilgi mesajları gösterilir.
Adım 6: Seçim Ekranı ve Program Başlangıcı
Son olarak kullanıcı arayüzünü ve programın giriş noktasını tanımlıyoruz.
*----------------------------------------------------------------------*
* Seçim Ekranı
*----------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
PARAMETERS p_from TYPE datum.
PARAMETERS p_to TYPE datum.
SELECTION-SCREEN END OF BLOCK b1.
SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE TEXT-002.
PARAMETERS p_mail1 TYPE ad_smtpadr.
PARAMETERS p_mail2 TYPE ad_smtpadr.
PARAMETERS p_mail3 TYPE ad_smtpadr.
SELECTION-SCREEN END OF BLOCK b2.
*----------------------------------------------------------------------*
* Program Başlangıcı
*----------------------------------------------------------------------*
START-OF-SELECTION.
DATA lt_emails TYPE string_table.
IF p_mail1 IS NOT INITIAL.
APPEND CONV string( p_mail1 ) TO lt_emails.
ENDIF.
IF p_mail2 IS NOT INITIAL.
APPEND CONV string( p_mail2 ) TO lt_emails.
ENDIF.
IF p_mail3 IS NOT INITIAL.
APPEND CONV string( p_mail3 ) TO lt_emails.
ENDIF.
IF lt_emails IS INITIAL.
MESSAGE 'En az bir mail adresi girilmelidir' TYPE 'E'.
ENDIF.
lcl_application=>run(
iv_date_from = p_from
iv_date_to = p_to
it_emails = lt_emails ).Seçim ekranında tarih aralığı ve üç mail adresi için alanlar bulunur. Program başlangıcında girilen mail adresleri bir tabloya aktarılır ve lcl_application=>run metodu çağrılır.
Ön Gereksinimler
SSL Sertifikası
STRUST işlem kodunda SSL Client (Anonymous) düğümüne api.anthropic.com sertifikasını ekleyin.
API Anahtarı
Anthropic Console'dan API anahtarınızı alın ve gc_api_key sabitine yazın.
Background Job Oluşturma
SM36 işlem kodunda:
AlanDeğerJob NameZPP_DAILY_REPORTJob ClassCProgramZPP_PRODUCTION_AI_REPORTVariantDAILYStart TimeHer gün 18:00
API Detayları
ParametreDeğerEndpointhttps://api.anthropic.com/v1/messagesModelclaude-sonnet-4-5-20250929API Version2023-06-01Max Tokens4096
Sonuç
Bu yazıda, SAP üretim verilerini Claude API ile analiz eden ve sonuçları mail olarak ileten tam bir ABAP uygulaması geliştirdik. Uygulama nesne yönelimli tasarım prensipleriyle yazıldı ve background job olarak çalışmaya uygun.
Aynı mimari, kalite bildirimleri, stok hareketleri veya satış verileri gibi farklı veri setleri için kolayca uyarlanabilir.
Yorumlar
Henüz yorum bulunmamaktadır.
İlk yorumu yapan siz olun.



